The inbounds marker is just a guarantee that the pointer arithmetic will result in a pointer within the bounds of the object. They define one byte past the end as a special case that's allowed. The part that goes beyond C spec are their runtime / libc assumptions.
Conversation
i.e. knowing that an object cannot ever be at 0 or the maximum address that could be represented by a pointer. They treat null in a special way (never valid object) and it allows their assumption of no wrapping for inbounds GEP.
2
1
Try twitter.com/DanielMicay/st with and without -fwrapv or -fno-strict-overflow with Clang.
In theory, the inbounds marker could be split up into 2 separate markers to provide the no-overflow guarantee as a separate guarantee from being within the bounds of the object.
Quote Tweet
Replying to @DanielMicay and @iximeow
For example, in C:
char *foo(char *x) {
return x + 10;
}
Compile this with `clang foo.c -S -emit-llvm -o - -O2`.
The function `foo` is a guarantee that `x` is not NULL and is at least 10 bytes large. The result is at most 1 byte past the end of `x`. It's a promise.
1
1
The only way you really get non-inbounds GEP from Clang is when you do stuff like casting to/from integers and it happens to compile that code back to GEP.
Casting to/from integers is what gets incredibly sketchy and is arguably broken due to pointer provenance rules they use.
2
Replying to
Everybody loses when provenance rears its ugly head. But I thought there were rules to track provenance through integers (in the C spec, and LLVM/GCC)?
(You're answering my q's as I tweet them :P)
2
Replying to
The current C standard doesn't really standardize it. LLVM / GCC and likely other compilers choose to come up with those rules. They feel it's the only reasonable approach because it would be too hard to optimize C otherwise. They'd still do it for other languages regardless.
1
C standard retroactively turns things into undefined behavior regularly. They see their job as largely standardizing real world implementations. If compiler authors want something badly enough, they'll get it, because they'll do it and the standard will change. Likely for this.
2
1
Replying to
twitter.com/DanielMicay/st I just realized: this comment about "inbounds assumes wrapping doesn't occur FOLLOWS FROM null is an invalid object" also codifies that "objects must have contiguous storage allocation".
Because if they didn't, then an object could just be placed in >>
Quote Tweet
Replying to @DanielMicay @cr1901 and 2 others
i.e. knowing that an object cannot ever be at 0 or the maximum address that could be represented by a pointer. They treat null in a special way (never valid object) and it allows their assumption of no wrapping for inbounds GEP.
1
two discontiguous chunks- one before wrapping, one after- to avoid accessing an object at an invalid address.
So what does the spec say about struct padding at the null and max address :P?
1
Replying to
Struct padding is part of the object size so the padding can't be touching the end of the maximum representable address space either. This isn't something the C spec talks about at all though. It's just what GCC/LLVM assume from the runtime / libc implementation.
2
Similarly, C specification says nothing about stack overflow. It should specify that there's an implementation defined limit for storing state for called functions and that the implementation must trap when it's exhausted.
Implementations don't really comply with it right now.
Replying to
(Well, DOS is nice enough to crash the system for you if you overflow its internal stack :D.)

