Thursday, April 04, 2024
Tracking down a bug
I've spent the past two days tracking down a bug, and I think it's a library issue.
So I have this program I wrote some time ago that uses Xlib and for reasons, I needed to store a 64-bit value that's related to a window. This is easy enough with setting a window property. The code for that is easy enough:
void svalue(Display *display,Window window,unsigned long long int value) { assert(display != NULL); assert(window != None); XChangeProperty( display, window, CALC_VALUE, XA_INTEGER, 32, /* format */ PropModeReplace, (unsigned char *)&value, sizeof(value) / 4 /* number of 'format' units */ ); }
CALC_VALUE
is the “variable”
(for lack of a better term)
and XA_INTEGER
is
(again, for lack of a better term)
the base type.
Yes,
this is just wrapping a single function call in a function,
but it's an abstraction to make things simpler as it's called from multiple locations in the codebase.
To query the value:
unsigned long long int qvalue(Display *display,Window window) { assert(display != NULL); assert(window != None); unsigned long long int value; Atom atom_got; unsigned char *plong; int rc = XGetWindowProperty( display, window, CALC_VALUE, 0, sizeof(unsigned long long int) / 4, False, XA_INTEGER, &atom_got, &(int){0}, /* this is don't care */ &(unsigned long int){0}, /* another don't care */ &(unsigned long int){0}, /* another don't care */ &plong ); if ((rc == Success) && (atom_got == XA_INTEGER)) { memcpy(&value,plong,sizeof(unsigned long long int)); XFree(plong); } else value = 0; return value; }
Again, nothing too horrible or tricky.
The code was originally written on a 32-bit system (just after I left The Enterprise), and it worked. I then wanted to get the program working on a 64-bit system (beacuse I want to both release it and talk about it). It worked, but only for values of 31-bits or less. As soon as the value hit 32-bits, the upper 32-bits were all 1s.
I added code to dump the value just before the call to XChangeProperty()
and code to dump the value just after the call to XGetWindowProperty()
and somewhere,
once the value was 0x00000000FFFFFFFF going into XChangeProperty()
,
it was 0xFFFFFFFFFFFFFFFF coming out of XGetWindowProperty()
.
32-bit version? No issues. 64-bit version? Issues.
I tried a different compiler,
on the off chance that I might be hitting some weird compiler bug,
and no go,
GCC or Clang,
both on the 64-bit system had the same issue.
I tried using a different X server and the same results—32 bit client, fine; 64-bit client, not fine.
So I think it's due to the client side on the 64-bit system where the issue lies.
Also,
if I change the call to XChangeProperty()
to:
void svalue(Display *display,Window window,unsigned long long int value) { assert(display != NULL); assert(window != None); XChangeProperty( display, window, CALC_VALUE, XA_INTEGER, 8, /* format, this time 8! */ PropModeReplace, (unsigned char *)&value, sizeof(value) /* still number of 'format' units */ ); }
That is, a format of 8 fixed the issue. Even a format of 16 worked. It's just that when I try to use a format of 32, on the 64-bit system, does it fail.
And using a format of 8 on the 32-bit system works as well, so at least I have a workaround for it. Still, it's annoying.
I love it when abstractions are too abstract to be useful
I recently found an annoying aspect of
Xlib—it's hard to find documentation about what keys affect the state
field of the keyboard event.
It's obvious that the shift keys on the keyboard will set ShiftMask
,
the control key will set ControlMask
,
and the CapsLock key will set LockMask
(when I would expect it to set ShiftMask
since it's just locking the shift keys to “on”),
but there's little to say what keys set the Mod1Mask
, Mod2Mask
, Mod3Mask
, Mod4Mask
and Mod5Mask
.
This is problematic,
because I do need to check for keyboard events and this threw me for a loop—why are none of the keys working?
Well,
that's because my virtual Linux server on the Mac sets the NumLock key,
which causes the X server to then set the Mod2Mask
for all keyboard events and I wasn't expecting that.
Sigh.