. "$BST_LIB" # BST-TIMEOUT: 600 # measured 61 s for 83 cases on an idle local guest # # (==BST-SUITE openjpeg elapsed=61s cases=83==, 2026-08-18; # # 60/61/61 s over three clean runs). ~30 execs, and the # # binaries are the heavy part of that: opj_decompress is # # 14 MB and opj_compress 12 MB, each exec a fresh wasm # # module instantiation. The 60 s default would not even # # cover the idle case. 600 is ~10x the measurement, which # # is the headroom the packager guide asks for rather than a # # round number -- a loaded shared host runs this shape # # several times slower, and an exec-heavy suite is exactly # # what hwjs-cc#69 makes slow before it makes it wedge. # openjpeg 2.5.4 (meta-oe recipes-graphics/openjpeg) -- the SECOND JPEG-2000 # codec on this image, and deliberately so. jasper is the ISO reference # implementation; openjpeg is the one production software links (poppler, GDAL, # ImageMagick, ffmpeg). They share no code, so each is an independent witness # for the other's arithmetic on a standard large enough that two implementations # routinely disagree about its corners. # # `opj_compress` encodes, `opj_decompress` decodes, `opj_dump` reports the # codestream structure. All three are file-in/file-out: no display, no network, # no device. # # ============================ WHAT THE ORACLES ARE ============================ # # THIS SUITE ASSERTS IN THREE DIFFERENT CURRENCIES, and mixing them up is how a # red gets misread. Each case below is one of: # # (A) EXACTNESS -- the assertion the codec itself owes, with no reference # needed. JPEG-2000's default wavelet here is the REVERSIBLE integer 5/3 # (opj_dump reports it as qmfbid=1): integer lifting, integer # quantization, integer coding, no rounding anywhere in the path. A # lossless round trip is therefore REQUIRED to return the source raster # BYTE FOR BYTE. Not close: exact. This is the strongest statement # available about any codec, and it is what catches a wrong wavelet, a # wrong coefficient order, a wrong MQ-coder state or a sign error -- # every one of those moves at least one byte. An (A) case going red is # ALWAYS a genuine codec fault and must never be re-pinned. # # (B) X86-64 DIGEST PINS -- md5 and size of the encoded codestreams and of # opj_dump's report, measured on a host build of THIS EXACT SOURCE: # SRCREV 6c4a29b0 with all three of the recipe's patches applied # (0001-Do-not-ask-cmake-to-export-binaries, CVE-2023-39327, # CVE-2026-6192), configured with the same four cmake options the # bbappend gives the target. Measured 2026-08-18. These say "this arm # produces the same bits x86-64 does", which is a claim about the # PORT rather than about the codec. # # (C) IMPLEMENTATION-INDEPENDENT RELATIONS -- things that must hold whatever # built the codec and whatever version of a third-party library it links: # the two containers must decode to the same raster, a lossy encode must # actually be lossy, a TIFF round trip must return the source. These are # the cases that survive a version bump, and they are deliberately the # ones carrying the TIFF coverage (see below), because pinning bytes # produced by libtiff would be pinning libtiff rather than openjpeg. # # ===================== WHY THE TIFF CASES EARN THEIR PLACE ==================== # # THEY ARE THE REGRESSION GUARD FOR THE ONE BUG THIS PORT HAD TO FIX. openjpeg's # thirdparty/CMakeLists.txt takes a pkg-config-dependent branch for TIFF and # LCMS2 in STATIC-ONLY builds, and the meta-oe recipe did not inherit pkgconfig # -- so both libraries were FOUND (which compiles converttif.c and the LCMS # colour path in) while their link-line names came out EMPTY. Under an ordinary # ELF linker that is an undefined-symbol error; under wasmld's --allow-undefined # it would have been thirteen `env.*` imports that TRAP AT FIRST CALL, i.e. a # program that runs fine until someone hands it a .tif. It was caught at build # time only because the HWJS-3 sanctioned-surface check refuses phantom imports. # The bbappend's `inherit pkgconfig` is the fix. A TIFF round trip here is what # notices if that inherit is ever dropped, in the currency a user would notice # it in. # # LCMS2 HAS NO RUN-TIME CASE HERE, AND THAT IS A STATED LIMIT RATHER THAN AN # OVERSIGHT. openjpeg reaches lcms only through color_apply_icc_profile and # color_cielab_to_rgb, both of which need an input already carrying an ICC # profile or a CIELab colour space -- and nothing in this port's own surface can # produce one (opj_compress has no profile option, and its TIFF reader, unlike # its PNG reader, does not copy an embedded profile). What DOES guard the lcms # half is the link itself: with `inherit pkgconfig` removed the build fails on # the cms* phantom imports before any test runs, which is a stronger guard than # a case, just not one that appears in this report. # # ============================== READING A RED ================================ # # * An (A) case red -- roundtrip-jp2-exact, roundtrip-j2k-exact, # roundtrip-tiled-exact, gray-roundtrip-exact -- is a codec fault. Do not # re-pin anything; find the fault. # * A (B) digest red with every (A) case still green is toolchain or version # drift. Confirm against the exact cases, then RE-DERIVE the pin from the # ==OPENJPEG-OBSERVED== line this suite prints, which carries every digest the # run actually produced -- one run gives both the failure and its replacement. # * THE ONE PIN WORTH EXPECTING TO DRIFT ON A NEW ARM IS encode-irrev-digest, # because `-I` selects the IRREVERSIBLE 9/7 wavelet and that is the only # floating-point path in this suite. If it goes red while irrev-is-lossy and # every (A) case stay green, the finding is float divergence on this arm, and # the right response is to DROP the pin rather than re-pin it to whatever this # arm printed -- a re-pin would assert the arm instead of the codec. It has # not drifted: measured 2026-08-18, the wasm32-hwjs glibc target reproduced # this pin and every other value in ==OPENJPEG-OBSERVED== BYTE-IDENTICALLY to # the x86-64 reference, the floating-point arm included. That is what wasm f64 # being strictly IEEE-754 with no excess precision and no contraction buys -- # the same guarantee SSE2 gives the reference host. # * A REFUSAL case red is a security finding, not a cosmetic one. JPEG-2000 # decoders have a long CVE history and two of this recipe's three patches are # CVE fixes; a decoder that stopped refusing malformed input has regressed # into exactly that history. # # THE ==OPENJPEG-OBSERVED== LINE sits outside the BST protocol, like # ==BST-SUITE==, so the report parsers ignore it. require opj_compress openjpeg/present tmp=${TMPDIR:-/tmp}/bst-openjpeg.$$ mkdir -p "$tmp" 2>/dev/null fix=$BST_DATA/openjpeg-fixture.ppm if [ ! -f "$fix" ]; then bst_notok openjpeg/payload "missing $fix -- remaining cases not run" rm -rf "$tmp" exit 0 fi # 96x64 P6: three bytes per pixel, no padding. RAW=18432 md5of() { md5sum "$1" 2>/dev/null | cut -d' ' -f1; } size() { wc -c < "$1" 2>/dev/null | tr -d ' '; } # The raster alone. openjpeg writes a "# OpenJPEG-" COMMENT into every # PNM header it produces, so the whole file carries the codec's version string # and the fixture's does not -- comparing files would report a version change as # a codec fault. Taking the last RAW bytes is header-length-agnostic and is the # comparison the codec actually owes. raster() { tail -c "${2:-$RAW}" "$1" 2>/dev/null | md5sum 2>/dev/null | cut -d' ' -f1; } geom() { head -c 64 "$1" 2>/dev/null | tr '\n' ' ' | awk '{for(i=1;i<=NF;i++) if($i ~ /^[0-9]+$/ && $(i+1) ~ /^[0-9]+$/) {print $i"x"$(i+1); exit}}'; } have_md5=0; command -v md5sum >/dev/null 2>&1 && have_md5=1 # ----------------------------------------------------------------- payload --- # Pinned BEFORE anything reads it. Without this a later mismatch has two # indistinguishable causes -- the codec changed, or the payload did -- and the # wrong one gets reported. if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/fixture-digest 43d4241dc8350c3b8b740b5743da02f1 "$(md5of "$fix")" else bst_skip openjpeg/fixture-digest "no md5sum on this image" fi check_eq openjpeg/fixture-size 18445 "$(size "$fix")" fixraster=$(raster "$fix") for p in opj_compress opj_decompress opj_dump; do if command -v $p >/dev/null 2>&1; then bst_ok openjpeg/program-$p else bst_notok openjpeg/program-$p "$p is not on PATH"; fi done # --------------------------------------- the reversible path: EXACTNESS (A) --- lj=$tmp/ll.jp2 check openjpeg/encode-jp2-lossless opj_compress -i "$fix" -o "$lj" check_eq openjpeg/encode-jp2-lossless-size 3988 "$(size "$lj")" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-jp2-lossless-digest c932143a1ed1c922c9bd4f7cf65012fc "$(md5of "$lj")" else bst_skip openjpeg/encode-jp2-lossless-digest "no md5sum on this image" fi ld=$tmp/dec_ll.ppm check openjpeg/decode-jp2-lossless opj_decompress -i "$lj" -o "$ld" # THE STRONGEST ASSERTION IN THIS SUITE. check_eq openjpeg/roundtrip-jp2-exact "$fixraster" "$(raster "$ld")" # openjpeg stamps its own version into the PNM comment it writes. That makes the # decoded file self-identifying, and is the one place the running codec states # its version in its own output rather than in a help text. check_eq openjpeg/version "# OpenJPEG-2.5.4" "$(head -2 "$ld" | tail -1)" check_eq openjpeg/decode-geometry "96x64" "$(geom "$ld")" # The raw codestream is a second, independent container over the same coder: no # JP2 boxes, no colour specification, just the SOC..EOC markers. lc=$tmp/ll.j2k check openjpeg/encode-j2k-lossless opj_compress -i "$fix" -o "$lc" check_eq openjpeg/encode-j2k-lossless-size 3903 "$(size "$lc")" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-j2k-lossless-digest 266c0ec7b5899ef67a95729861e2d3f5 "$(md5of "$lc")" else bst_skip openjpeg/encode-j2k-lossless-digest "no md5sum on this image" fi cd_=$tmp/dec_j2k.ppm check openjpeg/decode-j2k-lossless opj_decompress -i "$lc" -o "$cd_" check_eq openjpeg/roundtrip-j2k-exact "$fixraster" "$(raster "$cd_")" # (C) The container must not reach the samples. Asserted separately from the two # exactness cases above because a codec that returned the SOURCE regardless of # input would satisfy both of those and fail nothing else. check_eq openjpeg/container-agreement "$(raster "$ld")" "$(raster "$cd_")" # A codec that is deterministic is what makes a stored digest an oracle at all, # so it is asserted rather than assumed. opj_compress -i "$fix" -o "$tmp/ll2.jp2" >/dev/null 2>&1 check openjpeg/encode-determinism cmp -s "$lj" "$tmp/ll2.jp2" # ------------------------------------------------ what opj_dump reports (B) --- # The third program, and the ticket's "dump the codestream header". Its whole # report is pinned, then the fields that carry the port's meaning are asserted # individually -- so a red says WHICH field moved rather than only that the # text did. opj_dump -i "$lj" > "$tmp/dump.txt" 2>/dev/null if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/dump-digest 0eeb52dc1efa53b8d1cf6c528e50dd07 "$(md5of "$tmp/dump.txt")" else bst_skip openjpeg/dump-digest "no md5sum on this image" fi check_eq openjpeg/dump-lines 83 "$(wc -l < "$tmp/dump.txt" | tr -d ' ')" check_out openjpeg/dump-geometry "x1=96, y1=64" cat "$tmp/dump.txt" check_out openjpeg/dump-numcomps "numcomps=3" cat "$tmp/dump.txt" check_out openjpeg/dump-precision "prec=8" cat "$tmp/dump.txt" # qmfbid=1 IS the reversible 5/3 wavelet, which is what makes the exactness # cases above a requirement rather than a hope. If this ever reads 0 for a # default encode, those cases are asserting something the codestream no longer # promises. check_out openjpeg/dump-reversible "qmfbid=1" cat "$tmp/dump.txt" check_out openjpeg/dump-single-tile "tw=1, th=1" cat "$tmp/dump.txt" check_out openjpeg/dump-mct "mct=1" cat "$tmp/dump.txt" check_out openjpeg/dump-resolutions "numresolutions=6" cat "$tmp/dump.txt" # ------------------------------------- rate-limited, STILL REVERSIBLE (B/C) --- # -r 20 asks for 20x compression and is LOSSY BY TRUNCATION -- openjpeg keeps # the reversible 5/3 transform (qmfbid stays 1) and simply discards coding # passes. So this arm is still integer arithmetic end to end, which is why its # digest is pinnable at all. It is a different failure surface from -I below: # this one exercises the RATE ALLOCATOR, that one exercises floating point. r20=$tmp/rate20.jp2 check openjpeg/encode-rate20 opj_compress -i "$fix" -o "$r20" -r 20 check_eq openjpeg/encode-rate20-size 937 "$(size "$r20")" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-rate20-digest 5ab6b16608a3465ffa27d834afc98cf7 "$(md5of "$r20")" else bst_skip openjpeg/encode-rate20-digest "no md5sum on this image" fi r20d=$tmp/dec_rate20.ppm check openjpeg/decode-rate20 opj_decompress -i "$r20" -o "$r20d" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/decode-rate20-raster 1a74ddec136c4bb685c92f5dde46b56c "$(raster "$r20d")" else bst_skip openjpeg/decode-rate20-raster "no md5sum on this image" fi # (C) A "lossy" codec that returned its input would pass every digest above once # re-pinned. Asserting that it did NOT is what keeps those pins meaningful. if [ "$(raster "$r20d")" = "$fixraster" ]; then bst_notok openjpeg/rate20-is-lossy "-r 20 decode is identical to the source raster" else bst_ok openjpeg/rate20-is-lossy fi # (C) 20x asked for, and the whole point of a rate allocator is that it delivers. # 18445/937 is ~19.7x of the PPM, comfortably inside a factor of two of the # request; the bound is loose on purpose, because the exact size is already # pinned above and this case exists to catch an allocator that ignored -r # entirely rather than one that rounded differently. if [ "$(size "$r20")" -lt 2000 ]; then bst_ok openjpeg/rate20-honoured else bst_notok openjpeg/rate20-honoured "$(size "$r20") bytes for a 20x request on an 18445-byte source" fi # ------------------------------- the irreversible 9/7 path: FLOATING POINT ---- # THE ONLY FLOATING-POINT ARM IN THIS SUITE, and the one place a wasm32 target # could legitimately have diverged from x86-64. See READING A RED above before # touching this pin. ir=$tmp/irrev.jp2 check openjpeg/encode-irrev opj_compress -i "$fix" -o "$ir" -I -r 20 check_eq openjpeg/encode-irrev-size 937 "$(size "$ir")" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-irrev-digest 668ab3fa9771fbd04c9c7d34f33fb39c "$(md5of "$ir")" else bst_skip openjpeg/encode-irrev-digest "no md5sum on this image" fi ird=$tmp/dec_irrev.ppm check openjpeg/decode-irrev opj_decompress -i "$ir" -o "$ird" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/decode-irrev-raster 0397c3a8d94649394a4310cd01a1ace3 "$(raster "$ird")" else bst_skip openjpeg/decode-irrev-raster "no md5sum on this image" fi if [ "$(raster "$ird")" = "$fixraster" ]; then bst_notok openjpeg/irrev-is-lossy "-I -r 20 decode is identical to the source raster" else bst_ok openjpeg/irrev-is-lossy fi # The two arms must not be the same file: same rate, different transform. check_out openjpeg/dump-irreversible "qmfbid=0" sh -c "opj_dump -i '$ir' 2>/dev/null" if cmp -s "$r20" "$ir"; then bst_notok openjpeg/transform-selected "-I produced the same codestream as the reversible encode" else bst_ok openjpeg/transform-selected fi # ----------------------------------------------- layers, tiles, sub-decodes --- # Three codestream FEATURES rather than three more digests: each changes the # structure opj_dump reports, so each is asserted through the structure as well # as through the bytes. ly=$tmp/layers.jp2 check openjpeg/encode-layers opj_compress -i "$fix" -o "$ly" -r 40,20,10 if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-layers-digest 97a9ee77dfef8b86d361e2a6bc1525c4 "$(md5of "$ly")" else bst_skip openjpeg/encode-layers-digest "no md5sum on this image" fi check_out openjpeg/dump-numlayers "numlayers=3" sh -c "opj_dump -i '$ly' 2>/dev/null" ti=$tmp/tiled.jp2 check openjpeg/encode-tiled opj_compress -i "$fix" -o "$ti" -t 32,32 if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-tiled-digest 644c92a95074eca7226c136b5c828ebc "$(md5of "$ti")" else bst_skip openjpeg/encode-tiled-digest "no md5sum on this image" fi check_out openjpeg/dump-tile-grid "tw=3, th=2" sh -c "opj_dump -i '$ti' 2>/dev/null" tid=$tmp/dec_tiled.ppm check openjpeg/decode-tiled opj_decompress -i "$ti" -o "$tid" # (A) Tiling changes how the picture is cut up, never what it contains. A tile # offset applied in one direction only would survive every digest that was # re-pinned and would fail here. check_eq openjpeg/roundtrip-tiled-exact "$fixraster" "$(raster "$tid")" # -r on DECOMPRESS is the resolution reduction, not a rate: one wavelet level # discarded, so half the linear size. This is JPEG-2000's headline capability -- # a smaller picture read from the SAME codestream, without decoding all of it. rd=$tmp/red1.ppm check openjpeg/decode-reduce opj_decompress -i "$lj" -o "$rd" -r 1 check_eq openjpeg/decode-reduce-geometry "48x32" "$(geom "$rd")" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/decode-reduce-raster 69ed7ecd93eeb1ddd0df4b955590da7c "$(raster "$rd" 4608)" else bst_skip openjpeg/decode-reduce-raster "no md5sum on this image" fi # A region of interest decoded out of the middle of the codestream. The window # deliberately straddles the disc's edge, so a decoder that got the region # origin wrong returns a picture of the wrong part of the image rather than # a corrupt one -- which only a pinned raster distinguishes from success. rg=$tmp/reg.ppm check openjpeg/decode-region opj_decompress -i "$lj" -o "$rg" -d 24,16,56,48 check_eq openjpeg/decode-region-geometry "32x32" "$(geom "$rg")" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/decode-region-raster e05d6f8cc5c8083b6412bf73bb495d35 "$(raster "$rg" 3072)" else bst_skip openjpeg/decode-region-raster "no md5sum on this image" fi # ------------------------------------------ the single-component path (A/B) --- # Three components exercise the multi-component transform (mct=1); ONE component # turns it off, and that is a different code path rather than the same one run # thinner. The greyscale is extracted from the colour codestream rather than # shipped as a second payload, so the two halves cannot drift apart. c0=$tmp/c0.pgm check openjpeg/decode-component opj_decompress -i "$lj" -o "$c0" -c 0 if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/decode-component-raster e3a40bd7aa1b647091a8ab90d9c6cbc5 "$(raster "$c0" 6144)" else bst_skip openjpeg/decode-component-raster "no md5sum on this image" fi gj=$tmp/gray.jp2 check openjpeg/encode-gray opj_compress -i "$c0" -o "$gj" if [ "$have_md5" -eq 1 ]; then check_eq openjpeg/encode-gray-digest 8f6027770cdd46b647c64d1d9644b7fc "$(md5of "$gj")" else bst_skip openjpeg/encode-gray-digest "no md5sum on this image" fi check_out openjpeg/dump-gray-mct "mct=0" sh -c "opj_dump -i '$gj' 2>/dev/null" gd_=$tmp/gray_dec.pgm check openjpeg/decode-gray opj_decompress -i "$gj" -o "$gd_" check_eq openjpeg/gray-roundtrip-exact "$(raster "$c0" 6144)" "$(raster "$gd_" 6144)" # ----------------------------------------------- TIFF: the linkage guard (C) --- # See "WHY THE TIFF CASES EARN THEIR PLACE" at the top. Nothing here is pinned # to a byte: libtiff's own output is libtiff's business and changes with its # version. What must hold is that a lossless codestream survives a trip out # through the TIFF writer and back in through the TIFF reader. tf=$tmp/out.tif if opj_decompress -i "$lj" -o "$tf" >/dev/null 2>&1 && [ -s "$tf" ]; then bst_ok openjpeg/tiff-write # A TIFF really is a TIFF. Read as hex rather than as `od -c` characters, # because the version word 42 renders as the character `*` there and a case # pattern then has to carry an escaped NUL -- which different shells treat # differently. Both byte orders are accepted: openjpeg's writer opens with # libtiff's "wb" mode, which is big-endian regardless of the host, so MM is # what this arm produces, but the assertion this case owes is "a TIFF was # written", not "in this order". if command -v od >/dev/null 2>&1; then mag=$(head -c 4 "$tf" | od -An -t x1 2>/dev/null | tr -s ' ' | sed 's/^ *//;s/ *$//') case "$mag" in "49 49 2a 00"|"4d 4d 00 2a") bst_ok openjpeg/tiff-magic ;; *) bst_notok openjpeg/tiff-magic "first four bytes are $mag, not a TIFF header" ;; esac else bst_skip openjpeg/tiff-magic "no od on this image" fi tj=$tmp/fromtif.jp2 if opj_compress -i "$tf" -o "$tj" >/dev/null 2>&1 && [ -s "$tj" ]; then bst_ok openjpeg/tiff-read tp=$tmp/fromtif.ppm opj_decompress -i "$tj" -o "$tp" >/dev/null 2>&1 # THE CASE THE PHANTOM-IMPORT BUG WOULD HAVE FAILED, and the reason it is # an exactness case rather than a digest: it holds for any libtiff. check_eq openjpeg/tiff-roundtrip-exact "$fixraster" "$(raster "$tp")" else bst_notok openjpeg/tiff-read "opj_compress refused the TIFF opj_decompress wrote" bst_notok openjpeg/tiff-roundtrip-exact "not run -- the TIFF reader refused" fi else bst_notok openjpeg/tiff-write "opj_decompress produced no TIFF -- libtiff not linked?" bst_notok openjpeg/tiff-read "not run -- no TIFF was written" bst_notok openjpeg/tiff-roundtrip-exact "not run -- no TIFF was written" fi # ------------------------------------------------- malformed input: REFUSALS --- # A codec that accepts garbage is a security question. Two of this recipe's # three patches are CVE fixes, so the refusals are pinned as tightly as the # successes. THE THREE CASES ARE DELIBERATELY DIFFERENT DEPTHS OF DAMAGE: a cut # inside the entropy data (markers parse, packets do not), a cut before the JP2 # header boxes are complete, and something that is not an image at all. They # produce three different diagnostics, and a decoder that had collapsed them # into one generic error would have lost the ability to say where it stopped. head -c 500 "$lj" > "$tmp/trunc-entropy.jp2" 2>/dev/null head -c 60 "$lj" > "$tmp/trunc-header.jp2" 2>/dev/null printf 'not a jp2 at all\n' > "$tmp/junk.jp2" check_rc openjpeg/truncated-entropy-rc 1 \ opj_decompress -i "$tmp/trunc-entropy.jp2" -o "$tmp/t1.ppm" check_out openjpeg/truncated-entropy-diagnostic "Tile part length size inconsistent with stream length" \ sh -c "opj_decompress -i '$tmp/trunc-entropy.jp2' -o '$tmp/t1.ppm' 2>&1; exit 0" check_rc openjpeg/truncated-header-rc 1 \ opj_decompress -i "$tmp/trunc-header.jp2" -o "$tmp/t2.ppm" check_out openjpeg/truncated-header-diagnostic "Invalid box size" \ sh -c "opj_decompress -i '$tmp/trunc-header.jp2' -o '$tmp/t2.ppm' 2>&1; exit 0" check_rc openjpeg/junk-rc 1 opj_decompress -i "$tmp/junk.jp2" -o "$tmp/t3.ppm" check_out openjpeg/junk-diagnostic "Unknown input file format" \ sh -c "opj_decompress -i '$tmp/junk.jp2' -o '$tmp/t3.ppm' 2>&1; exit 0" # "A DIAGNOSTIC, NOT A CRASH" IS TWO CLAIMS AND check_rc ONLY MAKES ONE OF THEM. # A shell reports a killed child as 128+signal, so a decoder that segfaulted on # the truncated file would exit 139 -- non-zero, and enough to satisfy any gate # that only asked for failure. Assert the range explicitly. for pair in "entropy:$tmp/trunc-entropy.jp2" "header:$tmp/trunc-header.jp2" "junk:$tmp/junk.jp2"; do nm=${pair%%:*}; fl=${pair#*:} opj_decompress -i "$fl" -o "$tmp/nc.ppm" >/dev/null 2>&1 rc=$? if [ "$rc" -gt 0 ] && [ "$rc" -lt 128 ]; then bst_ok openjpeg/no-crash-$nm else bst_notok openjpeg/no-crash-$nm "exit $rc -- 128+ means killed by a signal, not refused" fi done # opj_dump is a separate program over the same reader and must refuse the file # it cannot identify. IT MUST ALSO ACCEPT THE ENTROPY-TRUNCATED ONE: the main # header is intact there and reporting it is precisely what a header dumper is # for, so a dumper that refused it would be the regression. The pair is what # distinguishes "refuses everything damaged" from "reads what is readable". check_rc openjpeg/dump-rejects-junk 1 opj_dump -i "$tmp/junk.jp2" check_rc openjpeg/dump-rejects-bad-header 1 opj_dump -i "$tmp/trunc-header.jp2" check_rc openjpeg/dump-reads-partial-file 0 opj_dump -i "$tmp/trunc-entropy.jp2" # Shape, not absence: this arm converts to shared libraries per recipe # (BRINTOS-1740), so a .so here is a conversion, not a policy breach. bst_lib_shape openjpeg/static-only "/usr/lib/libopenjp2.so*" if [ -f /usr/lib/libopenjp2.a ]; then bst_ok openjpeg/archive else bst_notok openjpeg/archive "/usr/lib/libopenjp2.a is missing"; fi if [ -f /usr/include/openjpeg-2.5/openjpeg.h ]; then bst_ok openjpeg/headers else bst_notok openjpeg/headers "/usr/include/openjpeg-2.5/openjpeg.h is missing" fi # One line carrying everything a re-derivation needs, so a drifted pin can be # replaced from the run that found it rather than from a second run. echo "==OPENJPEG-OBSERVED ll=$(md5of "$lj") j2k=$(md5of "$lc") r20=$(md5of "$r20") irrev=$(md5of "$ir") layers=$(md5of "$ly") tiled=$(md5of "$ti") gray=$(md5of "$gj") dump=$(md5of "$tmp/dump.txt") decll=$(raster "$ld") decr20=$(raster "$r20d") decirrev=$(raster "$ird")==" rm -rf "$tmp"