On Thu, Aug 02, 2018 at 09:59:13PM -0600, Martin Sebor wrote: > > If I call this with foo (2, 1), do you still claim it is not valid C? > > String functions like strlen operate on character strings stored > in character arrays. Calling strlen (&s[1]) is invalid because > &s[1] is not the address of a character array. The fact that > objects can be represented as arrays of bytes doesn't change > that. The standard may be somewhat loose with words on this > distinction but the intent certainly isn't for strlen to traverse > arbitrary sequences of bytes that cross subobject boundaries. > (That is the intent behind the raw memory functions, but > the current text doesn't make the distinction clear.)
But the standard doesn't say that right now. Plus, at least from the middle-end POV, there is also the case of placement new and stores changing the dynamic type of the object, previously say a struct with two fields, then a placement new with a single char array over it (the placement new will not survive in the middle-end, so it will be just a memcpy or strcpy or some other byte copy over the original object, and due to the CSE/SCCVN etc. of pointer to pointer conversions being in the middle-end useless means you can see a pointer to the struct with two fields rather than pointer to char array. Consider e.g. typedef __typeof__ (sizeof 0) size_t; void *operator new (size_t, void *p) { return p; } void *operator new[] (size_t, void *p) { return p; } struct S { char a; char b[64]; }; void baz (char *); size_t foo (S *p) { baz (&p->a); char *q = new (p) char [16]; baz (q); return __builtin_strlen (q); } I don't think it is correct to say that strlen must be 0. In this testcase the pointer passed to strlen is still S *, though I think with enough tweaking you could also have something where the argument is &p->a. I have no problem for strlen to return 0 if it sees a toplevel object of size 1, but note that if it is extern, it already might be a problem in some cases: struct T { char a; char a2[]; } b; extern struct T c; void foo (int *p) { p[0] = strlen (b); p[1] = strlen (c); } If c's definition is struct T c = { ' ', "abcde" }; then the object doesn't have length of 1. But for subobjects and especially trying to derive anything from what kind of pointer you are called with just doesn't work, unless you do it in the FE only. Jakub