Am Donnerstag, dem 26.10.2023 um 11:20 +0200 schrieb Martin Uecker:
> Am Donnerstag, dem 26.10.2023 um 10:45 +0200 schrieb Richard Biener:
> > On Wed, Oct 25, 2023 at 8:16 PM Martin Uecker <uec...@tugraz.at> wrote:
> > > 
> > > Am Mittwoch, dem 25.10.2023 um 13:13 +0200 schrieb Richard Biener:
> > > > 
> > > > > Am 25.10.2023 um 12:47 schrieb Martin Uecker <uec...@tugraz.at>:
> > > > > 
> > > > > Am Mittwoch, dem 25.10.2023 um 06:25 -0400 schrieb Siddhesh 
> > > > > Poyarekar:
> > > > > > > On 2023-10-25 04:16, Martin Uecker wrote:
> > > > > > > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> > > > > > > > 
> > > > > > > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker 
> > > > > > > > > <uec...@tugraz.at>:
> > > > > > > > > 
> > > > > > > > > Am Dienstag, dem 24.10.2023 um 20:30 +0000 schrieb Qing Zhao:
> > > > > > > > > > Hi, Sid,
> > > > > > > > > > 
> > > > > > > > > > Really appreciate for your example and detailed 
> > > > > > > > > > explanation. Very helpful.
> > > > > > > > > > I think that this example is an excellent example to show 
> > > > > > > > > > (almost) all the issues we need to consider.
> > > > > > > > > > 
> > > > > > > > > > I slightly modified this example to make it to be 
> > > > > > > > > > compilable and run-able, as following:
> > > > > > > > > > (but I still cannot make the incorrect reordering or DSE 
> > > > > > > > > > happening, anyway, the potential reordering possibility is 
> > > > > > > > > > there…)
> > > > > > > > > > 
> > > > > > > > > >  1 #include <malloc.h>
> > > > > > > > > >  2 struct A
> > > > > > > > > >  3 {
> > > > > > > > > >  4  size_t size;
> > > > > > > > > >  5  char buf[] __attribute__((counted_by(size)));
> > > > > > > > > >  6 };
> > > > > > > > > >  7
> > > > > > > > > >  8 static size_t
> > > > > > > > > >  9 get_size_from (void *ptr)
> > > > > > > > > > 10 {
> > > > > > > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > > > > > > 12 }
> > > > > > > > > > 13
> > > > > > > > > > 14 void
> > > > > > > > > > 15 foo (size_t sz)
> > > > > > > > > > 16 {
> > > > > > > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz 
> > > > > > > > > > * sizeof(char));
> > > > > > > > > > 18  obj->size = sz;
> > > > > > > > > > 19  obj->buf[0] = 2;
> > > > > > > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > > > > > > 21  return;
> > > > > > > > > > 22 }
> > > > > > > > > > 23
> > > > > > > > > > 24 int main ()
> > > > > > > > > > 25 {
> > > > > > > > > > 26  foo (20);
> > > > > > > > > > 27  return 0;
> > > > > > > > > > 28 }
> > > > > > > > > > 
> > > > > > 
> > > > > > <snip>
> > > > > > 
> > > > > > > > When it’s set I suppose.  Turn
> > > > > > > > 
> > > > > > > > X.l = n;
> > > > > > > > 
> > > > > > > > Into
> > > > > > > > 
> > > > > > > > X.l = __builtin_with_size (x.buf, n);
> > > > > > > 
> > > > > > > It would turn
> > > > > > > 
> > > > > > > some_variable = (&) x.buf
> > > > > > > 
> > > > > > > into
> > > > > > > 
> > > > > > > some_variable = __builtin_with_size ( (&) x.buf. x.len)
> > > > > > > 
> > > > > > > 
> > > > > > > So the later access to x.buf and not the initialization
> > > > > > > of a member of the struct (which is too early).
> > > > > > > 
> > > > > > 
> > > > > > Hmm, so with Qing's example above, are you suggesting the 
> > > > > > transformation
> > > > > > be to foo like so:
> > > > > > 
> > > > > > 14 void
> > > > > > 15 foo (size_t sz)
> > > > > > 16 {
> > > > > > 16.5  void * _1;
> > > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > > sizeof(char));
> > > > > > 18  obj->size = sz;
> > > > > > 19  obj->buf[0] = 2;
> > > > > > 19.5  _1 = __builtin_with_size (obj->buf, obj->size);
> > > > > > 20  __builtin_printf (“%d\n", get_size_from (_1));
> > > > > > 21  return;
> > > > > > 22 }
> > > > > > 
> > > > > > If yes then this could indeed work.  I think I got thrown off by the
> > > > > > reference to __bdos.
> > > > > 
> > > > > Yes. I think it is important not to evaluate the size at the
> > > > > access to buf and not the allocation, because the point is to
> > > > > recover it from the size member even when the compiler can't
> > > > > see the original allocation.
> > > > 
> > > > But if the access is through a pointer without the attribute visible
> > > > even the Frontend cannot recover?
> > > 
> > > Yes, if the access is using a struct-with-FAM without the attribute
> > > the FE would not be insert the builtin.  BDOS could potentially
> > > still see the original allocation but if it doesn't, then there is
> > > no information.
> > > 
> > > > We’d need to force type correctness and give up on indirecting
> > > > through an int * when it can refer to two diffenent container types.
> > > > The best we can do I think is mark allocation sites and hope for
> > > > some basic code hygiene (not clobbering size or array pointer
> > > > through pointers without the appropriately attributed type)
> > > 
> > > I am do not fully understand what you are referring to.
> > 
> > struct A { int n; int data[n]; };
> > struct B { long n; int data[n]; };
> > 
> > int *p = flag ? a->data : b->data;
> > 
> > access *p;
> > 
> > Since we need to allow interoperability of pointers (a->data is
> > convertible to a non-fat pointer of type int *) this leaves us with
> > ambiguity we need to conservatively handle to avoid false positives.
> 
> For BDOS, I would expect this to work exactly like:
> 
> char aa[n1];
> char bb[n2];
> char *p = flag ? aa : bb;
> 
> (or similar code with malloc). In fact it does:
> 
> https://godbolt.org/z/bK68YKqhe
> (cheating a bit and also the sub-object version of
> BDOS does not seem to work)
> 
> > 
> > We _might_ want to diagnose decay of a->data to int *, but IIRC
> > there's no way (or proposal) to allow declaring a corresponding
> > fat pointer, so it's not a good designed feature.
> 
> As a language feature, I fully agree.  I see the
> counted_by attribute has a makeshift solution.
> 
> But we can already do:
> 
> auto p = flag ? &aa : &bb;
> 
> and this already works perfectly:
> 
> https://godbolt.org/z/rvb6xWWPj
> 
> We can also name the variably-modifed type: 
> 
> char (*p)[flag ? n1 : n2] = flag ? &aa : &bb;
> https://godbolt.org/z/13cTT1vGP
> 
> The problem with this version is that consistency
> is not checked. (I have patch for adding run-time
> checks).
> 
> And then the next step would be to allow
> 
> char (*p)[:] = flag ? &aa : &bb;
> 
> or similar.  Dennis Ritchie proposed this himself
> a long time ago.
> 
> So far this seems straightfoward.
> 
> If we then want to allow such wide pointers as
> function arguments or in structs, we would need
> to define an ABI. But the ABI could just be
> 
> struct { char (*p)[.s]; size_t s; };
> 
> Maybe we could try to make the following
> ABI compatible:
> 
> int foo(int p[s], size_t s);
> int foo(int p[:]);
> 
> 
> > Having __builtin_with_size at allocation would possibly make
> > the BOS use-def walk discover both objects.
> 
> Yes. But I do not think this there is any fundamental
> difference to discovering allocation functions.
> 
> >   I think you can't
> > insert __builtin_with_size at the access to *p, but in practice
> > that would be very much needed.
> 
> Usually the access to *p would follow directly the
> access x.buf, so BDOS should find it.
> 
> But yes, to get full bounds safety, the pointer type 
> has to change to a variably-modified type (which would work
> today) or a fat pointer type. The later can be built on
> vm-types easily because all the FE semantics already
> exists.

We could insert the __builtin_with_size everywhere
we have to convert a wide pointer or let an array
decay to traditional pointer for reason of compatibility 
with legacy code.

Martin

> 
> Martin
> 
> > 
> > Richard.
> > 
> > > But yes,
> > > for full bounds safety we would need the language feature.
> > > In C people should start to variably-modified types
> > > more.  I think we can build perfect bounds safety on top of
> > > them in a very good way with only FE changes.
> > > 
> > > All these attributes are just a best effort.  But for a while,
> > > this will be necessary.
> > > 
> > > Martin
> > > 
> > > > 
> > > > > Evaluating at this point requires that the size is correctly set
> > > > > before the access to the FAM and the user has to make sure
> > > > > this is the case. But to me this requirement would make sense.
> > > > > 
> > > > > Semantically, it could aöso make sense to evaluate the size at a
> > > > > later time.  But then the reordering becomes problematic again.
> > > > > 
> > > > > Also I think this would make this feature generally more useful.
> > > > > For example, it could work also for others pointers in the struct
> > > > > and not just for FAMs.  In this case, the struct may already be
> > > > > freed when  BDOS is called, so it might also not possible to
> > > > > access the size member at a later time.
> > > > > 
> > > > > Martin
> > > > > 
> > > > > 
> > > > > > 
> > > > > 
> > > 
> 

Reply via email to