jim@ci-dandelion.UUCP (02/13/87)
PROBLEM:
There are several declaration bugs in lk201.c that can cause X servers to loop
when processing input events of type VSE_KBTRAW. We found this after a number
of our QVSS's and QDSS's started hanging after our product application started
turning off AutoRepeat. Getting a core dump showed that the server was always
in the Deal_with_input call around line 75 under the ALLUPS case. A sample of
the variables at that point gave some interesting values:
key = 380084
bits = -1
Since bits is declared a SIGNED register int, the loop
key = 0;
do {
if (bits & 1) {
ev->vse_key = (idx << 5) | key;
Deal_with_input (ev);
}
key++;
} while (bits >>= 1);
never terminates (hence the absurd value of key) because the sign bit (1) is
always shifted in, keeping bits from ever becoming zero.
SOLUTION:
Make sure that the keymodes[], keys[], key, and bits variables are declared
UNSIGNED int so that the shift problem doesn't happen.
EXPLANATION:
The situation seems to arise when the low 5 bits of ev->vse_key are equal to 31
and (key > MAXSPECIAL || (key >= BASEKEY && key < MINSPECIAL)), i.e. 95, 127,
159, 191, 223, 255. This causes the high bit of key to be set at line 46:
key &= 0x1f;
key = 1 << key; /* key == 31 -> key becomes 0x80000000 */
if (!(keymodes[idx] & key) || ((keys[idx] ^= key) & key))
if the high bit in the corresponding keymodes word is set, the test in the
next line causes keys[idx] to be xor'ed with 0x80000000. Now, the keymodes
array can get filled with lots of negative numbers by turning off autorepeat
(the QVSS calls UpDownLKMode):
keymodes: 0 0 -4194304 -1 -1 -267911169 -1 -1
So, it becomes fairly easy to get one of 6 keycodes mentioned above which
will result in the sign bit of one of the keys[] being set. Then, if an
ALLUPS code is received, the do loop wedges your server.
MORAL: Beware of signed bit masks.
Jim Fulton
Cognition Inc.
900 Tech Park Drive
UUCP: ...!{mit-eddie,talcott}!ci-dandelion!jim Billerica, MA
ARPA: fulton@eddie.mit.edu, jim@athena.mit.edu (617) 667-4800