On Tue, Nov 23, 2021 at 09:08:35PM +0530, Siddhesh Poyarekar wrote: > On 11/23/21 21:06, Siddhesh Poyarekar wrote: > > On 11/23/21 20:42, Jakub Jelinek wrote: > > > On Wed, Nov 10, 2021 at 12:31:32AM +0530, Siddhesh Poyarekar wrote: > > > > (object_sizes_execute): Don't insert min/max for dynamic sizes. > > > > > > I'm worried about this. > > > I'd say what we might want to do is in the early pass for __bdos > > > compute actually __bos (i.e. the static one) and add MIN_EXPR/MAX_EXPR > > > for the result of the __bdos call from the second pass with the > > > statically computed value. > > > > > > The reason for the MIN_EXPR/MAX_EXPR stuff is that GIMPLE optimizations > > > can remove exact ADDR_EXPRs with detailed COMPONENT_REF etc. access paths > > > in it, so during the late objsz2 pass the subobject modes don't work > > > reliably anymore. But the subobject knowledge should be the same between > > > the static and dynamic evaluation... > > > > So in the dynamic case we almost always end up with the right expression > > in objsz1, except in cases where late optimizations make available > > information that wasn't available earlier. How about putting in a > > MIN_EXPR/MAX_EXPR if we *fail* to get the subobject size instead? > > Actually if we don't get a dynamic expression it's unlikely that we'll get a > static size either, so I'm not sure if MIN_EXPR/MAX_EXPR will actually do > anything useful.
Consider: struct S { int a; char b[16]; int c; char d[]; }; static int foo (struct S *s) { return __builtin_object_size (&s->b[2], 1); } int bar (int m) { struct S *s = (struct S *) __builtin_malloc (m); int r = foo (s); __builtin_free (s); return r; } In early_objsz, foo isn't inlined, we can statically determine the maximum bound of 14 but don't really know how large the allocation will actually be. So, we record that foo returns MIN_EXPR <__builtin_object_size (&s->b[2], 1), 14> and in the late objsz compute that as MIN_EXPR <-1UL, 14>. Now, with __builtin_dynamic_object_size, I think it is pretty much the same, you don't know how large the allocation actually is, so IMHO we want to record MIN_EXPR <__buitin_dynamic_object_size (&s->b[2], 1), 14> and at runtime do MIN_EXPR <m - 6, 14> or so. It is true that it is just an upper bound, if we do: static int baz (struct S *s, int l) { return __builtin_dynamic_object_size (l ? &s->b[3] : &s->b[2], 1); } int qux (int m, int l) { struct S *s = (struct S *) __builtin_malloc (m); int r = foo (s, l); __builtin_free (s); return r; } then the statically computed __bos in early_objsz would be still 14 and I think dynamic needs to punt because it really doesn't know how large the allocation will be. In the late objsz it can make m - 6 - !!l out of it for the __bdos (, 0) from it and combine that to MIN_EXPR <m - 6 - !!l, 14> which still isn't exact, that would be l ? MIN_EXPR <m - 7, 13> : MIN_EXPR <m - 6, 14>. But, at late objsz time, the information that there was &s->b[3] and &s->b[2] might be gone, consider e.g. in baz above a call corge ((char *) s + offsetof (struct S, b) + 2, (char *) s + offsetof (struct S, b) + 3); where SCCVN will CSE the (char *) s + offsetof (struct S, b) + 2 and &s->b[2] etc. expressions because they have the same value. But __bos ((char *) s + offsetof (struct S, b) + 2, 1) should be equal to __bos ((char *) s + offsetof (struct S, b) + 2, 0). Jakub