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

Reply via email to