Pack and unpack words struct cannot describe - #721
Conversation
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
The full-suite and workspace-gate lines were measured at Behaviour outside the reported failure, compared against baseline by running the same matrix of sizes, signedness and endness under both revisions: Scope: 14 of the 183 p-code languages pypcode 4.0.1.dev0 exposes report a three-byte word, and Caveats: |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_721 |
Clemory.unpack() and pack() catch struct.error to tell an access that ran off the end of its backer, which is a KeyError, from an operation that genuinely failed. They made that decision by calling struct.calcsize() on the same format string, which raises the same error when the format is one struct cannot parse. That exception escaped from inside the handler, so neither answer was reported and callers saw a bare struct.error from a line that was only meant to be measuring. ClemoryReadOnlyView.unpack() carries two more copies of that handler, one for the cached backer and one for the general lookup. Work out which exception to report first and raise it afterwards, outside the handler, so a short access no longer carries the struct error as its context either.
struct has integer format characters for 1, 2, 4 and 8 bytes only, so pack_word had no way to write the 3-byte word of a 24-bit architecture, and unpack_word covered wider words with a halving recursion that rejected every size that was not a power of two. ELF TLS setup writes the DTV pointer with pack_word, so opening any ELF on a 24-bit architecture failed with "bad char in struct format" before analysis began. Build a word of any width struct cannot name from its bytes instead. The write checks that the whole word is backed first, because store() writes the bytes that fit before it reports the overrun.
18e03c7 to
01a4fe8
Compare
test_tls_24bit_arch assembled its own ELF32 header with struct.pack to reach an architecture whose word is three bytes wide, so it exercised a container shape no toolchain emits. Load tests/avr/isqrt_atmega128.o from angr/binaries instead. Its e_flags name the extended-address AVR variant, which Ghidra maps to avr8:LE:16:extended, a 24-bit language; name that language explicitly because cle picks the 16-bit default for every EM_AVR ELF today. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
acdccc0 to
1571db8
Compare
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Opening any ELF on a 24-bit architecture failed with "bad char in struct format" before analysis began: ELF TLS setup writes the DTV pointer with
pack_word, andstructhas integer format characters for one, two, four and eight bytes only, so nothing names a three-byte word.unpack_wordcovered wider words with a halving recursion;pack_wordhad nothing.Both now build a word of any width
structcannot name from its bytes.The first commit stops
unpack(),pack()and the two copies inClemoryReadOnlyViewfrom classifying astruct.errorwithcalcsize()inside the handler, where a formatstructcannot parse raises the same error again.Regressions load an AVR object under a 24-bit p-code language and round-trip odd-width words. That object is a fixture angr/binaries#176 adds, so the checks here stay red until it merges. angr/archinfo#364 is the other half. Validation: #721 (comment).