. "$BST_LIB" # BST-TIMEOUT: 300 # One probe run plus ~130 shell extractions. Same shape and # the same figure as 57-libxfixes.test and # 57-libxcomposite.test. # libXdamage 1.1.6 -- the client half of the DAMAGE extension (poky # recipes-graphics/xorg-lib). See libxdamage_%.bbappend for what the port adds. # # --------------------------------------------------------------------------- # WHAT IS MEASURED HERE, AND -- FIRST -- WHAT IS NOT CLAIMED # # THIS SUITE DOES NOT EXERCISE DAMAGE ACCUMULATION, AND CANNOT. DAMAGE exists to # tell a client which rectangles of a drawable changed; all six entry points # take a Display, this image has no X server, so no display opens and not one of # them can complete here -- ever, not merely today. A reader looking for "the # library reported a damaged rectangle" will not find it, and should not: it is # not a gap in the port, it is what a server-less image permits. # # This library is also POORER IN DISPLAY-FREE SURFACE than the two siblings it # is modelled on. libXfixes has XFixesVersion() and libXcomposite # XCompositeVersion(), each returning the protocol version compiled INTO the # archive, so each can cross-check the archive against the sysroot's headers. # libXdamage has no such entry point at all. That cross-check is therefore # unavailable here and no substitute is invented for it; what stands in its # place is the one data symbol, XDamageExtensionName. # # What is asserted instead: # # the ARTEFACTS the archive, the header and the pkg-config file, which # are the practical value of this package: gtk+3 and any # compositor read all three. # # the WIRE NAME XDamageExtensionName out of the archive's read-only # data, against DAMAGE_NAME from the headers. # # the HONEST-FAILURE each entry point's DOCUMENTED no-extension return, # ARM with a DIFFERENT sentinel per kind so the answers # discriminate rather than reading as a uniform # "nothing works". This is the ticket's "assert the # documented refusal", measured. # # the NEGOTIATED ARM the other side of the same branch, for the exactly two # entry points that still return before the wire once # the extension is present. Without it, a guard that # always returned the failure sentinel would be green # above for the wrong reason. # # the EVENT UNION the ticket's headline risk: XDamageNotifyEvent is one # of the packed, extension-numbered XEvent members, the # library writes through a pointer the application # supplied, and getting the layout wrong is SILENT. Size, # every member offset, and -- the invariant that keeps an # event queue from being overrun -- that it is no larger # than XEvent. # # the WIRE the protocol constants and the request/reply struct # sizes this ILP32 arm computes. A client that disagrees # with the server here does not fail to build; it sends # the wrong bytes. # # the SYMBOL SET all seven linkable names, against the committed list # below. A build that silently dropped part of the API # fails here rather than at the first consumer's link. # # --------------------------------------------------------------------------- # HOW THE FAILURE ARM IS REACHED WITHOUT UNDEFINED BEHAVIOUR # # Passing a NULL or invented Display straight into an entry point is undefined # behaviour, not a documented failure: XDamageFindDisplay misses the cache, # falls into XDamageExtAddDisplay, and that calls XInitExtension(dpy, ...), # which dereferences (src/Xdamage.c:58). A probe that crashed there would be # reporting on its own mistake. 57-libxext.test's probe declines to go near it # for exactly this reason. # # libXdamage keeps its OWN extension list rather than using extutil's, and # declares it with external linkage -- `XDamageExtInfo XDamageExtensionInfo;' # (src/Xdamage.c:30, extern at src/xdamageint.h:48) -- while # XDamageExtFindDisplay's fast path is a COMPARISON of the Display pointer and # never a load through it (src/Xdamage.c:176). So the probe seeds that global # with one entry whose display is a token address and whose codes are NULL, and # every entry point then runs its real prologue out of libXdamage.a and takes # the arm XDamageCheckExtension defines. Same mechanism as 57-libxfixes.test and # 57-libxcomposite.test; see the probe source for why it is legitimate for these # paths and nothing else. # # --------------------------------------------------------------------------- # NOTHING HERE HAD RUN ON A TARGET WHEN IT WAS WRITTEN, BUT IT IS NOT GUESSWORK # # Every expectation below was MEASURED on 2026-09-12 by a reference run of this # exact probe source, compiled against upstream's own src/Xdamage.c -- the # 1.1.6 tarball whose sha256 matches poky's SRC_URI[sha256sum] -- on x86-64 and # run with no DISPLAY. Ninety-eight lines, exit 0. # # THE REFERENCE HOST DISAGREES WITH THE TARGET IN EXACTLY TWO PLACES, AND BOTH # ARE DELIBERATE HERE: # # 1. WORD SIZE. sizeof-Damage, sizeof-Drawable and sizeof-XserverRegion are XID # widths and the event layout is built out of them, so the LP64 reference # answered 8 / 80 and this ILP32 arm answers 4 / 52. The target's numbers # are asserted, deliberately: these cases exist to catch a typedef that # changed shape on this arm, not to compare architectures. # # 2. THE REFERENCE HOST HAS AN X SERVER. Its `unix-0' fixture OPENED a display; # the target's must not. That is a property of the workstation the reference # ran on, not of the library, and it is the one line of the reference output # this suite must not copy. NULL is asserted for all four spellings. # # --------------------------------------------------------------------------- # NOTHING IS ASSERTED ABOUT A SHARED OBJECT, IN EITHER DIRECTION # # libxdamage was off brintos.conf's allow-list (BRINTOS-2727 retired it), so on the # arm shipping today FILES:${PN} (${libdir}/libXdamage.so.*) matches nothing and # the main package is never emitted. Asserting the .so absent would go red the # day libxdamage is allow-listed, and asserting it present is false today; both # make the suite arm-dependent for a fact that is a property of the build # configuration rather than of the port. So neither is asserted, and # libXdamage.a is the artefact this suite is about. Same reading, and the same # reason, as BRINTOS-2375 established for libsombok3, libotr and libevent, and # BRINTOS-2333, -2334, -2335 and -2337 applied for libxpm, libxkbfile, # libxcursor and libxcomposite. PROBE=${BST_LIBXDAMAGE_PROBE:-/usr/libexec/libxdamage-tests/libxdamage-probe} ARCHIVE=/usr/lib/libXdamage.a PCFILE=/usr/lib/pkgconfig/xdamage.pc INCDIR=/usr/include/X11/extensions tmp=${TMPDIR:-/tmp} out=$tmp/bst-libxdamage-probe.$$.out # The first BST result line of a suite is dropped by the guest console, so the # suite opens with one that costs nothing to lose. bst_ok libxdamage/suite-begin # --------------------------------------------------------------------------- # THE ARTEFACTS # --------------------------------------------------------------------------- if [ -f "$ARCHIVE" ]; then bst_ok libxdamage/archive-present else bst_notok libxdamage/archive-present "$ARCHIVE missing" fi if [ -s "$ARCHIVE" ]; then bst_ok libxdamage/archive-nonempty else bst_notok libxdamage/archive-nonempty "$ARCHIVE empty" fi if [ -f "$INCDIR/Xdamage.h" ]; then bst_ok libxdamage/header-Xdamage.h else bst_notok libxdamage/header-Xdamage.h "$INCDIR/Xdamage.h missing" fi # The header must declare the API, not merely exist -- a truncated or wrong # install would satisfy the check above. XDamageQueryExtension is the one # prototype unique to this header and to no dependency's. if grep -q "XDamageQueryExtension" "$INCDIR/Xdamage.h" 2>/dev/null; then bst_ok libxdamage/header-declares-api else bst_notok libxdamage/header-declares-api "no XDamageQueryExtension prototype in $INCDIR/Xdamage.h" fi # The event structure is declared in this header and nowhere else, and it is # what section EVENT below is about. A header that installed without it would # leave every consumer unable to dispatch the one event DAMAGE has. if grep -q "XDamageNotifyEvent" "$INCDIR/Xdamage.h" 2>/dev/null; then bst_ok libxdamage/header-declares-event else bst_notok libxdamage/header-declares-event "no XDamageNotifyEvent in $INCDIR/Xdamage.h" fi if [ -f "$PCFILE" ]; then bst_ok libxdamage/pkgconfig-present else bst_notok libxdamage/pkgconfig-present "$PCFILE missing" fi if grep -q "^Name: *Xdamage" "$PCFILE" 2>/dev/null; then bst_ok libxdamage/pkgconfig-names-xdamage else bst_notok libxdamage/pkgconfig-names-xdamage "no 'Name: Xdamage' in $PCFILE" fi if grep -q "^Version: *1\.1\.6" "$PCFILE" 2>/dev/null; then bst_ok libxdamage/pkgconfig-version-1.1.6 else bst_notok libxdamage/pkgconfig-version-1.1.6 "$(grep '^Version:' "$PCFILE" 2>/dev/null)" fi # The two lines a consumer's build actually consumes. A .pc that lost either is # a package that cannot be linked against however complete its files are. if grep -q '^Cflags: *-I\${includedir}' "$PCFILE" 2>/dev/null; then bst_ok libxdamage/pkgconfig-cflags else bst_notok libxdamage/pkgconfig-cflags "$(grep '^Cflags:' "$PCFILE" 2>/dev/null)" fi if grep -q '^Libs: *-L\${libdir} *-lXdamage' "$PCFILE" 2>/dev/null; then bst_ok libxdamage/pkgconfig-libs else bst_notok libxdamage/pkgconfig-libs "$(grep '^Libs:' "$PCFILE" 2>/dev/null)" fi # Requires is the public closure a consumer inherits; Requires.private is what # the bbappend's link closure is spelled out FROM. The recipe deliberately does # NOT link libXfixes -- Xdamage.c uses it for the XserverRegion typedef only -- # so this case is also the pin on the assumption behind that omission. The # version on damageproto is configure.ac's DAMAGEEXT_VERSION, the first two # components of 1.1.6. if grep -q "^Requires: *xproto damageproto >= 1\.1 xfixes" "$PCFILE" 2>/dev/null; then bst_ok libxdamage/pkgconfig-requires else bst_notok libxdamage/pkgconfig-requires "$(grep '^Requires:' "$PCFILE" 2>/dev/null)" fi if grep -q "^Requires.private: *x11 xfixes" "$PCFILE" 2>/dev/null; then bst_ok libxdamage/pkgconfig-requires-private else bst_notok libxdamage/pkgconfig-requires-private "$(grep '^Requires.private:' "$PCFILE" 2>/dev/null)" fi # --------------------------------------------------------------------------- # THE PROBE # --------------------------------------------------------------------------- if [ -x "$PROBE" ]; then bst_ok libxdamage/probe-present else bst_notok libxdamage/probe-present "$PROBE missing or not executable" fi "$PROBE" > "$out" 2>&1 prc=$? if [ "$prc" -eq 0 ]; then bst_ok libxdamage/probe-exit-0 else bst_notok libxdamage/probe-exit-0 "exit $prc -- the probe did not finish, so every CASE below is unscorable" fi # The END line is the probe's own statement that it did not die part way. Every # case below reads $out, so without it they would all be reading a truncated # file and reporting the absence of a value as a wrong value. It is also the # ticket's no-crash and no-hang clause: a probe that faulted in an entry point, # or that blocked in a connect, never gets here, and BST-TIMEOUT above is the # wall-clock bound on the second of those. # # `unscorable' here and in probe-exit-0 above is PARSED, not prose: # brintos_local_verify.py matches the bare word in a failing case's message and # re-measures this suite alone on a fresh guest rather than counting the ~110 # reds below against the port (BRINTOS-1644). Either check alone collapses the # evidence plane, so both carry it. if grep -q '^XDAMAGE-PROBE-END$' "$out"; then bst_ok libxdamage/probe-reached-end else bst_notok libxdamage/probe-reached-end "no END line; probe died, so its output is truncated and every CASE below is unscorable. tail: $(tail -3 "$out" | tr '\n' ' ')" fi # field -- nth whitespace field of the line starting with TAG field() { awk -v t="$1" -v n="$2" '$1==t {print $(n); exit}' "$out"; } expect() { # expect _got=$(field "$2" "$3") if [ "$_got" = "$4" ]; then bst_ok "$1" else bst_notok "$1" "want '$4', got '$_got'" fi } # expect() takes the FIRST line matching the tag, which is right only where the # tag appears once. Most of the probe's output is tag-plus-key, so those are # read by their key instead; a case written with expect() against a repeated tag # would silently assert the first line's value under a second line's name. keyed() { # keyed _got=$(awk -v t="$2" -v k="$3" -v n="$4" '$1==t && $2==k {print $(n); exit}' "$out") if [ "$_got" = "$5" ]; then bst_ok "$1" else bst_notok "$1" "want '$5', got '$_got'" fi } # The line count, as a FLOOR. Every case below is grepped for by prefix, so a # run that died halfway leaves its remaining cases simply absent -- and absent # reads the same as "the grep found nothing", which is how a truncated run # passes for a short one. 98 is the reference run's count; a floor rather than # an equality so that adding a case to the probe is not a red here as well as a # red in whichever case it belongs to. _total=$(field XDAMAGE-TOTAL 2) if [ -n "$_total" ] && [ "$_total" -ge 98 ] 2>/dev/null; then bst_ok libxdamage/probe-total-floor else bst_notok libxdamage/probe-total-floor "want >= 98, got '$_total'" fi # --------------------------------------------------------------------------- # THE DISPLAY-FREE SURFACE # # One data symbol, because this library has no display-free entry point at all. # XDamageExtensionName is `const char[]' in the archive, defined AS DAMAGE_NAME, # and it is the string the library sends on the wire to ask for the extension. # A client that asked for the wrong name would simply never get the extension, # on every server, silently. # --------------------------------------------------------------------------- expect libxdamage/version-pv XDAMAGE-VERSION 2 1.1.6 keyed libxdamage/ver-pv XDAMAGE-VER pv 3 1.1.6 keyed libxdamage/ver-header-major XDAMAGE-VER header-major 3 1 keyed libxdamage/ver-header-minor XDAMAGE-VER header-minor 3 1 keyed libxdamage/ver-ext-name XDAMAGE-VER ext-name 3 DAMAGE keyed libxdamage/ver-ext-name-matches XDAMAGE-VER ext-name-matches 3 yes keyed libxdamage/ver-ext-name-len XDAMAGE-VER ext-name-len 3 6 keyed libxdamage/ver-no-version-entry XDAMAGE-VER no-display-free-version 3 by-design # --------------------------------------------------------------------------- # THE SEEDED EXTENSION LIST # # This is the fixture the whole failure arm rests on, so it is asserted rather # than assumed. find-cached takes the fast path (extinfo->cur matches); # find-walk clears the cache and forces the loop over ->head, which must find # the same entry and re-promote it. Both must return the seeded entry: anything # else means XDamageFindDisplay reached XDamageExtAddDisplay, and the cases # below would be measuring undefined behaviour. # --------------------------------------------------------------------------- keyed libxdamage/list-ndisplays XDAMAGE-LIST seeded-ndisplays 3 1 keyed libxdamage/list-find-cached XDAMAGE-LIST find-cached 3 seeded keyed libxdamage/list-find-walk XDAMAGE-LIST find-walk 3 seeded keyed libxdamage/list-repromotes XDAMAGE-LIST walk-repromotes 3 seeded keyed libxdamage/list-has-ext-seeded XDAMAGE-LIST has-ext-seeded 3 0 keyed libxdamage/list-has-ext-null XDAMAGE-LIST has-ext-null 3 0 keyed libxdamage/list-absent XDAMAGE-LIST absent-in-list 3 0 keyed libxdamage/list-unknown-major XDAMAGE-LIST unknown-version 3 major=-1 keyed libxdamage/list-unknown-minor XDAMAGE-LIST unknown-version 4 minor=-1 # --------------------------------------------------------------------------- # THE HONEST-FAILURE ARM -- the ticket's documented refusal, one case per kind # # The sentinels differ on purpose, and that is what makes these discriminate: # # False, out-parameters untouched XDamageQueryExtension # Status 0, out-parameters untouched XDamageQueryVersion # 0 XDamageCreate, which returns a Damage # void, having returned at all Destroy, Subtract, Add # # The `returned' cases are the whole measurement for the void calls, and they # are not weak: a build in which XDamageSimpleCheckExtension had stopped # short-circuiting would carry on into GetReq and dereference the token, so # reaching the next line is the evidence. # # The untouched cases are the part a client actually depends on. A client that # trusted a written-through event base on the failure path would add garbage to # every event code it compared. # --------------------------------------------------------------------------- keyed libxdamage/fail-query-extension XDAMAGE-FAIL query-extension 3 0 keyed libxdamage/fail-qe-untouched-ev XDAMAGE-FAIL query-extension-untouched 3 ev=-1 keyed libxdamage/fail-qe-untouched-err XDAMAGE-FAIL query-extension-untouched 4 err=-1 keyed libxdamage/fail-query-version XDAMAGE-FAIL query-version 3 0 keyed libxdamage/fail-qv-untouched-major XDAMAGE-FAIL query-version-untouched 3 major=-1 keyed libxdamage/fail-qv-untouched-minor XDAMAGE-FAIL query-version-untouched 4 minor=-1 keyed libxdamage/fail-create XDAMAGE-FAIL create 3 0 keyed libxdamage/fail-destroy XDAMAGE-FAIL destroy 3 returned keyed libxdamage/fail-subtract XDAMAGE-FAIL subtract 3 returned keyed libxdamage/fail-add XDAMAGE-FAIL add 3 returned # Nothing above may add, remove or cache anything, because every one of them # returned at the guard. A build that had walked past the guard would have # mutated the list, and this is the only case that would say so. keyed libxdamage/fail-list-unchanged XDAMAGE-FAIL list-unchanged 3 yes # --------------------------------------------------------------------------- # THE NEGOTIATED ARM -- the guard PASSING # # Without this section, a guard that always returned the failure sentinel would # be green above for the wrong reason. Here the codes are present, the guard is # true, and the two entry points that can complete without a connection do: # QueryExtension hands back the bases it was given (the other half of the # untouched pair), and QueryVersion reports the cached version and returns 1. # # The two code cases are the arithmetic every DAMAGE client does in its event # loop -- first_event + XDamageNotify and first_error + BadDamage -- and this is # the only place the base and the extension's own numbering meet. # # NOTHING ELSE IS EXERCISED HERE AND THAT IS DELIBERATE: Create, Destroy, # Subtract and Add all run LockDisplay on the line after their check, so with a # token display there is no fixture at which any of them is safe. The # `by-design' case is a marker so that a later edit which "completes" this # section is a change to a documented decision rather than an oversight. # --------------------------------------------------------------------------- keyed libxdamage/codes-has-ext XDAMAGE-CODES has-ext-with-codes 3 1 keyed libxdamage/codes-query-extension XDAMAGE-CODES query-extension 3 1 keyed libxdamage/codes-bases-ev XDAMAGE-CODES query-extension-bases 3 ev=64 keyed libxdamage/codes-bases-err XDAMAGE-CODES query-extension-bases 4 err=128 keyed libxdamage/codes-query-version XDAMAGE-CODES query-version 3 1 keyed libxdamage/codes-reported-major XDAMAGE-CODES query-version-reported 3 major=1 keyed libxdamage/codes-reported-minor XDAMAGE-CODES query-version-reported 4 minor=1 keyed libxdamage/codes-notify-code XDAMAGE-CODES notify-event-code 3 64 keyed libxdamage/codes-error-code XDAMAGE-CODES bad-damage-error-code 3 128 keyed libxdamage/codes-by-design XDAMAGE-CODES nothing-else-exercised 3 by-design keyed libxdamage/codes-restored XDAMAGE-CODES restored 3 0 # --------------------------------------------------------------------------- # THE PROTOCOL CONSTANTS # # Wire values, stated outright from the DAMAGE protocol specification rather # than diffed against a build host -- there is nothing about a second machine # that could make an answer here more true. A shifted opcode is the single most # destructive thing that can go wrong on this wire. # # The report levels are the ticket's explicit clause. They are also the only # DAMAGE constants a client can get wrong without the wire noticing: an # out-of-range level is a protocol error, but a SWAPPED pair is a client # silently asking for the wrong granularity of reporting. # --------------------------------------------------------------------------- keyed libxdamage/const-name XDAMAGE-CONST DAMAGE_NAME 3 DAMAGE keyed libxdamage/const-major XDAMAGE-CONST DAMAGE_MAJOR 3 1 keyed libxdamage/const-minor XDAMAGE-CONST DAMAGE_MINOR 3 1 keyed libxdamage/const-report-raw XDAMAGE-CONST ReportRawRectangles 3 0 keyed libxdamage/const-report-delta XDAMAGE-CONST ReportDeltaRectangles 3 1 keyed libxdamage/const-report-bbox XDAMAGE-CONST ReportBoundingBox 3 2 keyed libxdamage/const-report-nonempty XDAMAGE-CONST ReportNonEmpty 3 3 keyed libxdamage/const-req-queryver XDAMAGE-CONST req-QueryVersion 3 0 keyed libxdamage/const-req-create XDAMAGE-CONST req-Create 3 1 keyed libxdamage/const-req-destroy XDAMAGE-CONST req-Destroy 3 2 keyed libxdamage/const-req-subtract XDAMAGE-CONST req-Subtract 3 3 keyed libxdamage/const-req-add XDAMAGE-CONST req-Add 3 4 keyed libxdamage/const-numrequests XDAMAGE-CONST NumberRequests 3 5 keyed libxdamage/const-opcodes-dense XDAMAGE-CONST opcodes-dense-from-0 3 yes keyed libxdamage/const-opcode-count XDAMAGE-CONST opcode-count 3 5 # DAMAGE carries exactly one event and one error, each numbered from a base the # server hands out. A header that grew a second event would change how a client # dispatches on every extension it has, which is why the ones are asserted # rather than left implicit. keyed libxdamage/const-notify XDAMAGE-CONST Notify 3 0 keyed libxdamage/const-numevents XDAMAGE-CONST NumberEvents 3 1 keyed libxdamage/const-baddamage XDAMAGE-CONST BadDamage 3 0 keyed libxdamage/const-numerrors XDAMAGE-CONST NumberErrors 3 1 # The bit the wire packs into `level' and the translator masks back out. A # client that lost it would read `more' as part of the level and see a report # level of 128 or more. keyed libxdamage/const-notify-more XDAMAGE-CONST DamageNotifyMore 3 0x80 # --------------------------------------------------------------------------- # THE WIRE STRUCTS # # The protocol fixes these sizes. On a new arm the thing that can actually go # wrong is PADDING -- a CARD16 aligned differently would silently shift every # field after it, and the server would read a different request from the one the # client wrote. # # ALL SIX sz_ CONSTANTS ARE LITERALS in damageproto.h, so `sz == sizeof' is a # real cross-check between the specification and the compiler on every one of # them. libxcomposite's suite had to exclude three of its ten as tautologies; # this one excludes none. # --------------------------------------------------------------------------- keyed libxdamage/wire-queryver-sz XDAMAGE-WIRE sz-QueryVersionReq 3 12 keyed libxdamage/wire-queryver-sizeof XDAMAGE-WIRE sz-QueryVersionReq 5 12 keyed libxdamage/wire-queryrep-sz XDAMAGE-WIRE sz-QueryVersionReply 3 32 keyed libxdamage/wire-queryrep-sizeof XDAMAGE-WIRE sz-QueryVersionReply 5 32 keyed libxdamage/wire-create-sz XDAMAGE-WIRE sz-CreateReq 3 16 keyed libxdamage/wire-create-sizeof XDAMAGE-WIRE sz-CreateReq 5 16 keyed libxdamage/wire-destroy-sz XDAMAGE-WIRE sz-DestroyReq 3 8 keyed libxdamage/wire-destroy-sizeof XDAMAGE-WIRE sz-DestroyReq 5 8 keyed libxdamage/wire-subtract-sz XDAMAGE-WIRE sz-SubtractReq 3 16 keyed libxdamage/wire-subtract-sizeof XDAMAGE-WIRE sz-SubtractReq 5 16 keyed libxdamage/wire-add-sz XDAMAGE-WIRE sz-AddReq 3 12 keyed libxdamage/wire-add-sizeof XDAMAGE-WIRE sz-AddReq 5 12 keyed libxdamage/wire-reply-32 XDAMAGE-WIRE reply-is-32 3 yes keyed libxdamage/wire-reqs-mult-4 XDAMAGE-WIRE reqs-multiple-of-4 3 yes # The wire event the server sends and the library's WireToEvent translator # reads. 32 bytes like every other X event, on both word sizes -- every field is # an explicitly sized CARD. keyed libxdamage/wire-event-wire-32 XDAMAGE-WIRE sizeof-NotifyEventWire 3 32 # THE THREE VALUES IN THIS BLOCK THAT ARE THE TARGET'S RATHER THAN THE REFERENCE # HOST'S. An XID is an unsigned long, so the LP64 reference run answered 8 and # this ILP32 arm answers 4. Asserted as 4 deliberately: the case exists to catch # a typedef that changed shape on this arm, not to compare architectures. keyed libxdamage/wire-sizeof-damage XDAMAGE-WIRE sizeof-Damage 3 4 keyed libxdamage/wire-sizeof-drawable XDAMAGE-WIRE sizeof-Drawable 3 4 keyed libxdamage/wire-sizeof-region XDAMAGE-WIRE sizeof-XserverRegion 3 4 # --------------------------------------------------------------------------- # THE EVENT UNION -- this ticket's headline risk # # XDamageNotifyEvent is one of the packed, extension-numbered XEvent members, # and getting its layout wrong is SILENT: the library writes through a pointer # the application supplied, into storage the application sized from XEvent. # # `fits-in-xevent' is the load-bearing one -- a struct that grew past XEvent # overruns the application's own event queue, one element into the next, which # no amount of correct field handling would save. sizeof(XEvent) itself is NOT # asserted: it is a union over every event Xlib knows and its size is a property # of Xlib's headers rather than of this port, so pinning it here would make this # suite go red on an Xlib change that cannot affect DAMAGE. # # The offsets are this arm's, and they are ILP32 ARITHMETIC rather than the # reference host's readings: XID, Time, unsigned long and the Display pointer # are all 4 here and 8 there, so every offset past `type' differs by # construction and the LP64 run's 80/8/16/24... would be wrong to copy. They # are ARITHMETIC from the declaration in Xdamage.h, cross-checked against a # retyped ILP32 model on the build host. # # MEASURED ON TARGET 2026-09-12, and the model held: all twelve of these cases # passed on the first on-target run of this port -- sizeof 52 and offsets # 0/4/8/12/16/20/24/28/32/36/44, with sizeof-Damage/Drawable/XserverRegion 4. # The model was ARITHMETIC, not a reading (`-m32' is unavailable on the build # host -- no gnu/stubs-32.h), so agreement between it and the target is a real # cross-check rather than a tautology. docs/design/BRINTOS-2493-port-libxdamage.md # records both readings. The target run stays the authority: if a later one # disagrees, THESE cases are what must change, not it. # --------------------------------------------------------------------------- keyed libxdamage/event-sizeof XDAMAGE-EVENT sizeof-XDamageNotifyEvent 3 52 keyed libxdamage/event-fits-in-xevent XDAMAGE-EVENT fits-in-xevent 3 yes keyed libxdamage/event-off-type XDAMAGE-EVENT off-type 3 0 keyed libxdamage/event-off-serial XDAMAGE-EVENT off-serial 3 4 keyed libxdamage/event-off-send-event XDAMAGE-EVENT off-send_event 3 8 keyed libxdamage/event-off-display XDAMAGE-EVENT off-display 3 12 keyed libxdamage/event-off-drawable XDAMAGE-EVENT off-drawable 3 16 keyed libxdamage/event-off-damage XDAMAGE-EVENT off-damage 3 20 keyed libxdamage/event-off-level XDAMAGE-EVENT off-level 3 24 keyed libxdamage/event-off-more XDAMAGE-EVENT off-more 3 28 keyed libxdamage/event-off-timestamp XDAMAGE-EVENT off-timestamp 3 32 keyed libxdamage/event-off-area XDAMAGE-EVENT off-area 3 36 keyed libxdamage/event-off-geometry XDAMAGE-EVENT off-geometry 3 44 # The first four members are the common X event prefix, in the order every # XEvent member shares. A client that switches on `type' and then reads # `xany.display' depends on this holding across the union, and it is # word-size-independent. keyed libxdamage/event-prefix-xany XDAMAGE-EVENT prefix-matches-xany 3 yes # XRectangle is two shorts and two unsigned shorts on every arm. keyed libxdamage/event-sizeof-xrect XDAMAGE-EVENT sizeof-XRectangle 3 8 keyed libxdamage/event-area-first XDAMAGE-EVENT area-before-geometry 3 yes # --------------------------------------------------------------------------- # THE EXPORTED SYMBOL SET, AGAINST A COMMITTED LIST # # Seven names, written out here rather than counted, because a census by number # goes green again the moment one entry point is lost and another appears and it # cannot say which one left. The probe takes each address, so the STATIC LINK is # what proves the archive still contains it -- a name the build had dropped # fails do_compile with that name, rather than surfacing months later in a # consumer's link. # # Six are Xdamage.h's public API; XDamageFindDisplay is the one non-static # internal, exported through xdamageint.h. The library's other six functions are # `static' and are deliberately absent -- they are not linkable names at all. # --------------------------------------------------------------------------- for sym in XDamageQueryExtension XDamageQueryVersion XDamageFindDisplay \ XDamageCreate XDamageDestroy XDamageSubtract XDamageAdd; do got=$(awk -v s="$sym" '$1=="XDAMAGE-SYM" && $2==s {print $3; exit}' "$out") if [ "$got" = "linked" ]; then bst_ok "libxdamage/sym-$sym" else bst_notok "libxdamage/sym-$sym" "want 'linked', got '$got'" fi done expect libxdamage/sym-count XDAMAGE-SYM-COUNT 2 7 expect libxdamage/sym-null XDAMAGE-SYM-NULL 2 0 # The data symbol is not a function pointer, so it is censused separately. Six # is the length of "DAMAGE"; a truncated or relocated string would still read as # a valid C string and only the length would say so. keyed libxdamage/sym-data-name-len XDAMAGE-SYM-DATA ext-name-len 3 6 # --------------------------------------------------------------------------- # THE DISPLAY THAT IS NOT THERE # # The documented no-server path, and the reason the failure arm above had to # seed the list to say anything at all. What must hold is that XOpenDisplay SAYS # so -- returns NULL, promptly, for each spelling -- rather than crashing, # blocking, or handing back a half-built Display that the first # XDamageQueryVersion would then walk into. The fixtures are the transports a # display string selects: no DISPLAY at all, the local socket, an unused local # display number, and an explicit TCP host -- the ticket's "DISPLAY pointing at # an address nothing is listening on". # # All four are NULL on target. The reference host answered `opened' for unix-0 # because it has a live X server; see this file's header for why that reading is # the machine's and not the library's. # --------------------------------------------------------------------------- keyed libxdamage/dpy-no-env XDAMAGE-DPY no-env 3 NULL keyed libxdamage/dpy-unix-0 XDAMAGE-DPY unix-0 3 NULL keyed libxdamage/dpy-unix-99 XDAMAGE-DPY unix-99 3 NULL keyed libxdamage/dpy-tcp XDAMAGE-DPY tcp 3 NULL keyed libxdamage/dpy-reached-end XDAMAGE-DPY reached-end 3 yes rm -f "$out"