Skip to content

Commit 5b45e5c

Browse files
committed
ICU-22934 Limit the number of resursive call
To avoid stack overflow while building RBBI
1 parent 8437d1d commit 5b45e5c

File tree

3 files changed

+44
-18
lines changed

3 files changed

+44
-18
lines changed

icu4c/source/common/rbbinode.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -193,26 +193,40 @@ void RBBINode::NRDeleteNode(RBBINode *node) {
193193
// references in preparation for generating the DFA tables.
194194
//
195195
//-------------------------------------------------------------------------
196-
RBBINode *RBBINode::cloneTree() {
196+
constexpr int kRecursiveDepthLimit = 3500;
197+
RBBINode *RBBINode::cloneTree(UErrorCode &status, int depth) {
198+
if (U_FAILURE(status)) {
199+
return nullptr;
200+
}
201+
// If the depth of the stack is too deep, we return U_INPUT_TOO_LONG_ERROR
202+
// to avoid stack overflow crash.
203+
if (depth > kRecursiveDepthLimit) {
204+
status = U_INPUT_TOO_LONG_ERROR;
205+
return nullptr;
206+
}
197207
RBBINode *n;
198208

199209
if (fType == RBBINode::varRef) {
200210
// If the current node is a variable reference, skip over it
201211
// and clone the definition of the variable instead.
202-
n = fLeftChild->cloneTree();
212+
n = fLeftChild->cloneTree(status, depth+1);
203213
} else if (fType == RBBINode::uset) {
204214
n = this;
205215
} else {
206216
n = new RBBINode(*this);
207217
// Check for null pointer.
208218
if (n != nullptr) {
209219
if (fLeftChild != nullptr) {
210-
n->fLeftChild = fLeftChild->cloneTree();
211-
n->fLeftChild->fParent = n;
220+
n->fLeftChild = fLeftChild->cloneTree(status, depth+1);
221+
if (U_SUCCESS(status)) {
222+
n->fLeftChild->fParent = n;
223+
}
212224
}
213225
if (fRightChild != nullptr) {
214-
n->fRightChild = fRightChild->cloneTree();
215-
n->fRightChild->fParent = n;
226+
n->fRightChild = fRightChild->cloneTree(status, depth+1);
227+
if (U_SUCCESS(status)) {
228+
n->fRightChild->fParent = n;
229+
}
216230
}
217231
}
218232
}
@@ -239,7 +253,6 @@ RBBINode *RBBINode::cloneTree() {
239253
// nested references are handled by cloneTree(), not here.
240254
//
241255
//-------------------------------------------------------------------------
242-
constexpr int kRecursiveDepthLimit = 3500;
243256
RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
244257
if (U_FAILURE(status)) {
245258
return this;
@@ -251,7 +264,7 @@ RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
251264
return this;
252265
}
253266
if (fType == varRef) {
254-
RBBINode *retNode = fLeftChild->cloneTree();
267+
RBBINode *retNode = fLeftChild->cloneTree(status, depth+1);
255268
if (retNode != nullptr) {
256269
retNode->fRuleRoot = this->fRuleRoot;
257270
retNode->fChainIn = this->fChainIn;
@@ -280,19 +293,30 @@ RBBINode *RBBINode::flattenVariables(UErrorCode& status, int depth) {
280293
// the left child of the uset node.
281294
//
282295
//-------------------------------------------------------------------------
283-
void RBBINode::flattenSets() {
296+
void RBBINode::flattenSets(UErrorCode &status, int depth) {
297+
if (U_FAILURE(status)) {
298+
return;
299+
}
300+
// If the depth of the stack is too deep, we return U_INPUT_TOO_LONG_ERROR
301+
// to avoid stack overflow crash.
302+
if (depth > kRecursiveDepthLimit) {
303+
status = U_INPUT_TOO_LONG_ERROR;
304+
return;
305+
}
284306
U_ASSERT(fType != setRef);
285307

286308
if (fLeftChild != nullptr) {
287309
if (fLeftChild->fType==setRef) {
288310
RBBINode *setRefNode = fLeftChild;
289311
RBBINode *usetNode = setRefNode->fLeftChild;
290312
RBBINode *replTree = usetNode->fLeftChild;
291-
fLeftChild = replTree->cloneTree();
292-
fLeftChild->fParent = this;
313+
fLeftChild = replTree->cloneTree(status, depth+1);
314+
if (U_FAILURE(status)) {
315+
fLeftChild->fParent = this;
316+
}
293317
delete setRefNode;
294318
} else {
295-
fLeftChild->flattenSets();
319+
fLeftChild->flattenSets(status, depth+1);
296320
}
297321
}
298322

@@ -301,11 +325,13 @@ void RBBINode::flattenSets() {
301325
RBBINode *setRefNode = fRightChild;
302326
RBBINode *usetNode = setRefNode->fLeftChild;
303327
RBBINode *replTree = usetNode->fLeftChild;
304-
fRightChild = replTree->cloneTree();
305-
fRightChild->fParent = this;
328+
fRightChild = replTree->cloneTree(status, depth+1);
329+
if (U_FAILURE(status)) {
330+
fRightChild->fParent = this;
331+
}
306332
delete setRefNode;
307333
} else {
308-
fRightChild->flattenSets();
334+
fRightChild->flattenSets(status, depth+1);
309335
}
310336
}
311337
}

icu4c/source/common/rbbinode.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ class RBBINode : public UMemory {
9696
~RBBINode();
9797
static void NRDeleteNode(RBBINode *node);
9898

99-
RBBINode *cloneTree();
99+
RBBINode *cloneTree(UErrorCode &status, int depth=0);
100100
RBBINode *flattenVariables(UErrorCode &status, int depth=0);
101-
void flattenSets();
101+
void flattenSets(UErrorCode &status, int depth=0);
102102
void findNodes(UVector *dest, RBBINode::NodeType kind, UErrorCode &status);
103103

104104
#ifdef RBBI_DEBUG

icu4c/source/common/rbbitblb.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void RBBITableBuilder::buildForwardTable() {
142142
// Replace all references to UnicodeSets with the tree for the equivalent
143143
// expression.
144144
//
145-
fTree->flattenSets();
145+
fTree->flattenSets(*fStatus, 0);
146146
#ifdef RBBI_DEBUG
147147
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "stree")) {
148148
RBBIDebugPuts("\nParse tree after flattening Unicode Set references.");

0 commit comments

Comments
 (0)