This is a discussion on Re: shifting curiosity within the mailing.openbsd.tech forums, part of the OpenBSD category; --> On Thu, 16 Jun 2005, Moritz Grimm wrote: > Hi, > > > today, I came across an idiosyncrasy ...
| |||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| On Thu, 16 Jun 2005, Moritz Grimm wrote: > Hi, > > > today, I came across an idiosyncrasy wrt shifting in C/C++, at least with gcc > and g++ on OpenBSD/i386. > > The following snippet demonstrates it in a form that also occurs quite a few > times similarily in OpenBSD source code, e.g. in src/usr.sbin/bgpctl/parser.c > and various other places (each with more or less likelihood of ``bits'' ever > being 0): > > { > unsigned int mask1, mask2; > int bits; > > bits = 0; > > mask1 = 0xffffffff << (32 - bits); > mask2 = (unsigned long long)0xffffffff << (32 - bits); > > [...] > } > > mask1 and mask2 are not the same. The value of mask1 is 0xffffffff, as if it > were left-shifted by 0, while mask2 is 0. Concerning prefix lengths of CIDR > network numbers, the latter is clearly what we want, so that 0.0.0.0/0 doesn't > break (I need this in a different context, which made me stumble over this in > every case, not only when dealing with an actual 0.0.0.0/0 network.) > > The reason for this seems that even without optimization, the amount of bits > to shift is mod'ed with the amount of bits in the type the shifting is done > with - 32 % 32 = 0, ergo no shifting is being done. A shift of an amount larger than the size of the expression in bits is undefined. In practise the result depends on compiler and/or CPU. In the first expression, both operands are int, so the result is undefined. In the seconds expression, the left hand operand is unsigned long long, so the shift is well-defined. I don't know if the variable bits in the expression in bgpctl/parser.c:520 can assume the value 0, bit if so, it looks like a bug. > My solution is to cast the unshifted mask to 64bit and let the > casting-back-to-32bit take care of making the 1s disappear for good. That is safe, another possibility would be something like value = bits == 0 ? 0 : (mask << (32 - bits)); > > What I am curious about is whether all of this is intended behavior, and why > (I find it strange) - other than that, please consider this as a general FYI, > as this *might* be a problem in some places in OpenBSD (userland mostly, I > suppose). -Otto |