. "$BST_LIB" # BST-TIMEOUT: 300 # one probe run plus ~180 shell extractions; the 60s default # is for suites that fork far less than this one does. # libXfixes 6.0.1 -- the XFIXES extension client library (poky recipes-graphics/ # xorg-lib). See libxfixes_%.bbappend for what the port adds and why. # # --------------------------------------------------------------------------- # ALMOST NONE OF THIS LIBRARY CAN REACH A SERVER HERE, AND THAT IS THE POINT # # libXfixes is the client half of XFIXES -- server-side regions, cursor # visibility and image access, selection-ownership notification, the save-set, # the pointer barriers, the client-disconnect mode. Nearly every entry point is # a round trip: XFixesFindDisplay(dpy), then a request on a wire. THIS IMAGE HAS # NO X SERVER, so no display opens (section 9) and not one of those requests can # complete -- not untested today, unreachable by construction. # # A shell suite is therefore left saying that an archive and a header arrived, # which is a statement about tar rather than about a cross compiler. So the port # builds the consumer libXfixes does not ship, and this suite drives what # genuinely stands alone: # # the client-side version XFixesVersion(), the one entry point with no Display # the extension list Xfixes.c's OWN cache, not extutil's # the honest-failure arm each family's documented no-extension path # the bases and constants the arithmetic every client does by hand # # WHY THE HONEST-FAILURE ARM IS THE SUBSTANTIVE SECTION, AND WHY IT IS SAFE. # # 57-libxext.test's probe refuses to pass an invented Display into an entry # point, and is right to: libXext's find_display misses, falls into # XextAddDisplay and dereferences. libXfixes is different in the one way that # matters. It keeps its own list -- `XFixesExtInfo XFixesExtensionInfo;', external # linkage, Xfixes.c -- and XFixesExtFindDisplay's fast path COMPARES the pointer # without loading through it. Seeded with a single entry whose codes are NULL, # XFixesFindDisplay returns on the cache hit and never reaches XInitExtension. # # Every entry point then runs its real prologue out of libXfixes.a and takes the # arm XFixesCheckExtension defines for a server without XFIXES -- which is the # state this image is permanently in. The arm DIFFERS PER FAMILY, so the answers # discriminate rather than collapsing to "nothing works": # # 0 the region creators, the barrier creator, XFixesQueryVersion, # XFixesGetClientDisconnectMode # NULL XFixesFetchRegion, XFixesFetchRegionAndBounds, XFixesGetCursorImage, # XFixesGetCursorName # void every operation -- measured by RETURNING AT ALL, which is not weak: # a build that stopped short-circuiting would run on into # LockDisplay(token) and fault # False XFixesQueryExtension, which asks XFixesHasExtension itself and leaves # both out-parameters untouched # # A regression that moved one family off its documented path names itself here. # # WHY THE EXPECTATIONS ARE WRITTEN OUT RATHER THAN DIFFED AGAINST x86-64. # 57-libxcb.test compares its probe against a build-host reference because its # question -- what a code generator emitted under cross -- has no absolute # answer. This one does. The sentinels are fixed by the library's own source, # the protocol constants are wire values fixed by the XFIXES specification, and # the event and error bases are arithmetic. Each case states what it expects and # why, so a red is readable without a second machine. # # THE SECTIONS # 1 the payload headers, archive, probe # 2 the .pc how a consumer finds any of it # 3 the probe runs, and to its end # 4 the client-side version XFixesVersion() out of the archive # 5 the extension list the seeded cache and its walk # 6 the honest-failure arm region, cursor, selection, barrier # 6b the major_version ladder the refusal an OLD server would give # 7 the protocol constants opcodes, save-set, region kinds, barriers # 8 the event and error bases what a client adds by hand # 9 the entry-point census every family linked out of the archive # 10 the display that is not there the documented no-server path # # A build where 7 passes and 6 does not has a fault in the archive rather than # in the headers -- 7 is compiled here, 6 came out of libXfixes.a. One where 9 # goes red has lost a whole family; the name in the red says which. 6b is the # only section that runs with the extension guard PASSING, and its own comment # says exactly why that is safe and where the limit of it is. # --------------------------------------------------------------------------- # A root prefix, empty on the target and set only when this suite is validated # NATIVELY under dash before it ships. The runner never sets it, so on the image # every path below is exactly the absolute one. R="${BST_LIBXFIXES_ROOT:-}" INC=$R/usr/include/X11/extensions LIB=$R/usr/lib PCD=$R/usr/lib/pkgconfig XT=$R/usr/libexec/libxfixes-tests work=${TMPDIR:-/tmp}/bst-libxfixes.$$ rm -rf "$work"; mkdir -p "$work" hasfile() { if [ -s "$2" ]; then bst_ok "$1"; else bst_notok "$1" "missing or empty: $2"; fi } # xf_line # # The prefix is matched with grep -F rather than the whole line, so a red reports # WHAT THE PROBE ACTUALLY SAID for that case instead of merely "absent". Every # prefix is unique by construction: each is a section tag plus a case name, and # the case name is followed by a space that ends it. xf_line() { _l=$(grep -m 1 -F -- "$2" "$work/out" 2>/dev/null) check_eq "$1" "$2$3" "$_l" } # --------------------------------------------------------------------------- # 0. THE CANARY, which is not an assertion about libXfixes at all. # # The guest console drops a suite's FIRST BST result line before the host parser # sees it -- brintos/linux#96. The harness computes its pass count as # total-minus-failures, so THE DROPPED LINE IS COUNTED AS A PASS, and a suite # whose first case is a genuine `not ok' loses the one line that mattered. So # the first line out of this file asserts something already true. # Remove this case when #96 is fixed. bst_ok libxfixes/suite-canary # --------------------------------------------------------------------------- # 1. THE PAYLOAD. # # libXfixes installs exactly one public header. That is not an oversight to work # around: XFIXES' wire definitions live in xorgproto (xfixeswire.h, # xfixesproto.h), and Xfixes.h includes the first of them, so the pair is what a # consumer actually compiles against and both are asserted here. check_rc libxfixes/dir-extensions 0 test -d "$INC" hasfile libxfixes/hdr-Xfixes "$INC/Xfixes.h" # xorgproto's, not this recipe's -- but Xfixes.h is unusable without it, and an # image carrying one and not the other fails a consumer's do_compile rather than # anything on this image. hasfile libxfixes/hdr-xfixeswire "$INC/xfixeswire.h" hasfile libxfixes/hdr-xfixesproto "$INC/xfixesproto.h" # The archive. This distro is static-only, so libXfixes.a is the whole delivery # and there must be no .so beside it -- one would mean the recipe had started # producing something nothing on this image can load. hasfile libxfixes/archive "$LIB/libXfixes.a" # Branched per arm, as 57-libxcb is: on the converted arm the same sentence reads # "whatever shared object shipped must be usable". if bst_ps_converted "$LIB/libXfixes.so" "$LIB/libXfixes.so.*"; then bst_lib_shape libxfixes/shared-usable "$LIB/libXfixes.so*" else check_rc libxfixes/no-shared 1 test -e "$LIB/libXfixes.so.3" fi hasfile libxfixes/probe-shipped "$XT/libxfixes-probe" # Asserted on contents rather than size: a truncated install would still be # non-empty. XFIXES_VERSION is the formula section 4 measures the archive # against, and XFixesVersion is the one prototype that takes no Display. check libxfixes/hdr-has-version-formula \ grep -q 'XFIXES_VERSION' "$INC/Xfixes.h" check libxfixes/hdr-has-xfixesversion \ grep -q 'XFixesVersion' "$INC/Xfixes.h" # --------------------------------------------------------------------------- # 2. THE .pc -- how a consumer finds any of the above. hasfile libxfixes/pc-present "$PCD/xfixes.pc" # THE .pc IS ASSERTED ON ITS CONTENTS FIRST, AND THROUGH pkg-config SECOND. # Read directly, these lines are true whatever else is installed; asked through # pkg-config they are true only if the packages xfixes.pc NAMES are also on the # image, which is a fact about the image rather than about this port. Both are # worth having, and separating them is what makes a red say which. # # `Requires: xproto fixesproto' -- both from xorgproto-dev, so this is the one # dependency edge that Yocto turns into an RDEPENDS on libxfixes-dev (poky's # oe.package.process_pkgconfig reads `Requires' and NOT `Requires.private'). check libxfixes/pc-requires-fixesproto \ grep -q '^Requires:.*fixesproto' "$PCD/xfixes.pc" check libxfixes/pc-requires-xproto \ grep -q '^Requires:.*xproto' "$PCD/xfixes.pc" # x11 is a PRIVATE require, and correctly so: a consumer of the shared library # would not need it, but this distro is static-only, so every consumer here does # -- libXfixes.a calls into Xlib for every request it encodes (XInitExtension, # _XReply, LockDisplay) and would not link without it. check libxfixes/pc-requires-private-x11 \ grep -q '^Requires\.private: *x11' "$PCD/xfixes.pc" check libxfixes/pc-libs-name grep -q '\-lXfixes' "$PCD/xfixes.pc" # NOT `require pkg-config'. require ENDS THE FILE when the tool is absent, and # everything this suite exists for comes after this section. Gating the probe on # a query tool would mean an image without pkg-config reported a clean skip for # the library it never exercised. So these cases skip individually and the file # runs on. if command -v pkg-config >/dev/null 2>&1; then bst_ok libxfixes/pkg-config-present # The graph queries below resolve xfixes.pc's requires, so they answer about # xorgproto-dev and libx11-dev as much as about this port. Gated on both being # present, and gated by NAME, so that an image missing one reports which -- # rather than reporting `xfixes.pc is broken', which it would not be. # # x11.pc used to be genuinely absent: core-image-brintos-emcraft removed # libx11 through BRINTOS_HOSTGLIBC_EXCLUDED. BRINTOS-1770 deleted that block, # so these cases now run rather than skip. The gate stays -- it is what keeps # a missing dependency from being reported as a fault in xfixes.pc. if [ -f "$PCD/fixesproto.pc" ] && [ -f "$PCD/x11.pc" ]; then bst_ok libxfixes/pc-deps-present check libxfixes/pc-exists pkg-config --exists xfixes check libxfixes/pc-validate pkg-config --validate xfixes check_eq libxfixes/pc-modversion 6.0.1 "$(pkg-config --modversion xfixes 2>/dev/null)" # PKG_CONFIG_ALLOW_SYSTEM_LIBS is required for the same reason # 57-xtrans.test records for its --cflags case: pkg-config SUPPRESSES a -L # naming a directory already on the linker's default path, so the bare query # answers usefully only for the -l part. Asked for the flags it COMPUTED, # the library name has to be there. check_out libxfixes/pc-libs -lXfixes \ env PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs xfixes else bst_skip libxfixes/pc-deps-present \ "xfixes.pc requires fixesproto and (privately) x11; one is missing on this image" fi else bst_skip libxfixes/pkg-config-present "pkg-config not installed on this image" fi # --------------------------------------------------------------------------- # 3. THE PROBE RUNS, AND RUNS TO ITS END. # # do_install ships it 0755, but the rootfs is read-only at browser runtime and # the exec bit is not reliably readable there either, so it is copied to /tmp -- # a mode=1777 tmpfs with no noexec -- and given the bit where the copy lands. probe=$work/libxfixes-probe if cp "$XT/libxfixes-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then "$probe" >"$work/out" 2>"$work/err" rc=$? # The probe exits 0 whatever it measures -- every expectation lives in this # file, not in the binary -- so a non-zero status here means it did not RUN: a # trap, a missing import, an exec refusal. On this arm that is a real and # common failure and is what this case is for. # # It is also the case that would catch the seeded-list section going wrong. # If XFixesCheckExtension had stopped short-circuiting, section 6 would run on # into LockDisplay(token) and fault, and the probe would die HERE rather than # reporting a wrong sentinel. if [ "$rc" -eq 0 ]; then bst_ok libxfixes/probe-runs else bst_notok libxfixes/probe-runs "rc=$rc $(_bst_1line "$(cat "$work/err")")"; fi total=$(sed -n 's/^XFIXES-TOTAL //p' "$work/out") if [ -n "$total" ]; then bst_ok libxfixes/probe-complete else bst_notok libxfixes/probe-complete \ "no XFIXES-TOTAL line: $(_bst_1line "$(cat "$work/out")")"; fi # The measurement count, bounded from below. Adding a fixture raises it; a # probe that got THINNER while still terminating cleanly is what this catches, # and nothing else here would -- every case below greps for what it expects, # so a line that stopped being printed is indistinguishable from one whose # grep simply found nothing. if [ -n "$total" ] && [ "$total" -ge 190 ]; then bst_ok libxfixes/probe-coverage else bst_notok libxfixes/probe-coverage \ "reported ${total:-0} measurements, expected not less than 190"; fi # The version the archive was built from, reported by the binary rather than # read off a path, so a stale probe left behind by an earlier build cannot # pass for this one. xf_line libxfixes/probe-version "XFIXES-VERSION " "6.0.1" # ------------------------------------------------------------------------- # 4. THE CLIENT-SIDE VERSION. # # XFixesVersion() is the only entry point in the library that takes no # Display, so it is the only one that can be called on this image with no # fixture at all -- and it is therefore the cleanest single statement that the # cross build produced a CALLABLE archive rather than merely a well-formed # one. It returns XFIXES_VERSION as compiled INTO libXfixes.a, so comparing it # with the header's own formula compares the archive with the sysroot: a # mismatch means the .a and the xorgproto here came from different places, and # nothing else in this suite would notice. xf_line libxfixes/ver-pv "XFIXES-VER pv " "6.0.1" xf_line libxfixes/ver-major "XFIXES-VER header-major " "6" xf_line libxfixes/ver-minor "XFIXES-VER header-minor " "0" xf_line libxfixes/ver-revision "XFIXES-VER header-revision " "1" # (XFIXES_MAJOR * 10000) + (XFIXES_MINOR * 100) + XFIXES_REVISION. xf_line libxfixes/ver-header "XFIXES-VER header-version " "60001" xf_line libxfixes/ver-lib "XFIXES-VER lib-version " "60001" xf_line libxfixes/ver-agree "XFIXES-VER agree " "yes" # ------------------------------------------------------------------------- # 5. THE EXTENSION LIST (Xfixes.c). # # libXfixes does NOT use extutil's list -- it keeps its own, because it has to # cache the negotiated version alongside the codes. The cache is one entry # (extinfo->cur) and a fault in it would surface only with two displays open, # which on this image is never, so it would ship silently and break the first # real X client. # # The Display* is an opaque token the probe never loads through; see the # probe's header for why that is legitimate for these paths and for nothing # else in libXfixes. xf_line libxfixes/list-ndisplays "XFIXES-LIST seeded-ndisplays " "1" # The fast path: extinfo->cur matches, so this returns WITHOUT reaching # XFixesExtAddDisplay -- which is what makes section 6 safe at all. xf_line libxfixes/list-find-cached "XFIXES-LIST find-cached " "seeded" # The walk, isolated by clearing the cache, and the re-promotion it must # perform. A build that ignored the cache would pass a plain repeated lookup # and fail nothing; a build that ignored the LIST would fail this. xf_line libxfixes/list-find-walk "XFIXES-LIST find-walk " "seeded" xf_line libxfixes/list-repromotes "XFIXES-LIST walk-repromotes " "seeded" # The guard every entry point branches on, false here because ->codes is NULL # -- which is exactly the state a server without XFIXES leaves the entry in, # and the state section 6 measures the consequences of. xf_line libxfixes/list-has-ext "XFIXES-LIST has-ext-seeded " "0" xf_line libxfixes/list-has-ext-null "XFIXES-LIST has-ext-null " "0" xf_line libxfixes/list-absent "XFIXES-LIST absent-in-list " "0" # -1/-1 is what XFixesExtAddDisplay leaves when the server has no XFIXES, and # what XFixesQueryVersion would hand a caller if the guard ever let it through. xf_line libxfixes/list-unknown-version \ "XFIXES-LIST unknown-version " "major=-1 minor=-1" # ------------------------------------------------------------------------- # 6. THE HONEST-FAILURE ARM -- THE SUBSTANTIVE SECTION. # # Every case below is a real call into libXfixes.a that reached its real # prologue and returned through the arm XFixesCheckExtension defines for a # server without XFIXES. Read the sentinels as a group: they are DIFFERENT per # family by design, and it is the difference that makes a regression legible. # # THESE ARE NOT "EXPECTED FAILURES". They are the library's documented # behaviour for the state this image is in, and a green here is a green. # --- negotiation --- # XFixesQueryExtension is the odd one: it does not use XFixesCheckExtension, # it asks XFixesHasExtension itself, returns False, and leaves BOTH # out-parameters untouched. A client reads them only when it returns True, so # a build that wrote into them on the false path would be corrupting a # caller's stack for no reason -- which the next two cases are what catch. xf_line libxfixes/fail-query-extension "XFIXES-FAIL query-extension " "0" xf_line libxfixes/fail-query-ext-untouched \ "XFIXES-FAIL query-extension-untouched " "ev=-1 err=-1" # Status, through XFixesCheckExtension(dpy, info, 0). xf_line libxfixes/fail-query-version "XFIXES-FAIL query-version " "0" xf_line libxfixes/fail-query-version-untouched \ "XFIXES-FAIL query-version-untouched " "major=-1 minor=-1" # --- region: the XserverRegion arm, sentinel 0 --- # 0 is None, and it is what every one of these hands back. A client that got a # non-zero XID here would go on to use a region the server never created. xf_line libxfixes/fail-create-region "XFIXES-FAIL create-region " "0" xf_line libxfixes/fail-create-region-empty "XFIXES-FAIL create-region-empty " "0" xf_line libxfixes/fail-region-bitmap "XFIXES-FAIL region-from-bitmap " "0" xf_line libxfixes/fail-region-window "XFIXES-FAIL region-from-window " "0" xf_line libxfixes/fail-region-gc "XFIXES-FAIL region-from-gc " "0" xf_line libxfixes/fail-region-picture "XFIXES-FAIL region-from-picture " "0" # --- region: the pointer arm, sentinel NULL --- # The count out-parameter is untouched for the same reason as above: the # caller reads it only when a non-NULL pointer comes back. xf_line libxfixes/fail-fetch-region "XFIXES-FAIL fetch-region " "NULL" xf_line libxfixes/fail-fetch-untouched "XFIXES-FAIL fetch-region-untouched " "-1" xf_line libxfixes/fail-fetch-bounds "XFIXES-FAIL fetch-region-bounds " "NULL" xf_line libxfixes/fail-fetch-bounds-untouched \ "XFIXES-FAIL fetch-region-bounds-untouched " "-1" # --- region: the void arm --- # `returned' IS the measurement, and it is not a weak one: each of these ends # at XFixesSimpleCheckExtension, and a build in which that had stopped # short-circuiting would carry on into LockDisplay(token) and fault. Reaching # the next line is the evidence the documented path was taken. for c in destroy-region set-region copy-region union-region intersect-region \ subtract-region invert-region translate-region region-extents \ expand-region set-gc-clip set-window-shape set-picture-clip; do xf_line "libxfixes/fail-$c" "XFIXES-FAIL $c " "returned" done # --- cursor --- xf_line libxfixes/fail-cursor-image "XFIXES-FAIL get-cursor-image " "NULL" xf_line libxfixes/fail-cursor-name "XFIXES-FAIL get-cursor-name " "NULL" xf_line libxfixes/fail-cursor-name-untouched \ "XFIXES-FAIL get-cursor-name-untouched " "0" for c in select-cursor-input set-cursor-name change-cursor \ change-cursor-by-name hide-cursor show-cursor; do xf_line "libxfixes/fail-$c" "XFIXES-FAIL $c " "returned" done # --- selection --- # The one entry point in Selection.c, called with all three notify masks set, # so the mask argument is the full documented set rather than a single bit. xf_line libxfixes/fail-select-selection-input \ "XFIXES-FAIL select-selection-input " "returned" # --- save set --- xf_line libxfixes/fail-change-save-set "XFIXES-FAIL change-save-set " "returned" # --- barrier --- # PointerBarrier is an XID like XserverRegion, so its sentinel is 0 too -- but # it comes from a DIFFERENT source file and a different version block # (XFIXES 5), which is why it is asserted separately rather than folded in # with the region creators. xf_line libxfixes/fail-create-barrier "XFIXES-FAIL create-barrier " "0" xf_line libxfixes/fail-destroy-barrier "XFIXES-FAIL destroy-barrier " "returned" # --- client disconnect mode (XFIXES 6) --- xf_line libxfixes/fail-get-disconnect "XFIXES-FAIL get-disconnect-mode " "0" xf_line libxfixes/fail-set-disconnect "XFIXES-FAIL set-disconnect-mode " "returned" # Nothing above may have mutated the list: every call returned at the guard, # BEFORE the add/cache bookkeeping. A build that walked past the guard would # have grown the list, and this is the single case that says so for all of # them at once. xf_line libxfixes/fail-list-unchanged "XFIXES-FAIL list-unchanged " "yes" # ------------------------------------------------------------------------- # 6b. THE SECOND GATE: THE major_version LADDER. # # Section 6 measured the arm taken when the server has no XFIXES at all # (codes == NULL). Behind it sits the refusal a client on a REAL but OLD # server meets: ten entry points added after XFIXES 1 re-check the version the # negotiation cached and return early if the server is too old -- # < 2 for the four cursor-naming calls, < 4 for Hide/ShowCursor, < 5 for the # barriers, < 6 for the client-disconnect pair. # # Reaching it needs codes NON-NULL so that XFixesCheckExtension passes, and # that makes this the delicate section. Every one of those gates returns # BEFORE LockDisplay -- verified against the 6.0.1 source, Cursor.c 155-341 # and Disconnect.c 52-90 -- but an entry point whose gate does NOT fire runs # on into LockDisplay() on the token and faults. So the probe calls, at each # version, only the entry points whose threshold is above it, and drops each # one as its gate opens. XFixesGetCursorImage is never called here at all: it # LOCKS BEFORE its own version check, so no version of it is safe. # # A gate compiled away would not change a return value -- it would send the # call to the wire. That is why the `returned' answers here are load-bearing. # The precondition, asserted rather than assumed: with codes set, the guard # section 6 measured as false is now true. xf_line libxfixes/ladder-has-ext "XFIXES-LADDER has-ext-with-codes " "1" # The other half of section 6's untouched-out-parameter pair. This is the ONLY # place XFixesQueryExtension returns True, and it must hand back exactly the # bases the seeded codes carry -- which is what a client keys every event and # error comparison off. xf_line libxfixes/ladder-query-ext "XFIXES-LADDER query-extension " "1" xf_line libxfixes/ladder-query-ext-bases \ "XFIXES-LADDER query-extension-bases " "ev=64 err=128" # XFixesQueryVersion likewise: Status 1, and the cached pair reported. xf_line libxfixes/ladder-query-version "XFIXES-LADDER query-version " "1" xf_line libxfixes/ladder-query-version-reported \ "XFIXES-LADDER query-version-reported " "major=1 minor=0" # At version 1 every gated call is gated. The four cursor-naming calls, the # two visibility calls, the barrier pair and the disconnect pair. for c in set-cursor-name change-cursor change-cursor-by-name hide-cursor \ show-cursor destroy-barrier set-disconnect; do xf_line "libxfixes/ladder-v1-$c" "XFIXES-LADDER v1-$c " "returned" done xf_line libxfixes/ladder-v1-get-cursor-name "XFIXES-LADDER v1-get-cursor-name " "NULL" xf_line libxfixes/ladder-v1-create-barrier "XFIXES-LADDER v1-create-barrier " "0" # XFixesClientDisconnectFlagDefault, which is what the gate returns by name. xf_line libxfixes/ladder-v1-get-disconnect "XFIXES-LADDER v1-get-disconnect " "0" # At version 3 the < 2 gates have OPENED, so the four naming calls are dropped # -- calling one here would reach the wire. What is asserted is what is still # gated, and the drop itself is the assertion the absence of those cases makes. xf_line libxfixes/ladder-v3-hide-cursor "XFIXES-LADDER v3-hide-cursor " "returned" xf_line libxfixes/ladder-v3-show-cursor "XFIXES-LADDER v3-show-cursor " "returned" xf_line libxfixes/ladder-v3-create-barrier "XFIXES-LADDER v3-create-barrier " "0" xf_line libxfixes/ladder-v3-destroy-barrier "XFIXES-LADDER v3-destroy-barrier " "returned" xf_line libxfixes/ladder-v3-get-disconnect "XFIXES-LADDER v3-get-disconnect " "0" # At version 4 cursor visibility has opened; the barriers and the XFIXES 6 # pair remain. xf_line libxfixes/ladder-v4-create-barrier "XFIXES-LADDER v4-create-barrier " "0" xf_line libxfixes/ladder-v4-destroy-barrier "XFIXES-LADDER v4-destroy-barrier " "returned" xf_line libxfixes/ladder-v4-get-disconnect "XFIXES-LADDER v4-get-disconnect " "0" xf_line libxfixes/ladder-v4-set-disconnect "XFIXES-LADDER v4-set-disconnect " "returned" # At version 5 only the XFIXES 6 pair is still gated. This is the narrowest # rung and the one that would go red first if the disconnect-mode gate were # ever written as `<= 6' or dropped. xf_line libxfixes/ladder-v5-get-disconnect "XFIXES-LADDER v5-get-disconnect " "0" xf_line libxfixes/ladder-v5-set-disconnect "XFIXES-LADDER v5-set-disconnect " "returned" # NOTHING IS CALLED AT VERSION 6, and the probe says so in a case of its own so # that a later edit "completing the ladder" is a change to this file rather # than a crash. Every gate is open at 6; every one of these calls would reach # LockDisplay() on the token. xf_line libxfixes/ladder-v6 "XFIXES-LADDER v6-not-exercised " "by-design" # The list is put back to the codes == NULL state section 6 depends on, so the # two sections cannot interfere whichever order a future edit runs them in. xf_line libxfixes/ladder-restored "XFIXES-LADDER restored " "0" # ------------------------------------------------------------------------- # 7. THE PROTOCOL CONSTANTS. # # Wire values: a client that disagrees with the server about # WindowRegionBounding does not fail to build, it shapes the wrong window. # They are architecture-independent by definition, so each is stated here from # the XFIXES protocol specification rather than diffed against a build host -- # there is nothing about a second machine that could make an answer here more # true. xf_line libxfixes/const-name "XFIXES-CONST XFIXES_NAME " "XFIXES" xf_line libxfixes/const-major "XFIXES-CONST XFIXES_MAJOR " "6" xf_line libxfixes/const-minor "XFIXES-CONST XFIXES_MINOR " "0" # The request opcodes. A shifted opcode is the single most destructive thing # that can go wrong on this wire -- it does not fail, it does the wrong # operation -- so one is asserted per version block, at both ends of each. xf_line libxfixes/req-query-version "XFIXES-CONST req-QueryVersion " "0" xf_line libxfixes/req-change-save-set "XFIXES-CONST req-ChangeSaveSet " "1" xf_line libxfixes/req-select-sel "XFIXES-CONST req-SelectSelectionInput " "2" xf_line libxfixes/req-select-cursor "XFIXES-CONST req-SelectCursorInput " "3" xf_line libxfixes/req-get-cursor-img "XFIXES-CONST req-GetCursorImage " "4" xf_line libxfixes/req-create-region "XFIXES-CONST req-CreateRegion " "5" xf_line libxfixes/req-destroy-region "XFIXES-CONST req-DestroyRegion " "10" xf_line libxfixes/req-fetch-region "XFIXES-CONST req-FetchRegion " "19" xf_line libxfixes/req-change-cur-name "XFIXES-CONST req-ChangeCursorByName " "27" xf_line libxfixes/req-expand-region "XFIXES-CONST req-ExpandRegion " "28" xf_line libxfixes/req-hide-cursor "XFIXES-CONST req-HideCursor " "29" xf_line libxfixes/req-show-cursor "XFIXES-CONST req-ShowCursor " "30" xf_line libxfixes/req-create-barrier "XFIXES-CONST req-CreatePointerBarrier " "31" xf_line libxfixes/req-destroy-barrier "XFIXES-CONST req-DestroyPointerBarrier " "32" xf_line libxfixes/req-set-disconnect "XFIXES-CONST req-SetClientDisconnectMode " "33" xf_line libxfixes/req-get-disconnect "XFIXES-CONST req-GetClientDisconnectMode " "34" # The count, which is what a server bounds its dispatch table by. It is # (X_XFixesGetClientDisconnectMode + 1), so it moves only when the protocol # gains a request -- and if it ever does, this red is the notice. xf_line libxfixes/const-nrequests "XFIXES-CONST NumberRequests " "35" # Save-set. Nearest/Root select the target and Map/Unmap the mode, and the two # pairs are separate enumerations that happen to share their values -- which is # exactly why a client that crossed them would not fail visibly. xf_line libxfixes/const-saveset-nearest "XFIXES-CONST SaveSetNearest " "0" xf_line libxfixes/const-saveset-root "XFIXES-CONST SaveSetRoot " "1" xf_line libxfixes/const-saveset-map "XFIXES-CONST SaveSetMap " "0" xf_line libxfixes/const-saveset-unmap "XFIXES-CONST SaveSetUnmap " "1" # Region kinds, the `kind' argument to XFixesCreateRegionFromWindow. xf_line libxfixes/const-region-bounding "XFIXES-CONST WindowRegionBounding " "0" xf_line libxfixes/const-region-clip "XFIXES-CONST WindowRegionClip " "1" # Barrier directions -- a bitfield, and the one place in XFIXES where the # client does a shift. Asserted as the four powers of two they are. xf_line libxfixes/const-barrier-px "XFIXES-CONST BarrierPositiveX " "1" xf_line libxfixes/const-barrier-py "XFIXES-CONST BarrierPositiveY " "2" xf_line libxfixes/const-barrier-nx "XFIXES-CONST BarrierNegativeX " "4" xf_line libxfixes/const-barrier-ny "XFIXES-CONST BarrierNegativeY " "8" # Client-disconnect flags. ForceTerminate arrived in XFIXES 6.1 and is the # newest thing in this header, so it is the case that would go red first if # the sysroot's xorgproto were rolled back under this recipe. xf_line libxfixes/const-disc-default "XFIXES-CONST DisconnectDefault " "0" xf_line libxfixes/const-disc-term "XFIXES-CONST DisconnectTerminate " "1" xf_line libxfixes/const-disc-force "XFIXES-CONST DisconnectForceTerminate " "2" # ------------------------------------------------------------------------- # 8. THE EVENT AND ERROR BASES. # # XFIXES numbers its events and errors RELATIVE to a base the server hands # back through XFixesQueryExtension, and every client does the addition by # hand: # # if (ev->type == event_base + XFixesSelectionNotify) ... # if (err->error_code == error_base + BadRegion) ... # # Nothing in the library performs that addition, so nothing in the library can # get it wrong -- but the CONSTANTS it is done with are what this port ships, # and one of them wrong sends a client to the wrong branch on every event it # receives. Section 6 established that no base can be obtained on this image; # this section is what the port still owes a consumer regardless. xf_line libxfixes/base-selection-notify "XFIXES-BASE SelectionNotify " "0" xf_line libxfixes/base-cursor-notify "XFIXES-BASE CursorNotify " "1" xf_line libxfixes/base-nevents "XFIXES-BASE NumberEvents " "2" # The selection subtypes, which share one event number and are distinguished # by the `subtype' field -- so these three are not event codes and adding a # base to one would be the bug. xf_line libxfixes/base-sub-owner "XFIXES-BASE SetSelectionOwnerNotify " "0" xf_line libxfixes/base-sub-destroy "XFIXES-BASE SelectionWindowDestroyNotify " "1" xf_line libxfixes/base-sub-close "XFIXES-BASE SelectionClientCloseNotify " "2" xf_line libxfixes/base-sub-cursor "XFIXES-BASE DisplayCursorNotify " "0" xf_line libxfixes/base-mask-owner "XFIXES-BASE SetSelectionOwnerNotifyMask " "1" xf_line libxfixes/base-mask-destroy "XFIXES-BASE SelectionWindowDestroyNotifyMask " "2" xf_line libxfixes/base-mask-close "XFIXES-BASE SelectionClientCloseNotifyMask " "4" xf_line libxfixes/base-mask-cursor "XFIXES-BASE DisplayCursorNotifyMask " "1" # The masks are DEFINED as (1L << subtype), so each pair above is one fact # stated twice. These four are what notice a header edit that broke the # correspondence while leaving both numbers individually plausible -- which no # amount of checking the numbers alone could see. xf_line libxfixes/base-shift-owner "XFIXES-BASE mask-shift-owner " "1" xf_line libxfixes/base-shift-destroy "XFIXES-BASE mask-shift-destroy " "1" xf_line libxfixes/base-shift-close "XFIXES-BASE mask-shift-close " "1" xf_line libxfixes/base-shift-cursor "XFIXES-BASE mask-shift-cursor " "1" xf_line libxfixes/base-bad-region "XFIXES-BASE BadRegion " "0" xf_line libxfixes/base-bad-barrier "XFIXES-BASE BadBarrier " "1" xf_line libxfixes/base-nerrors "XFIXES-BASE NumberErrors " "2" # The addition itself, at a base a stock server would plausibly hand back. The # value 64 is arbitrary; what these assert is that the two events stay one # apart and inside the [base, base + XFixesNumberEvents) window that Xfixes.c # registers XESetWireToEvent over -- a window that is wrong by one if # XFixesNumberEvents ever disagrees with the event codes. xf_line libxfixes/base-ev-selection "XFIXES-BASE ev-selection-at-64 " "64" xf_line libxfixes/base-ev-cursor "XFIXES-BASE ev-cursor-at-64 " "65" xf_line libxfixes/base-ev-end "XFIXES-BASE ev-window-end-at-64 " "66" xf_line libxfixes/base-err-region "XFIXES-BASE err-region-at-128 " "128" xf_line libxfixes/base-err-barrier "XFIXES-BASE err-barrier-at-128 " "129" # THE STRUCT SIZES ARE THIS ARM'S, AND THAT IS THE POINT. # # Every member of both event structs is a 4-byte scalar on ILP32 -- int, Bool, # a pointer, and the XID/Atom/Time family, all `unsigned long' here -- so the # layouts are 10 and 9 members flat. On the LP64 build host they would be 80 # and 72. These cases exist to catch a struct that changed SHAPE, and they are # stated as the target's answers because that is the only machine whose answer # matters to a client running here. xf_line libxfixes/size-selection-event "XFIXES-BASE sizeof-selection-event " "40" xf_line libxfixes/size-cursor-event "XFIXES-BASE sizeof-cursor-event " "36" xf_line libxfixes/size-cursor-image "XFIXES-BASE sizeof-cursor-image " "28" # XserverRegion and PointerBarrier are both XID, so both are 4 here -- and # being EQUAL is the part that is architecture-independent. A build where they # differed would have redefined one of them. xf_line libxfixes/size-region "XFIXES-BASE sizeof-region " "4" xf_line libxfixes/size-barrier "XFIXES-BASE sizeof-barrier " "4" # Both events must fit in an XEvent, which is what XNextEvent writes through. # A client that received one into a short buffer would be corrupting its own # stack, and nothing else here would say so. xf_line libxfixes/fits-selection "XFIXES-BASE selection-fits-xevent " "1" xf_line libxfixes/fits-cursor "XFIXES-BASE cursor-fits-xevent " "1" # ------------------------------------------------------------------------- # 9. THE ENTRY-POINT CENSUS. # # Section 10 establishes that no display opens here, which makes the # round-trip half of the API unreachable -- so the only thing left to say # about it is that it EXISTS: that the cross build compiled each module, that # the static linker resolved each name out of libXfixes.a, and that the # address is in the shipped image. Taking the address is what forces the # archive member in, so a module the build had silently dropped fails the LINK # in do_compile, naming the symbol that went missing. # # Checked here by COUNT and by a sample of names: the count is what notices a # module leaving, and the recipe's own LIBXFIXES_MIN_ENTRY_POINTS floor is what # notices the probe's table shrinking to match. The named ones below are one # per SOURCE FILE -- the census is only as good as its coverage of modules, # and a count alone cannot say that Region.c and Cursor.c are both still in it. nsym=$(sed -n 's/^XFIXES-SYM-COUNT //p' "$work/out") if [ -n "$nsym" ] && [ "$nsym" -ge 38 ]; then bst_ok libxfixes/sym-count else bst_notok libxfixes/sym-count \ "census names ${nsym:-0} entry points, expected not less than 38"; fi xf_line libxfixes/sym-none-null "XFIXES-SYM-NULL " "0" # One per module, plus the version-block boundaries. A red here says which # family left, which a count cannot. for s in XFixesQueryExtension XFixesVersion XFixesFindDisplay \ XFixesChangeSaveSet XFixesSelectSelectionInput \ XFixesGetCursorImage XFixesShowCursor \ XFixesCreatePointerBarrier XFixesCreateRegion \ XFixesFetchRegionAndBounds XFixesExpandRegion \ XFixesGetClientDisconnectMode; do xf_line "libxfixes/sym-$s" "XFIXES-SYM $s " "linked" done # ------------------------------------------------------------------------- # 10. THE DISPLAY THAT IS NOT THERE. # # The documented no-server path, and the reason section 6 had to seed the list # to say anything at all: libXfixes' API begins at a Display, Xlib is the only # thing that makes one, and on this image it cannot. # # What must hold is that XOpenDisplay SAYS so -- NULL, for each spelling -- # rather than crashing, blocking, or handing back a half-built Display that # the first XFixesQueryVersion would then walk into. The last case is what # distinguishes a clean refusal from a hang: the probe reached its end. # # Note what is NOT here. No entry point is called with a NULL Display: that # would miss the seeded cache, fall into XFixesExtAddDisplay and dereference, # which is undefined behaviour rather than a documented failure -- and a probe # that crashed there would be reporting its own mistake. xf_line libxfixes/dpy-no-env "XFIXES-DPY no-env " "NULL" xf_line libxfixes/dpy-unix-0 "XFIXES-DPY unix-0 " "NULL" xf_line libxfixes/dpy-unix-99 "XFIXES-DPY unix-99 " "NULL" xf_line libxfixes/dpy-tcp "XFIXES-DPY tcp " "NULL" xf_line libxfixes/dpy-end "XFIXES-DPY reached-end " "yes" else bst_notok libxfixes/probe-stage "cannot stage $XT/libxfixes-probe" fi rm -rf "$work"