4 ms·
In fact, per the standard, a+x is already an array reference: you aren't allowed to go outside the bounds of the array immediately containing the pointee, on pa
by LegionMammal978 2y ago
In fact, per the standard, a+x is already an array reference: you aren't allowed to go outside the bounds of the array immediately containing the pointee, on pain of UB.
(Arrays do exist in the object model, and you can take pointers to them of type T (*)[N]; you just can't copy them around by value, and the name of an array decays to its first element pointer.)
Compilers just typically don't track array bounds at runtime because of (a) performance and (b) big ABI incompatibilities. There's nothing in the language itself that stops them.
- lisper 2y ago> on pain of UB But this is exactly the problem. UB can be anything, including nothing. This should be at the very least an optional warning. But here is what happens with a fairly current C compiler: % gcc -v Apple clang version 14.0.0 (clang-1400.0.29.202) ... % more test.c int main () { int x[10]; return *(x+20); } % gcc -Wall test.c %
- fweimer 2y agoThese kinds of warnings need optimizations enabled. $ gcc -O2 -Wall -c t.c t.c: In function ‘main’: t.c:3:14: warning: array subscript 20 is outside array bounds of ‘int[10]’ [-Warray-bounds] 3 | return *(x+20); | ^~~~~~~ t.c:2:11: note: at offset 80 into object ‘x’ of size 40 2 | int x[10]; | ^ Not sure how to get Clang to warn. It clearly recognizes the undefined behavior.
- dzaima 2y agoClang appears to have -Warray-bounds-pointer-arithmetic for this, though not enabled on -Wall nor -Wextra. (fwiw, clang has -Weverything to turn on literally every warning, including conflicting ones, for finding what flags there are)
- lisper 2y agoYeah, Clang warns on x[20] but not *(x+20) even with -Wall and -O2. It's kinda weird.
- dzaima 2y agoAh, the -Warray-bounds-pointer-arithmetic warning is actually just about the pointer addition; thus even that doesn't warn on *(x+10) on the 10-element array, as the construction of the past-the-end pointer is still valid, and seemingly no warning checks bounds validity for actual dereference.
- LegionMammal978 2y agoYou can also make it throw an error at runtime: $ gcc -fsanitize=undefined -o test test.c $ ./test test.c:3:10: runtime error: load of address 0x7ffea07fded0 with insufficient space for an object of type 'int' 0x7ffea07fded0: note: pointer points here b2 55 00 00 d8 df 7f a0 01 00 00 00 c8 df 7f a0 fe 7f 00 00 00 00 00 00 00 00 00 00 62 0f 73 ea ^ > But this is exactly the problem. UB can be anything, including nothing. There's nothing stopping compilers from implementing the semantics you want (when not crossing an ABI boundary), and indeed, they've been adding more gradual hardening options that can be used in production. It's just that there's little demand for universal bounds-checking on arrays, and some users even want more flexible accesses, e.g., for operations like container_of. On the other hand, people can and have made experimental forks of the Rust compiler to turn all panics into immediate LLVM-level UB, but the mere existence of such an option doesn't mean that Rust's bounds-checking is now worthless, as you seem to be implying for C.