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