Pack200: enforce strict attribute layout parsing - #747
Conversation
The parser for the [Pack200 attribute layout definitions](https://docs.oracle.com/en/java/javase/11/docs/specs/pack-spec.html#attribute-layout-definitions) micro-language was previously overly permissive, allowing invalid layouts and masking archive corruption. This change implements strict parsing in accordance with the [Java 11 specification](https://docs.oracle.com/en/java/javase/11/docs/specs/pack-spec.html) and removes duplication of the micro-language parsing logic between `pack200.NewAttributeBands` and `unpack200.NewAttributeBands`.
ppkarwasz
left a comment
There was a problem hiding this comment.
Stricter validation introduced by the parser caused several tests to fail.
Rather than relaxing the parser to match potentially incorrect test expectations, each failing test was reviewed individually, and the specific issues are described below.
| // @formatter:off | ||
| final CPUTF8 layout = new CPUTF8( | ||
| "[NH[(1)]][RSH NH[RUH(1)]][TB(66,67,73,83,90)[KIH](68)[KDH](70)[KFH](74)[KJH](99)[RSH](101)[RSH RUH](115)[RUH](91)[NH[(0)]](64)[RSH[RUH(0)]]()[]]" | ||
| "[NH[(1)]][RSHNH[RUH(1)]][TB(66,67,73,83,90)[KIH](68)[KDH](70)[KFH](74)[KJH](99)[RSH](101)[RSHRUH](115)[RUH](91)[NH[(0)]](64)[RSHNH[RUH(0)]]()[]]" |
There was a problem hiding this comment.
This test string originates from Harmony (commit b1ecf0b).
The embedded spaces are invalid per the Pack200 attribute layout specification, and the nested [...] callables are also non-conforming.
In the native implementation (see parseLayout), an unknown symbol triggers a parse failure, whereas our previous implementation incorrectly interpreted it as end-of-input.
| final CPUTF8 name = new CPUTF8(""); | ||
| final CPUTF8 layout = new CPUTF8("["); | ||
| assertDoesNotThrow(() -> new NewAttributeBands(1, null, null, | ||
| assertThrows(Pack200Exception.class, () -> new NewAttributeBands(1, null, null, |
There was a problem hiding this comment.
I looked into the cause of this failing test:
- The native
parseLayoutimplementation (see reference above) treats EOF as equivalent to a closing bracket]. - On the other hand, I wasn't able to use the JDK 11 Java implementation to parse this example: it failed even before reaching attribute layouts,
- Given that COMPRESS-626 specifically aims to ensure that unmatched brackets do not lead to OOM conditions and that the behavior of the C and Java implementations differ on this one, I think that this change is acceptable.
| final CPUTF8 layout = new CPUTF8("Re\\T"); | ||
| assertDoesNotThrow(() -> new NewAttributeBands(1, null, null, | ||
| new AttributeDefinitionBands.AttributeDefinition(35, AttributeDefinitionBands.CONTEXT_CLASS, name, layout))); | ||
| assertThrows(Pack200Exception.class, () -> new NewAttributeBands(1, null, null, new AttributeDefinitionBands.AttributeDefinition(35, | ||
| AttributeDefinitionBands.CONTEXT_CLASS, name, layout))); |
There was a problem hiding this comment.
COMPRESS-628 was also about an OOM, so the change in behavior should not be relevant.
The native C implementation should also fail on the first unrecognized letter (e).
There was a problem hiding this comment.
Pull Request Overview
This PR implements strict parsing for Pack200 attribute layout definitions according to the Java 11 specification. The parser now properly validates layout syntax and rejects invalid or corrupted archives that were previously accepted.
Key changes:
- Introduced new shared parsing logic in
AttributeLayoutParserandAttributeLayoutUtilsclasses to eliminate code duplication between pack200 and unpack200 implementations - Added validation for integral, reference, and other layout tags with proper error handling
- Updated tests to expect exceptions for previously accepted invalid layouts
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
src/main/java/org/apache/commons/compress/harmony/internal/AttributeLayoutParser.java |
New parser implementation for attribute layout definitions with strict validation |
src/main/java/org/apache/commons/compress/harmony/internal/AttributeLayoutUtils.java |
Utility methods for validating layout tags and processing layout elements |
src/main/java/org/apache/commons/compress/harmony/internal/package-info.java |
Package documentation for new internal package |
src/main/java/org/apache/commons/compress/harmony/unpack200/NewAttributeBands.java |
Refactored to use new shared parser, removed duplicate parsing logic |
src/main/java/org/apache/commons/compress/harmony/pack200/NewAttributeBands.java |
Refactored to use new shared parser, removed duplicate parsing logic |
src/test/java/org/apache/commons/compress/harmony/unpack200/NewAttributeBandsTest.java |
Added tests for empty body validation and corrected layout strings |
src/test/java/org/apache/commons/compress/harmony/pack200/NewAttributeBandsTest.java |
Corrected layout strings to remove invalid whitespace |
src/test/java/org/apache/commons/compress/harmony/pack200/Compress628Test.java |
Updated to expect Pack200Exception for invalid layout |
src/test/java/org/apache/commons/compress/harmony/pack200/Compress626Test.java |
Updated to expect Pack200Exception for invalid layout |
src/test/java/org/apache/commons/compress/harmony/internal/AttributeLayoutUtilsTest.java |
New tests for utility validation methods |
src/test/java/org/apache/commons/compress/harmony/internal/AttributeLayoutParserTest.java |
New comprehensive parser tests for valid and invalid layouts |
src/main/java/org/apache/commons/compress/harmony/archive/internal/nls/package-info.java |
Enhanced package documentation |
pom.xml |
Updated OSGi and module configuration to exclude internal packages from exports |
src/changes/changes.xml |
Added changelog entry |
Comments suppressed due to low confidence (2)
src/main/java/org/apache/commons/compress/harmony/internal/AttributeLayoutUtils.java:185
- @param tag ">" does not match any actual parameter of method "readAttributeLayout()".
* @param <ALE>> the type of AttributeLayoutElement.
src/main/java/org/apache/commons/compress/harmony/internal/AttributeLayoutUtils.java:213
- @param tag ">" does not match any actual parameter of method "readBody()".
* @param <ALE>> the type of AttributeLayoutElement.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This fails on JDK up to 11 and is yet another Javadoc quirk.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
Ah, we're missing a |
No, the The regular need to upgrade workflows to:
is the reason why I would prefer to have reusable workflows. The Maven build of different Commons projects is not so different. |
|
Ah, right, I remember holding off on migrating Compress to |
garydgregory
left a comment
There was a problem hiding this comment.
Hi @ppkarwasz
Thank you for the PR. A few comments here and there. Note that Lang has an IntegerRange to use instead of Range<Integer>.
This change adds a limit to the nesting level of `layout_element`s (64). Since all standard attribute layouts have a nesting level lower than 3, the limit should be suitable for most purposes.
|
I’ve applied your review suggestions and also made a small refactoring to eliminate a potential infinite recursion in the parser. The parser should now be ready for another review pass. |
The parser for the Pack200 attribute layout definitions micro-language was previously overly permissive, allowing invalid layouts and masking archive corruption.
This change implements strict parsing in accordance with the Java 11 version of the Pack200 specification and removes duplication of the micro-language parsing logic between
pack200.NewAttributeBandsandunpack200.NewAttributeBands.