-
Notifications
You must be signed in to change notification settings - Fork 437
Fix UtilCheckerFuzzer: Security exception Update I18nFormatUtil.java #7031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
851c120
ef8068b
d4b934c
05e84bf
3e11626
a7e95a6
e4bc6a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,6 @@ | |
| import java.text.SimpleDateFormat; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.IllegalFormatException; | ||
| import java.util.List; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
|
|
@@ -36,40 +35,52 @@ public class I18nFormatUtil { | |
| */ | ||
| @SuppressWarnings("nullness:argument") // It's not documented, but passing null as the | ||
| // argument array is supported. | ||
| public static void tryFormatSatisfiability(String format) throws IllegalFormatException { | ||
| public static void tryFormatSatisfiability(String format) throws IllegalArgumentException { | ||
| MessageFormat.format(format, (Object[]) null); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a {@link I18nConversionCategory} for every conversion found in the format string. | ||
| * | ||
| * @param format the format string to parse | ||
| * @throws IllegalFormatException if the format is not syntactically valid | ||
| * @throws IllegalArgumentException if the format is not syntactically valid | ||
| */ | ||
| public static I18nConversionCategory[] formatParameterCategories(String format) | ||
| throws IllegalFormatException { | ||
| throws IllegalArgumentException { | ||
|
|
||
| tryFormatSatisfiability(format); | ||
| I18nConversion[] cs = MessageFormatParser.parse(format); | ||
|
|
||
| I18nConversion[] cs; | ||
| try { | ||
| cs = MessageFormatParser.parse(format); | ||
| } catch (Exception e) { | ||
| // Defensive programming: fail gracefully on parse errors | ||
| throw new IllegalArgumentException("Invalid format string: " + format); | ||
| } | ||
|
Comment on lines
+53
to
+59
|
||
|
|
||
| int maxIndex = -1; | ||
| Map<Integer, I18nConversionCategory> conv = new HashMap<>(cs.length); | ||
|
|
||
| for (I18nConversion c : cs) { | ||
| int index = c.index; | ||
| if (index < 0 || index > 1000) { // Arbitrary upper bound to prevent abuse | ||
| throw new IllegalArgumentException( | ||
|
Comment on lines
+66
to
+67
|
||
| "Format string contains illegal argument index: " + index); | ||
|
Comment on lines
+66
to
+68
|
||
| } | ||
|
Comment on lines
+66
to
+69
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider documenting the 1000 index limit in the method's Javadoc. The arbitrary upper bound of 1000 is a reasonable safeguard against resource exhaustion attacks (as discovered by the fuzzer). However, this limit should be documented in the method's Javadoc so callers are aware of the constraint. Additionally, consider extracting Proposed improvement+ private static final int MAX_FORMAT_INDEX = 1000;
+
/**
* Returns a {`@link` I18nConversionCategory} for every conversion found in the format string.
*
* `@param` format the format string to parse
- * `@throws` IllegalArgumentException if the format is not syntactically valid
+ * `@throws` IllegalArgumentException if the format is not syntactically valid, or if any argument
+ * index exceeds {`@value` `#MAX_FORMAT_INDEX`}
*/And update the check: - if (index < 0 || index > 1000) { // Arbitrary upper bound to prevent abuse
+ if (index < 0 || index > MAX_FORMAT_INDEX) {🤖 Prompt for AI Agents |
||
|
|
||
| Integer indexKey = index; | ||
| conv.put( | ||
| indexKey, | ||
| I18nConversionCategory.intersect( | ||
| c.category, | ||
| conv.containsKey(indexKey) ? conv.get(indexKey) : I18nConversionCategory.UNUSED)); | ||
| I18nConversionCategory existing = conv.getOrDefault(indexKey, I18nConversionCategory.UNUSED); | ||
| I18nConversionCategory merged = I18nConversionCategory.intersect(c.category, existing); | ||
|
|
||
| conv.put(indexKey, merged); | ||
| maxIndex = Math.max(maxIndex, index); | ||
| } | ||
|
|
||
| I18nConversionCategory[] res = new I18nConversionCategory[maxIndex + 1]; | ||
| for (int i = 0; i <= maxIndex; i++) { | ||
| Integer indexKey = i; | ||
| res[i] = conv.containsKey(indexKey) ? conv.get(indexKey) : I18nConversionCategory.UNUSED; | ||
| res[i] = conv.getOrDefault(i, I18nConversionCategory.UNUSED); | ||
| } | ||
|
|
||
| return res; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Declaring
throwsfor unchecked exception is unconventional.IllegalArgumentExceptionextendsRuntimeException, so declaring it in the throws clause has no compile-time effect. While it serves as documentation, it's not idiomatic Java. Consider either removing the throws clause or adding a@throwsJavadoc tag instead for documentation purposes.🤖 Prompt for AI Agents