. "$BST_LIB" # oniguruma 6.9.9 -- the regex library jq and Ruby use. The distro is static-only, # so the payload is two headers, a .pc and the onig-config stub (-dev) plus # libonig.a (-staticdev), and nothing on this image links it yet. # # THIS SUITE IS NOT PAYLOAD-ONLY, and that is the point of the port. onig is the # package that produced the coroutinize pass's dynamic-alloca refusal: without the # bbappend's patch the archive builds and packages perfectly and then every # consumer's final link dies, so "the files are present and well-formed" is # EXACTLY the evidence that would have passed on a library nobody could use. The # only way to tell the two apart on target is to run something linked against the # archive, so data/onig-probe -- cross-linked with wasmcc-glibc against this very # libonig.a, the data/vfs-probe shape -- is driven below and its output compared # against a native build of the identical source. # # That decision is what found the SECOND defect. The static half of this suite is # 159/159 green; the runtime half is 21/26 RED on hwjs-cc#24, a silent # wrong-answer bug that no payload-shaped suite could ever have seen. See the # banner above the runtime section. # # Four things here would be got wrong by copying a neighbouring suite, all of # them measured rather than assumed: # # 1. THE mixed-* CASES ARE THE PATCH'S REGRESSION GUARD, not decoration. # disable_noname_group_capture() is the one function the pass refused; it # runs only when a pattern MIXES named and unnamed groups under a syntax # setting ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP. Instrumenting the library showed # the probe reaches it exactly 4 times -- the four mixed cases -- and zero # times for the three controls, so the pairing is what makes the guard real. # 2. AN UNNAMED GROUP IS DEMOTED TO NON-CAPTURING, which is the observable # behaviour the patched function implements: `(?x)(y)` yields ONE capture, # not two. A suite asserting two would fail against a correct port. The # contrast case is ONIG_OPTION_CAPTURE_GROUP, which keeps both -- and it is # the only available contrast, because EVERY built-in syntax that can express # (?...) at all (Oniguruma, Ruby, Perl_NG) also sets that syntax bit. # Plain ONIG_SYNTAX_PERL rejects (?...) outright. # 3. oniguruma.pc's Cflags AND Libs ARE BOTH NON-EMPTY AT THE SOURCE # (`-I${includedir}` / `-L${libdir} -lonig`), so pkgconf FILTERS them and # --keep-system-* RESTORES them. This is the cmark case and the exact # opposite of 76-libmxml.test, where identical output proves the fields were # never populated. Asserting only the filtered half would pass for the wrong # reason, so both directions are asserted. # 4. onig-config IS A STUB THAT MUST FAIL. The recipe inherits # binconfig-disabled, so the script's job is to refuse and exit 1. Asserting # that it ANSWERS anything would be asserting the policy had broken. root=${BST_ROOT:-} inc=$root/usr/include/oniguruma.h gnu=$root/usr/include/oniggnu.h pc=$root/usr/lib/pkgconfig/oniguruma.pc lib=$root/usr/lib/libonig.a cfg=$root/usr/bin/onig-config # ---------------------------------------------------------------- headers ---- check onig/header-present test -f "$inc" check onig/header-nonempty test -s "$inc" check_out onig/header-guard "#define ONIGURUMA_H" cat "$inc" check_out onig/header-extern-c 'extern "C" {' cat "$inc" check onig/gnu-header test -f "$gnu" check_out onig/gnu-header-guard "#define ONIGGNU_H" cat "$gnu" # Version, three macros plus the packed integer a consumer compares against. check_eq onig/ver-major 6 "$(awk '/define[ \t]+ONIGURUMA_VERSION_MAJOR/{print $3}' "$inc")" check_eq onig/ver-minor 9 "$(awk '/define[ \t]+ONIGURUMA_VERSION_MINOR/{print $3}' "$inc")" check_eq onig/ver-teeny 9 "$(awk '/define[ \t]+ONIGURUMA_VERSION_TEENY/{print $3}' "$inc")" check_eq onig/ver-int 60909 "$(awk '/define[ \t]+ONIGURUMA_VERSION_INT/{print $3}' "$inc")" # onigposix.h is ABSENT and that is correct: the POSIX API is off by upstream's # default in 6.9.x and the recipe does not enable it. Asserted so that turning it # on later is a visible test change rather than a silent one. check onig/no-posix-header sh -c '[ ! -e "$1/usr/include/onigposix.h" ]' _ "$root" # The syntax and encoding externs a caller names. These are the whole reason to # use oniguruma over glibc's POSIX regex, and each is a real object in the # archive further down, so header and archive have to agree. for s in ONIG_SYNTAX_ONIGURUMA ONIG_SYNTAX_RUBY ONIG_SYNTAX_PERL \ ONIG_SYNTAX_PERL_NG ONIG_SYNTAX_JAVA ONIG_SYNTAX_GNU_REGEX \ ONIG_SYNTAX_GREP ONIG_SYNTAX_EMACS ONIG_SYNTAX_POSIX_BASIC \ ONIG_SYNTAX_POSIX_EXTENDED ONIG_SYNTAX_DEFAULT; do check_out "onig/hdr-$s" "#define $s" cat "$inc" done for e in ONIG_ENCODING_UTF8 ONIG_ENCODING_ASCII ONIG_ENCODING_ISO_8859_1 \ ONIG_ENCODING_EUC_JP ONIG_ENCODING_SJIS ONIG_ENCODING_UTF16_BE \ ONIG_ENCODING_KOI8_R ONIG_ENCODING_BIG5 ONIG_ENCODING_GB18030; do check_out "onig/hdr-$e" "#define $e" cat "$inc" done # The option bits and the one error code the probe asserts by value. for o in ONIG_OPTION_NONE ONIG_OPTION_IGNORECASE ONIG_OPTION_EXTEND \ ONIG_OPTION_MULTILINE ONIG_OPTION_SINGLELINE ONIG_OPTION_FIND_LONGEST \ ONIG_OPTION_CAPTURE_GROUP ONIG_OPTION_DONT_CAPTURE_GROUP; do check_out "onig/hdr-$o" "#define $o" cat "$inc" done check_out onig/hdr-syn-capture-only "#define ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP" cat "$inc" check_out onig/hdr-err-unmatched-paren \ "define ONIGERR_END_PATTERN_WITH_UNMATCHED_PARENTHESIS" cat "$inc" check_out onig/hdr-max-errmsg "#define ONIG_MAX_ERROR_MESSAGE_LEN" cat "$inc" # ------------------------------------------------------------ pkg-config ---- check onig/pc-present test -f "$pc" check_out onig/pc-name "Name: oniguruma" cat "$pc" check_out onig/pc-desc "Description: Regular expression library" cat "$pc" check_out onig/pc-version "Version: 6.9.9" cat "$pc" check_out onig/pc-prefix "prefix=/usr" cat "$pc" check_out onig/pc-libdir "libdir=/usr/lib" cat "$pc" check_out onig/pc-incdir "includedir=/usr/include" cat "$pc" # Non-empty at the source -- see note 3. These two exact strings are what # --keep-system-* restores below. check_eq onig/pc-libs-raw '-L${libdir} -lonig' \ "$(sed -n 's/^Libs:[ ]*//p' "$pc")" check_eq onig/pc-cflags-raw '-I${includedir}' \ "$(sed -n 's/^Cflags:[ ]*//p' "$pc")" # No Requires: oniguruma needs nothing beyond libc, so a consumer's link line is # self-contained. check_eq onig/pc-requires-empty "" "$(sed -n 's/^Requires:[ ]*//p' "$pc")" # ------------------------------------------------------- onig-config stub ---- # See note 4: the stub's contract is to refuse. check onig/cfg-present test -f "$cfg" check_rc onig/cfg-exits-1 1 "$cfg" --version # The message is captured first because check_out also requires exit 0, and this # script's whole contract is to exit 1 -- asserting it through check_out directly # would fail on a stub that is behaving correctly. cfgout=$("$cfg" --cflags 2>&1 || true) check_out onig/cfg-says-pkgconfig "use an alternative such as pkg-config" \ printf '%s\n' "$cfgout" # ------------------------------------------------------------- the archive ---- check onig/lib-present test -f "$lib" check onig/lib-nonempty test -s "$lib" check_out onig/lib-archive "!" head -c 8 "$lib" flat=${TMPDIR:-/tmp}/bst-onig.$$ tr -c '\40-\176\n' ' ' < "$lib" > "$flat" 2>/dev/null # 48 members, one per translation unit: the engine, then one per encoding. The # encoding members are most of the archive and are the reason it is ~1.9 MB. for m in regparse regcomp regexec regenc regerror regext regsyntax regtrav \ regversion st reggnu unicode onig_init ascii utf8 utf16_be utf16_le \ utf32_be utf32_le euc_jp sjis big5 gb18030 koi8_r cp1251 euc_tw euc_kr \ iso8859_1 iso8859_5 iso8859_15 iso8859_16 \ unicode_unfold_key unicode_fold1_key unicode_fold2_key unicode_fold3_key; do check "onig/member-$m" grep -q "$m\.o" "$flat" done # The public API a consumer links against. for s in onig_new onig_new_without_alloc onig_free onig_free_body \ onig_search onig_search_with_param onig_match onig_match_with_param \ onig_scan onig_region_new onig_region_free onig_region_copy \ onig_region_clear onig_region_resize onig_region_set \ onig_name_to_group_numbers onig_name_to_backref_number \ onig_foreach_name onig_number_of_names onig_number_of_captures \ onig_number_of_capture_histories onig_get_capture_tree \ onig_error_code_to_str onig_initialize onig_end onig_version \ onig_copyright onig_get_encoding onig_get_syntax onig_set_syntax_op \ onig_get_options onig_set_default_syntax onig_new_deluxe \ onig_regset_new onig_regset_add onig_regset_search onig_regset_free \ onig_set_callout_of_name onig_get_callout_num_by_tag \ onig_initialize_encoding onig_get_default_case_fold_flag; do check "onig/sym-$s" grep -q "$s" "$flat" done # The syntax and encoding OBJECTS the header's macros dereference. A header # declaring ONIG_SYNTAX_RUBY whose OnigSyntaxRuby is missing from the archive is a # link error in the consumer, not a compile error, so these are asserted apart # from the macros above. for s in OnigSyntaxOniguruma OnigSyntaxRuby OnigSyntaxPerl OnigSyntaxPerl_NG \ OnigSyntaxJava OnigSyntaxGnuRegex OnigSyntaxGrep OnigSyntaxEmacs \ OnigSyntaxPosixBasic OnigSyntaxPosixExtended OnigDefaultSyntax; do check "onig/obj-$s" grep -q "$s" "$flat" done for e in OnigEncodingUTF8 OnigEncodingASCII OnigEncodingISO_8859_1 \ OnigEncodingEUC_JP OnigEncodingSJIS OnigEncodingUTF16_BE \ OnigEncodingKOI8_R OnigEncodingBIG5 OnigEncodingGB18030; do check "onig/obj-$e" grep -q "$e" "$flat" done # The wasm32 arm witness, and a size window. ~1.96 MB here; a build that dropped # the encoding members would fall far below, one that kept debug info far above. check onig/arm-not-elf sh -c '! head -c 512 "$1" | grep -q "ELF"' _ "$lib" sz=$(wc -c < "$lib") check onig/lib-size-window sh -c '[ "$1" -gt 1500000 ] && [ "$1" -lt 2500000 ]' _ "$sz" # Static-only packaging policy: onig's configure builds libonig.so.5 by default # and the distro's blanket --disable-shared is what turns it off, so a stray .so # would mean that flag stopped reaching this recipe. check onig/no-shared sh -c 'set -- "$1"/usr/lib/libonig.so*; [ ! -e "$1" ]' _ "$root" check onig/no-libtool sh -c '[ ! -e "$1/usr/lib/libonig.la" ]' _ "$root" # ptest is not in DISTRO_FEATURES, so the recipe's do_install_ptest never ran and # none of onig's test binaries reached the image. check onig/no-ptest sh -c '[ ! -d "$1/usr/lib/onig/ptest" ]' _ "$root" rm -f "$flat" # --------------------------------------------------- the library, RUNNING ---- # Everything above is true of an UNLINKABLE library too (see the header comment). # This is the part that is not — and this is the part that is currently RED. # # 21 OF THE 26 ASSERTIONS BELOW FAIL ON TARGET, ALL ON ONE ROOT CAUSE: # brintos.io/brintos/hwjs-cc/issues/24. oniguruma links (refused=0, after the # bbappend's patch) and then returns silently wrong match offsets: the match # START is correct, the match END comes back equal to the start, and every # capture group comes back unset. No trap, no diagnostic. onig's OWN upstream # `testc` scores 118/785 on this arm against 785/785 natively, so this is the # library on this platform, not this suite and not this probe. # # THE EXPECTED VALUES BELOW ARE DELIBERATELY LEFT AT THE CORRECT ONES -- the # values a native build of the identical release produces. They are not relaxed # to match the broken behaviour and the cases are not skipped, because that would # convert a live regression tripwire into a suite that passes on a broken # library. When #24 is fixed these 21 flip green on their own, which is the whole # point of leaving them failing. The five that DO pass (version, copyright, the # name table, regset and the error path) are the ones that read state out of the # compiled regex rather than out of an OnigRegion. probe=${TMPDIR:-/tmp}/bst-onig-probe.$$ if cp "$BST_DATA/onig-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then out=$("$probe" 2>&1) check_out onig/run-version "ONIG-version OK [6.9.9]" printf '%s\n' "$out" check_out onig/run-copyright "ONIG-copyright OK" printf '%s\n' "$out" # Note 1/2: the four cases that reach the patched function, asserted by their # full group layout rather than by a bare OK, because the layout IS what # disable_noname_group_capture() rewrites. check_out onig/run-mixed-2 \ "ONIG-mixed-2 OK [names=1 caps=1 rc=0 regs=2 g1=x]" printf '%s\n' "$out" check_out onig/run-mixed-3 \ "ONIG-mixed-3 OK [names=2 caps=2 rc=0 regs=3 g1=a g2=c]" printf '%s\n' "$out" check_out onig/run-mixed-digit \ "ONIG-mixed-digit OK [names=1 caps=1 rc=0 regs=2 g1=42]" printf '%s\n' "$out" check_out onig/run-perlng-mixed \ "ONIG-perlng-mixed OK [names=1 caps=1 rc=0 regs=2 g1=x]" printf '%s\n' "$out" # ...and the three that do not. mixed-capture-opt is the same pattern and # syntax as mixed-2 with ONIG_OPTION_CAPTURE_GROUP added: caps goes 1 -> 2. check_out onig/run-mixed-capture-opt \ "ONIG-mixed-capture-opt OK [names=1 caps=2 rc=0 regs=3 g1=x g2=y]" printf '%s\n' "$out" check_out onig/run-allnamed \ "ONIG-allnamed OK [names=2 caps=2 rc=0 regs=3 g1=x g2=y]" printf '%s\n' "$out" check_out onig/run-allunnamed \ "ONIG-allunnamed OK [names=0 caps=2 rc=0 regs=3 g1=x g2=y]" printf '%s\n' "$out" # The name table, sorted (the callback's own order is a hash artifact). check_out onig/run-names \ "ONIG-names OK [count=2 list=mon,year mon->n=1 g=2]" printf '%s\n' "$out" check_out onig/run-backref-icase \ "ONIG-backref-icase OK [pos=2 len=4]" printf '%s\n' "$out" check_out onig/run-scan \ "ONIG-scan OK [n=3 cb=3 text=1,22,333]" printf '%s\n' "$out" check_out onig/run-regset \ "ONIG-regset OK [idx=0 pos=3 n=2]" printf '%s\n' "$out" # The error path returns a code AND renders a message; both are asserted, since # a stubbed onig_error_code_to_str would still return the right code. check_out onig/run-error \ "ONIG-error-badpat OK [rc=-117 msg=end pattern with unmatched parenthesis]" \ printf '%s\n' "$out" # Five grammars over the same engine -- the dialect support that is the reason # to ship oniguruma rather than rely on glibc's POSIX regex. check_out onig/run-syn-ruby "ONIG-syn-ruby OK [pos=2 len=4]" printf '%s\n' "$out" check_out onig/run-syn-perl "ONIG-syn-perl OK [pos=2 len=3]" printf '%s\n' "$out" check_out onig/run-syn-java "ONIG-syn-java OK [pos=2 len=3]" printf '%s\n' "$out" check_out onig/run-syn-posix "ONIG-syn-posix OK [pos=2 len=2]" printf '%s\n' "$out" check_out onig/run-syn-grep "ONIG-syn-grep OK [pos=2 len=3]" printf '%s\n' "$out" # Four encodings, including two multibyte ones -- these are the only cases that # actually consult an encoding table rather than carry it. check_out onig/run-enc-utf8 "ONIG-enc-utf8 OK [pos=2 len=4]" printf '%s\n' "$out" check_out onig/run-enc-ascii "ONIG-enc-ascii OK [pos=1 len=3]" printf '%s\n' "$out" check_out onig/run-enc-latin1 "ONIG-enc-latin1 OK [pos=2 len=2]" printf '%s\n' "$out" check_out onig/run-enc-eucjp "ONIG-enc-eucjp OK [pos=1 len=4]" printf '%s\n' "$out" check_out onig/run-utf8-prop "ONIG-utf8-prop OK [pos=3 len=3]" printf '%s\n' "$out" # The probe's own tally, and its exit status. 24/24 is what the same source # scores natively against a host build of the identical release. check_out onig/run-summary "ONIG-SUMMARY 24/24" printf '%s\n' "$out" check_rc onig/run-exit0 0 "$probe" rm -f "$probe" else bst_notok onig/run-stage "cannot stage $BST_DATA/onig-probe" fi