2016-10-23 17:05 GMT+02:00 Dominik Vogt <dominik.v...@gmx.de>: > On Sun, Oct 23, 2016 at 04:39:53PM +0200, Viktor Griph wrote: >> Den 23 okt. 2016 14:36 skrev "Dominik Vogt" <dominik.v...@gmx.de>: >> > void fev_sanitise_configure_request(XConfigureRequestEvent *cr) >> > { >> > if (cr->value_mask & CWX) >> > { >> > cr->x = (((int)cr->x) & 0xffff); >> > } >> > ... >> > if (cr->value_mask & CWHeight) >> > { >> > cr->height = (((unsigned int)cr->height) & >> 0xffff); >> > } >> > ... >> > } >> > >> > This tries to deal with an inconsistency between the X protocol >> > and the Xlib structures: In the X protocol, in the >> > ConfirureWindow request, X and Y are signed "INT16" quantities and >> > WIDTH and HEIGT are unsigned "CARD16" quantities, while in the >> > Xlib structures they are "int" or "unsigned int". >> > >> > The code tries to cut off the excess bits from X and Y and does it >> > wrong. With 32-bit integers, if cr->x is -1: >> > >> > ((int)-1) & 0xffff = 0xffffffff & 0xffff >> > = 0xffff >> > = 65535 >> > >> > I'm not sure how to fix this. The easiest approach would be to >> > cast these values to int16_t or uint16_t from stdint.h, but I >> > vaguely remember there are some portability issues with the >> > inttypes.s/stdint.h headers. >> >> Instead of setting the excess bits to 0 we need to set them to 1 for the >> negative case. >> >> What about >> if (cr->x & 0x8000) >> { >> cr->x = (((int)-1) ^ 0x7fff) | (((int)cr->x) & 0x7fff); >> } >> else >> { >> cr->x = (((int)cr->x) & 0xffff); >> } >> >> The negative case could be simplified to >> >> (((int)-1) ^ 0x7fff) | ((int)cr->x) >> >> Or >> >> ((int)-1)<<16|((int)cr->x) > > I never can remember this; is it safe (in C) to assume that > negative integers are stored in two-complement format? (Of course > the old code makes the same assumtion, but it's broken and I want > to fix it.)
So use (~(int)0) instead of -1 and it should work for both one-complement and two-complement numbers. The MSB would still mark the sign. (If what the code is trying to fix is that there may be extra bits beyond the 16 bits that are defined in the X-server, then those bits could be anything, and maybe wouldn't guarantee that negative numbers are correctly 1-padded above bit 16, in fact they may not even have the int MSB set. If that is the case then I don't think casting to int16_t or uint16_t would be feasible. The standard mandates the int16_t to be in two-complement form even if the hardware is using one-complement so casting from int to int_16t on a one-complement platform would change the bit pattern in order to maintain the value, but if the value is out of range for the 16-bit number due to the excess bits you are trying to correct. I'm not sure if the handling of overflow at a cast to xxx16_t is well-defined cross all platforms. > > If it's really portable, the cleanest way is casting to int16_t > and uint16_t from stdint.h. Definitely. I just don't know if it is.