tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: in which we present an ugly hack to make sys/queue.h CIRCLEQ work



On 2013-11-24 mouse%Rodents-Montreal.ORG@localhost wrote:

if the code never followed the pointers, it could compare them just
fine without risk (though I'm going to ask my go-to C reference person
to check my reading on this point).

This is the case with CIRCLEQ, which is what Dennis was pointing out. It could have used NULL as a sentinel, but instead used the pointer to some other completely different type it happened to have available. Additionally, when doing the later comparison the correct type of the pointer being compared is cast to void * explicitly and there is an implicit conversion of the incorrectly-typed pointer. It seems like an interesting C language question if all that is supposed to work.

Looking at section 6.3.2.3 of N1570 (pointers), "trap representation" is only mentioned for integer conversion to pointer so that idea of mine seems completely wrong. Conversion between pointers of different types only mentions differing alignment causing undefined behavior (except for NULL, which is guaranteed to work). I wouldn't think it would be a differing alignment issue. I also read Dennis's message again and learned more :). It sounds like it might be supposed to work. Unless something requires the cast to be applied to the wrongly typed pointer when doing the comparison. 6.3.2.3 only guarantees that when converted back it will compare equal, so I wonder if this does mean that there is supposed to be an explicit cast (though I don't see anything that seems to say that an explicit cast is different than an implicit conversion or that casting to void * wouldn't qualify as "converted back" for this purpose).

I tried and failed to get a simple CIRCLEQ test case to produce incorrect code on an arch linux system with gcc 4.8.2. Also, I tried compiling nvi-1.79 (from Keith Bostic's site, because that was easy; there don't seem to be significant differences from NetBSD CIRCLEQ) with -O2 -fstrict-aliasing -Wstrict-aliasing=1 (and -Wstrict-aliasing=2 and 3; 1 and 3 produced completely different results and 2 produced the combination of 1 and 3, which is not what I expected from the man page).

There are a couple of strict-alias warnings at level 1 and 2 for CIRCLEQ (actually the hand coded equivalent of CIRCLEQ_FOREACH), which go away (without produced output changes) if the cast is moved to the left side of the comparison. I didn't notice any differences in behavior between the original code and using __launder_type with a few simple tests, though that isn't surprising.

I'm not sure it is worth putting more time into (and I'm glad folks have been removing CIRCLEQ from most places), but casting to struct type * when storing and casting to typeof(head) on the left side of the comparison seems likely to make it work reliably (possibly just changing the cast on the left of the comparison to void * would work too and would be standard C).

  Thanks to everyone doing the gcc update :).

-Matt


Home | Main Index | Thread Index | Old Index