. "$BST_LIB" # BST-TIMEOUT: 300 # NOT MEASURED ON TARGET YET. One probe run plus ~150 shell # extractions -- the shape of 57-libxtst.test, which # carries the same 300 for ~130 of them. Replace this note # with a measured elapsed the first time the suite runs on # target. # libXRes 1.2.2 -- the client half of the X-Resource extension (poky # recipes-graphics/xorg-lib). See libxres_%.bbappend for what the port adds and # why. # # --------------------------------------------------------------------------- # NOTHING HERE HAS RUN ON A TARGET YET # # This file was written in a phase that builds at recipe scope only and never # boots an image, so no value in it is an on-target finding. Where a red # appears, read it as this file having been wrong until the case is checked # against the source again. # # But the expectations are not all of one kind, and the difference matters when # you are reading a red: # # THE PACKAGING BLOCK IS MEASURED, off the five .debs the recipe-scope build # produced (1367 of 1367 tasks, all succeeded). libxres-dev carries XRes.h and # xres.pc; libxres-staticdev carries libXRes.a; libxres-tests carries the # probe; libxres-doc carries the six man pages; and there is NO bare libxres # package, which is what libxres/no-shared asserts from the other side. The # xres.pc cases below quote that file's actual contents, and all eleven # libxres/sym-* names were confirmed present in the built archive. Those are # results, not predictions. What remains unmeasured about them is only that # the packages INSTALL on a target -- which is what the image build and this # suite's own libxres/present case answer. # # GROUPS C, V, P, W, X, I AND L ARE CONFIRMED ON A REFERENCE BUILD. The probe # was compiled and run on x86-64 against libXRes 1.2.2's own src/XRes.c, and # every value those groups assert below was MEASURED there, not guessed. # Those groups are architecture-independent -- constants out of the protocol # headers, control flow through a guard, the Display bookkeeping an # initialisation leaves behind -- so the reference answers them for this arm # too. A red in one of them means the target genuinely diverges from x86-64, # which would be worth a ticket on its own. # # GROUP A IS DERIVED, and deliberately so: it is the one group that CANNOT be # confirmed off-target, because it is the group that is about the word size. # The reference run measured the LP64 layout; the values below are the ILP32 # ones, and every one of them is exactly half its LP64 counterpart except the # `unsigned int' member, which is 4 on both. That halving is the derivation, # and A is where a surprise would be a real finding rather than a typo. # # GROUP W IS HALF AND HALF. The arm and the widths are measured here; the # FOLD those widths select is behind a guard and is not executed by anybody, # on either machine. It is stated as unmeasured below rather than asserted. # # --------------------------------------------------------------------------- # X-RESOURCE CANNOT REACH A SERVER HERE, AND THAT IS WHAT IS MEASURED # # X-Resource's whole subject is what the SERVER holds on each client's behalf -- # which clients exist, what each owns, what it costs. This image has no X server # (57-libx11 measures XOpenDisplay returning NULL, in four forms, and this suite # does not repeat it), so nine of libXRes's eleven entry points cannot complete. # They are not untested; they are unreachable past a guard, by construction. # # What IS reachable is three things: # # THREE ENTRY POINTS NEVER TOUCH A CONNECTION (group P): XResGetClientIdType, # XResGetClientPid, and the two free functions XResClientIdsDestroy and # XResResourceSizeValuesDestroy, executed as a consumer would execute them. # # THE GUARD THE OTHER SEVEN PASS FIRST (group X), and there are TWO of them: # # XResCheckExtension -> XextCheckExtension, for six of the seven -- calls # XMissingExtension and returns the value the macro was # given # the `else' arm XResQueryExtension alone -- returns False and calls # nothing at all # # The probe installs an extension-error handler, so "returned 0" and # "returned 0 having raised the missing-extension error" are DIFFERENT # measurements rather than one undifferentiated "no display". # # WHAT INITIALISATION LEFT ON THE DISPLAY (group I). # # --------------------------------------------------------------------------- # THE FINDING: ON THE REFUSAL PATH, TWO ENTRY POINTS REPORT SUCCESS # # XResCheckExtension(dpy, info, 0) returns ZERO. For the four v1.0 calls that is # correct -- their return is a Status in Xlib's older sense, 1 for success and 0 # for failure. # # The two v1.2 calls that return `Success' inverted that convention and the # guard was never updated with them. XResQueryClientIds and # XResQueryResourceBytes return `Success' -- which X.h defines as 0 -- on their # success path and `!Success' (1) on their own error path. So the guard's zero # is INDISTINGUISHABLE FROM SUCCESS, and a caller that writes the documented # `if (XResQueryClientIds(...) == Success)' is told the call worked. That is # X51 and X61, and both were reproduced on the reference build. # # What such a caller then reads is uninitialised. Both functions set only their # COUNT out-parameter ahead of the guard (`*num_ids = 0', `*num_sizes = 0'); # the ARRAY out-parameter is assigned only after LockDisplay, which the guard # returns before. X54 and X64 assert exactly that -- the caller's sentinel # survives the call -- so the sequence on this image is: reports Success, count # reads 0, array pointer is whatever the caller's variable held, and # XResClientIdsDestroy is then free(3) on it. # # The four v1.0 calls do NOT have this: X23, X33 and X42 are the same # measurement coming out the other way, because those three zero both # out-parameters before the guard. The asymmetry is why this suite scores each # function's out-parameters separately instead of scoring "the call refused". # # This is an upstream defect in libXRes and it is ours to work around rather # than to report (no-public-upstream-reports). It matters here in particular # because round 16's xrestop is the consumer this library is being ported for, # and xrestop calls both of them. A consumer in this tree must test the COUNT, # or initialise the array pointer to NULL before the call, and not trust the # return. # # X51/X54/X61/X64 therefore assert the BROKEN behaviour on purpose. If upstream # ever fixes the guard, those four go red -- which is the correct signal, and the # comment to read is this one. # # --------------------------------------------------------------------------- # THE 32-BIT FACT IS NOT THE ONE IT LOOKS LIKE # # X-Resource 1.2 is the version whose replies carry 64-bit quantities, and the # expectation going into this port was that a client structure would hold a # 64-bit field that had to stay 64 bits wide on a 32-bit arm. It does not. # Every field on the wire is a CARD32 (XResproto.h, group V), and every # client-side field is an XID, an Atom, an `unsigned int' or a `long' -- all 32 # bits here (group A). There is no 64-bit field in this API to check. # # The 64-bit quantity is assembled from two CARD32s in exactly one place, # xXResQueryClientPixmapBytesReply's `bytes' and `bytes_overflow', and # XResQueryClientPixmapBytes folds them into an `unsigned long': # # #ifdef LONG64 # *bytes = (rep.bytes_overflow * 4294967296UL) + rep.bytes; # #else # *bytes = rep.bytes_overflow ? 0xffffffff : rep.bytes; # #endif # # On this ILP32 arm the extension's headline capability SATURATES: a client # holding more than 4 GiB of pixmaps is reported as exactly 4 GiB - 1, with no # error and no way for a caller to tell that answer from a true one. Group W # asserts the arm and the width. It does not assert the fold, which is behind # the guard and unreachable on an image with no server -- see W90. # # --------------------------------------------------------------------------- # THE CASE EVERYTHING IN X, I AND L RESTS ON IS libxres/no-trap # # libXRes's find_display is static, so its extension list cannot be seeded from # outside. The reachable route -- libxtst's, already measured on this arm -- is # that the only thing between find_display and a wire is XQueryExtension, which # XInitExtension calls first and returns NULL on. The probe DEFINES # XQueryExtension, and in a static link that definition is taken from the # probe's object while libX11's QuExt.o, which holds that function and nothing # else, is never pulled. The stub's answer is the truthful one for this image: # there is no X-Resource here. # # If that link-order argument were wrong, the real XQueryExtension would run # over a Display with no socket and the fault would take the guest's console # down with it -- on an image several tickets share. It cannot. Every path into # Xlib's request machinery begins with LockDisplay, the probe supplies the # Display's lock_fns, and before each guarded call it arms a trap with the # number of stub answers that must have arrived before any lock is legitimate. # A lock that comes too early prints `TRAP ...', prints PROBE-ABORT instead of # PROBE-END, and exits 0. # # That is not a theory: it fires, exactly so, on the x86-64 SHARED-library # reference build, where libXRes's call to XQueryExtension binds to the probe # but libX11's internal one does not (Debian builds libX11 with # -Bsymbolic-functions). So a red on libxres/no-trap with libxres/probe-complete # red beside it and every X/I/L case absent is the method failing SAFELY, not # the library failing. The confirmed X/I/L values quoted above came from a # second, static-equivalent reference link where the interposition does hold. PROBE=${BST_LIBXRES_PROBE:-/usr/libexec/libxres-tests/libxres-probe} ARCHIVE=/usr/lib/libXRes.a PCFILE=/usr/lib/pkgconfig/xres.pc HDR=/usr/include/X11/extensions/XRes.h HDR_PROTO=/usr/include/X11/extensions/XResproto.h # The library version the recipe pins. Asserted rather than read back, so a # recipe bumped without revisiting this suite is a red here instead of a silent # change of subject -- every expectation below is derived from THIS version's # source. WANT_VERSION=1.2.2 # The PROTOCOL version, which is a different number from a different package and # is NOT this one. libXres' own configure.ac says so in as many words: "XResQueryVersion # returns the version from XResproto.h, NOT the version we set here." XRes.h and # the library are 1.2.2 (this recipe); XRES_MAJOR_VERSION/XRES_MINOR_VERSION are # 1 and 2 and come from xorgproto (BRINTOS-1376). A suite that asserted 1.2.2 # against the header macros would be asserting that two independently versioned # packages moved together, which nothing guarantees. WANT_PROTO_MAJOR=1 WANT_PROTO_MINOR=2 # The first BST result line of a suite is dropped by the guest console # (brintos/linux#96), consistently and every run. This case asserts something # already true so that what is lost is a line that costs nothing; remove it when # #96 lands. if [ -f "$ARCHIVE" ]; then bst_ok libxres/suite-canary else bst_notok libxres/suite-canary "$ARCHIVE is not a file"; fi if [ ! -f "$ARCHIVE" ]; then bst_skip libxres/present "libxres not installed on this image" exit 0 fi bst_ok libxres/present # --- the package is whole ----------------------------------------------------- check libxres/staticlib test -s "$ARCHIVE" check libxres/pkgconfig test -s "$PCFILE" check libxres/hdr-xres test -s "$HDR" check libxres/hdr-proto test -s "$HDR_PROTO" # --disable-shared is image-wide, so the archive is the whole library # deliverable. A .so here would mean that stopped being true -- and it is the # reason this suite asserts no soname: libXRes.la carries -version-number 1:0:0, # so a shared build would produce libXRes.so.1.0.0, and on this arm nothing # produces it at all. if [ -e /usr/lib/libXRes.so ] || [ -e /usr/lib/libXRes.so.1 ]; then bst_notok libxres/no-shared "a shared libXRes is installed on a static-only distro" else bst_ok libxres/no-shared fi pcver=$(sed -n 's/^Version: *//p' "$PCFILE" 2>/dev/null | head -1) check_eq libxres/pkgconfig-version "$WANT_VERSION" "$pcver" # xres.pc must name what a consumer resolves through it. On a static-only distro # a missing entry is not a warning -- it is a link that fails in the consumer, # because there is no shared object to carry the dependency. Upstream splits # them: xproto is public (a consumer compiles against its headers through this # file) and x11 and xext are private (needed to link, not to compile). Both # halves matter here, since every link is static. pcpub=$(sed -n 's/^Requires: *//p' "$PCFILE" 2>/dev/null | head -1) case "$pcpub" in *xproto*) bst_ok libxres/pkgconfig-requires-xproto ;; *) bst_notok libxres/pkgconfig-requires-xproto "xres.pc Requires does not name xproto: '$pcpub'" ;; esac pcpriv=$(sed -n 's/^Requires\.private: *//p' "$PCFILE" 2>/dev/null | head -1) for want in x11 xext; do case " $pcpriv " in *" $want "*) bst_ok "libxres/pkgconfig-requires-$want" ;; *) bst_notok "libxres/pkgconfig-requires-$want" "xres.pc Requires.private does not name $want: '$pcpriv'" ;; esac done # xres.pc's -lXRes must name the archive that is actually installed. On a # static-only arm this is the whole of what a consumer's link line resolves to. pclibs=$(sed -n 's/^Libs: *//p' "$PCFILE" 2>/dev/null | head -1) case "$pclibs" in *-lXRes*) bst_ok libxres/pkgconfig-libs ;; *) bst_notok libxres/pkgconfig-libs "xres.pc Libs does not name -lXRes: '$pclibs'" ;; esac # --- the premise: there is no X server on this image -------------------------- # Stated here rather than executed, because 57-libx11 owns the executed form and # runs it last for a reason. These two are free and they fix what the rest of # this file means: with a display, group X would be measuring something else # entirely. if [ -z "${DISPLAY:-}" ]; then bst_ok libxres/no-display else bst_notok libxres/no-display "DISPLAY is set to '$DISPLAY' on an image with no X server"; fi if [ ! -d /tmp/.X11-unix ]; then bst_ok libxres/no-x-socket-dir else bst_notok libxres/no-x-socket-dir "/tmp/.X11-unix exists"; fi # The archive carries the API. grep rather than nm: the image ships no binutils # nm, and the names are present as plain bytes. -a where the grep supports it -- # on this arm the archive members are LLVM IR bitcode (ThinLTO), so a grep that # suppresses matches in a file containing NULs reports nothing; GNU grep needs # -a, busybox grep as shipped does not. Probing keeps this measuring libXRes # rather than measuring the image's grep. if echo x | grep -aq x 2>/dev/null; then _grepq="grep -aq"; else _grepq="grep -q"; fi # All eleven, which is the whole of src/XRes.c's public surface. The probe's # link is the exhaustive check; this is the part that survives the probe being # absent. for sym in XResQueryExtension XResQueryVersion XResQueryClients \ XResQueryClientResources XResQueryClientPixmapBytes \ XResQueryClientIds XResClientIdsDestroy XResGetClientIdType \ XResGetClientPid XResQueryResourceBytes \ XResResourceSizeValuesDestroy; do if $_grepq "$sym" "$ARCHIVE" 2>/dev/null; then bst_ok "libxres/sym-$sym" else bst_notok "libxres/sym-$sym" "$sym absent from $ARCHIVE" fi done # The installed headers must declare what a consumer compiles against. XRes.h is # libXRes's own and carries the client structures as well as the calls, which is # why the type names are checked beside the function names; XResproto.h is # xorgproto's and carries the wire. for decl in XResQueryExtension XResQueryVersion XResQueryClients \ XResQueryClientIds XResGetClientPid XResQueryResourceBytes \ XResClient XResType XResClientIdSpec XResClientIdValue \ XResClientIdType XResResourceIdSpec XResResourceSizeSpec \ XResResourceSizeValue; do if grep -q "$decl" "$HDR" 2>/dev/null; then bst_ok "libxres/hdr-decl-$decl" else bst_notok "libxres/hdr-decl-$decl" "$decl is not declared in $HDR" fi done for decl in XRES_NAME XRES_MAJOR_VERSION X_XResQueryClientIds \ X_XResQueryResourceBytes xXResClient xXResClientIdSpec \ xXResResourceSizeSpec; do if grep -q "$decl" "$HDR_PROTO" 2>/dev/null; then bst_ok "libxres/proto-decl-$decl" else bst_notok "libxres/proto-decl-$decl" "$decl is not declared in $HDR_PROTO" fi done # --- the probe ---------------------------------------------------------------- if [ ! -x "$PROBE" ]; then bst_skip libxres/probe-runs "$PROBE absent from the image" exit 0 fi pout=${TMPDIR:-/tmp}/bst-libxres-out.$$ "$PROBE" > "$pout" 2>&1 prc=$? if [ "$prc" -eq 0 ]; then bst_ok libxres/probe-runs elif bst_execfail "$(head -c 200 "$pout" 2>/dev/null)"; then bst_unrun libxres/probe-runs "$(head -c 200 "$pout" 2>/dev/null)" rm -f "$pout" exit 0 else bst_notok libxres/probe-runs "probe exited $prc: $(_bst_1line "$(head -c 300 "$pout")")" fi if grep -q '^PROBE-END$' "$pout" 2>/dev/null; then bst_ok libxres/probe-complete else bst_notok libxres/probe-complete "probe output has no PROBE-END terminator (last line: $(tail -1 "$pout" 2>/dev/null))" fi # The trap described at the top of this file. A TRAP line means the probe # stopped ITSELF rather than faulting, so this case and probe-complete going red # together, with X/I/L absent, is the method failing safely. if grep -q '^TRAP ' "$pout" 2>/dev/null; then bst_notok libxres/no-trap "the probe trapped: $(grep -m1 '^TRAP ' "$pout")" else bst_ok libxres/no-trap fi # val -- the probe's value for one case, empty when the probe stopped # first. Matches on the ID in field 1 rather than taking the line by position, # because the probe's output is captured with 2>&1 and a platform diagnostic # could land in the middle of it. val() { awk -v k="$1" '$1==k { $1=""; sub(/^ /,""); print; exit }' "$pout"; } # want -- score one probe value against a derived answer. # A missing value is reported as the probe having stopped early rather than as a # mismatch against '', which is a different fault and localises to a different # line. want() { _got=$(val "$1") if [ -z "$_got" ]; then bst_notok "libxres/$2" "no value on target (probe stopped before $1); want='$3'" elif [ "$_got" = "$3" ]; then bst_ok "libxres/$2" else bst_notok "libxres/$2" "want:'$3' got:'$_got'" fi } # --- C: the census ------------------------------------------------------------ # Eleven is the whole of libXRes's public surface, and unlike libxvmc's it is # also every function the header declares. The floor is stated here as well as # in the bbappend because a .test cannot read a bitbake variable, and because # this is the half that catches a SHORT probe: every case below is grepped for # by ID, so a run that died halfway leaves its remaining cases simply absent. want C01 entry-points 11 want C02 entry-points-bound 1 # --- V: the constants the archive and the staged protocol headers agree on ---- # All confirmed on the reference build. V01..V16 are the extension's identity # and its request numbering; V17..V31 are the WIRE sizes, and those are the half # of "32-bit" that IS a risk here -- every one is fixed by the protocol and must # NOT move with the word size, unlike group A, whose sizes legitimately differ # per architecture. want V01 ext-name X-Resource want V02 proto-major "$WANT_PROTO_MAJOR" want V03 proto-minor "$WANT_PROTO_MINOR" want V04 req-query-version 0 want V05 req-query-clients 1 want V06 req-client-res 2 want V07 req-pixmap-bytes 3 want V08 req-client-ids 4 want V09 req-resource-bytes 5 want V10 id-type-xid 0 want V11 id-type-pid 1 want V12 id-type-nr 2 want V13 id-mask-xid 1 want V14 id-mask-pid 2 want V15 wire-mask-xid 1 want V16 wire-mask-pid 2 want V17 wire-sz-client 8 want V18 wire-sz-type 8 want V19 wire-sz-clientidspec 8 want V20 wire-sz-clientidvalue 12 want V21 wire-sz-resourceidspec 8 want V22 wire-sz-req-version 8 want V23 wire-sz-req-clients 4 want V24 wire-sz-req-pixmapbytes 8 want V25 wire-sz-req-clientids 8 want V26 wire-sz-req-resbytes 12 want V27 wire-sz-rep-pixmapbytes 32 want V28 wire-sz-rep-clientids 32 want V29 wire-sz-req-clientres 8 # The two the client side has a counterpart for, and they do not both agree with # it: the SizeSpec is 20 bytes on the wire and 20 in the client structure (A60), # while the SizeValue is 24 on the wire and 28 in the client structure (A70), # because the client one carries a pointer. A reader who took the first # agreement as a rule would be wrong about the second, which is why both are # here rather than only one. want V30 wire-sz-resourcesizespec 20 want V31 wire-sz-resourcesizevalue 24 # --- A: the client structure layout on this ILP32 arm ------------------------- # THE ONLY DERIVED GROUP. The reference run measured the LP64 layout; every # value below is exactly half its LP64 counterpart, except A05 (`unsigned int', # 4 on both). XID and Atom are `unsigned long', so they are 4 here and 8 there # -- which is why not one of the seven structures has the same size on this arm # as on the hosts these headers are normally read on, and why a value copied # from such a host would be wrong in a way nothing else here would catch. want A01 sizeof-xid 4 want A02 sizeof-atom 4 want A03 sizeof-long 4 want A04 sizeof-pointer 4 want A05 sizeof-uint 4 want A10 sizeof-client 8 want A11 off-client-base 0 want A12 off-client-mask 4 want A20 sizeof-type 8 want A21 off-type-restype 0 want A22 off-type-count 4 want A30 sizeof-idspec 8 want A31 off-idspec-client 0 want A32 off-idspec-mask 4 want A40 sizeof-idvalue 16 want A41 off-idvalue-spec 0 want A42 off-idvalue-length 8 want A43 off-idvalue-value 12 want A50 sizeof-residspec 8 want A51 off-residspec-res 0 want A52 off-residspec-type 4 want A60 sizeof-sizespec 20 want A61 off-sizespec-spec 0 want A62 off-sizespec-bytes 8 want A63 off-sizespec-ref 12 want A64 off-sizespec-use 16 want A70 sizeof-sizevalue 28 want A71 off-sizevalue-size 0 want A72 off-sizevalue-numxr 20 want A73 off-sizevalue-xrefs 24 # --- W: the arm X-Resource 1.2's 64-bit byte count takes here ----------------- # See the header. W01/W03 are what this arm is; W02 names the consequence. want W01 long-arm ilp32 want W02 pixmap-bytes-arm saturating want W03 sizeof-ulong 4 want W04 max-pixmap-bytes 4294967295 # The fold itself is behind the guard and is executed by nobody -- there is no # server to send a reply with bytes_overflow set. Recorded as a skip rather than # left unsaid, so that "X-Resource's 64-bit reply was not exercised" is a line in # the run instead of an absence a reader has to notice. bst_skip libxres/pixmap-bytes-fold "no X server on this image: XResQueryClientPixmapBytes returns at the guard, so the bytes/bytes_overflow fold (which saturates at 4 GiB - 1 on this ILP32 arm) is never reached" # --- P: the entry points that never touch a connection ------------------------ # Confirmed on the reference build. P00/P90 bracket the group with the Display's # lock count: nothing here takes a Display at all, so a lock in between would be # a fault nothing could explain. want P00 pure-locks-before 0 # assert(3) is live in this build -- NDEBUG is not defined. That is what makes # XResGetClientIdType's zero-mask case an abort(3) rather than a return of 0, and # it is why the probe does NOT call it that way: the value it is documented to # take comes from a reply, and aborting would cost the shared image a suite. # Stated as a measurement so the suite says which of the two behaviours this # image has rather than leaving a reader to infer it. want P01 assert-arm assert-live want P02 idtype-xid 0 want P03 idtype-pid 1 want P10 pid-from-value 4242 want P11 pid-wrong-mask -1 want P12 pid-short-value -1 want P20 destroy-ids-empty 1 want P21 destroy-ids-array 1 want P22 destroy-sizes-empty 1 want P23 destroy-sizes-array 1 want P90 pure-locks-after 0 want P91 pure-exterrors 0 # --- X: the guard, and the two ways it is reached ----------------------------- # Confirmed on the reference build. X01..X06: XResQueryExtension's own `else'. # It returns False, raises NOTHING (X02), and -- worth its own case -- leaves # BOTH out-parameters untouched, so the sentinel survives (X03/X04). X05/X06 are # the one extension query find_display made, by name. want X01 queryext-returns 0 want X02 queryext-no-exterr 0 want X03 queryext-ev-untouched -7 want X04 queryext-er-untouched -7 want X05 queryext-queries 1 want X06 queryext-query-name X-Resource # X10..X14: XResQueryVersion, the first of the six that go through # XextCheckExtension. It raises the missing-extension error (X11) naming the # extension (X12), returns 0 -- correct for a v1.0 Status -- and leaves its two # out-parameters untouched, which is NOT a defect here because 0 already means # failure for this call. want X10 version-returns 0 want X11 version-exterr 1 want X12 version-exterr-name X-Resource want X13 version-major-untouched -7 want X14 version-minor-untouched -7 # X20..X42: the other three v1.0 calls, which zero BOTH out-parameters ahead of # the guard. This is the shape the two v1.2 calls below do not have, and it is # scored here so the asymmetry is visible in the run rather than only in a # comment. want X20 clients-returns 0 want X21 clients-exterr 1 want X22 clients-count-zeroed 0 want X23 clients-array-nulled 1 want X30 clientres-returns 0 want X31 clientres-exterr 1 want X32 clientres-count-zeroed 0 want X33 clientres-array-nulled 1 want X40 pixmapbytes-returns 0 want X41 pixmapbytes-exterr 1 want X42 pixmapbytes-zeroed 0 # X50..X64: THE FINDING. See the header of this file. X51 and X61 assert that # the refusal is indistinguishable from `Success'; X54 and X64 assert that the # array out-parameter is left holding whatever the caller put there. All four # assert the BROKEN behaviour deliberately, and all four were reproduced on the # reference build -- so if upstream ever fixes the guard, these go red and this # comment is what to read. want X50 clientids-returns 0 want X51 clientids-reads-as-success 1 want X52 clientids-exterr 1 want X53 clientids-count-zeroed 0 want X54 clientids-array-untouched 1 want X60 resbytes-returns 0 want X61 resbytes-reads-as-success 1 want X62 resbytes-exterr 1 want X63 resbytes-count-zeroed 0 want X64 resbytes-array-untouched 1 # The NULL-Display case the ticket asks for is NOT called, and this is the # record of why rather than a value. find_display(NULL) reaches XextFindDisplay, # which walks the cache comparing `dpyinfo->display == dpy' -- safe -- and then # XextAddDisplay -> XInitExtension(NULL, ...) and XAddExtension(NULL), which # loads through the pointer. Xlib documents no behaviour for a NULL Display # anywhere, so there is no documented result to assert and the fault would be # the probe's, not the library's. bst_skip libxres/null-display "Xlib documents no behaviour for a NULL Display; libXRes's find_display path ends in XAddExtension(dpy), which dereferences it, so there is no documented result to assert" # --- I: what initialisation left on the Display ------------------------------- # Confirmed on the reference build. I01 is the cache being observed rather than # assumed: seven guarded calls, ONE extension query, because find_display caches # on extinfo->cur. I03..I05: XInitExtension came back NULL, so XextAddDisplay # takes its no-extension arm and hangs libXRes's close_display hook on a private # Xlib extension slot of its own. One family, one slot, one hook -- and a # library that silently stopped registering close_display would leak its # per-display cache at XCloseDisplay, which is where that would show. want I01 init-queries 1 want I02 init-query-order X-Resource want I03 init-ext-number 1 want I04 init-ext-slots 1 want I05 init-close-hooks 1 # --- L: the method itself, as numbers ----------------------------------------- # Confirmed on the reference build. TWO locks is the whole of it, and both are # libXext's rather than libXRes's: XAddExtension takes one and XESetCloseDisplay # the other, both on the no-extension arm and both AFTER the stub has answered # -- which is exactly the distinction the trap's answer-counting draws. Every # guarded call in group X returned before LockDisplay, which is the method's # limit stated as a number rather than as a claim. 57-libxtst measured six for # the same shape across two families plus XTestDiscard; two per family is the # figure this inherits. want L01 lock-queries 1 want L02 lock-query-order X-Resource want L03 lock-total 2 want L04 unlock-total 2 # The half an "it locked" assertion misses: nothing here leaks the lock. want L05 lock-balanced 1 want L06 exterr-total 6 want L07 exterr-last-name X-Resource rm -f "$pout"