ICU-22642 Avoid spending too much time inside CanonicalIterator

See #3017
This commit is contained in:
Frank Tang 2024-06-05 18:27:35 +00:00 committed by Fredrik Roubert
parent 6543634649
commit 87fce24233
2 changed files with 21 additions and 1 deletions

View file

@ -363,6 +363,9 @@ UnicodeString* CanonicalIterator::getEquivalents(const UnicodeString &segment, i
char16_t USeg[256];
int32_t segLen = segment.extract(USeg, 256, status);
getEquivalents2(&basic, USeg, segLen, status);
if (U_FAILURE(status)) {
return nullptr;
}
// now get all the permutations
// add only the ones that are canonically equivalent
@ -466,6 +469,9 @@ Hashtable *CanonicalIterator::getEquivalents2(Hashtable *fillinResult, const cha
Hashtable remainder(status);
remainder.setValueDeleter(uprv_deleteUObject);
if (extract(&remainder, cp2, segment, segLen, i, status) == nullptr) {
if (U_FAILURE(status)) {
return nullptr;
}
continue;
}
@ -490,6 +496,13 @@ Hashtable *CanonicalIterator::getEquivalents2(Hashtable *fillinResult, const cha
ne = remainder.nextElement(el);
}
// ICU-22642 Guards against strings that have so many permutations
// that they would otherwise hang the function.
constexpr int32_t kResultLimit = 4096;
if (fillinResult->count() > kResultLimit) {
status = U_UNSUPPORTED_ERROR;
return nullptr;
}
}
}

View file

@ -172,7 +172,7 @@ public final class CanonicalIterator {
permute(source, skipZeros, output, 0);
}
private static int PERMUTE_DEPTH_LIMIT = 8;
private static final int PERMUTE_DEPTH_LIMIT = 8;
/**
* Simple implementation of permutation.
* <br><b>Warning: The strings are not guaranteed to be in any particular order.</b>
@ -308,6 +308,7 @@ public final class CanonicalIterator {
}
static private final int RESULT_LIMIT = 4096;
private Set<String> getEquivalents2(String segment) {
Set<String> result = new HashSet<String>();
@ -342,6 +343,12 @@ public final class CanonicalIterator {
result.add(prefix + item);
}
}
// ICU-22642 Guards against strings that have so many permutations
// that they would otherwise hang the function.
if (result.size() > RESULT_LIMIT) {
throw new UnsupportedOperationException("Too many permutations");
}
}
return result;
/*