D does not decay arrays, so D has array bounds checking.
Note that array overflow bugs are consistently the #1 problem with shipped C code, by a wide margin.
This isn’t strictly true, a C implementation is allowed to associate memory-range (or more generally, pointer provenance) metadata with a pointer.
The DeathStation 9000 features a conforming C implementation which is known to catch all array bounds violations. ;)
int main() {
int a[3];
return foo(a);
}
> gcc test.c
> ./a.out
Oops.D: int foo(int[] a) { return a[5]; }
int main() {
int[3] a;
return foo(a);
}
> ./cc array.d
> ./array
core.exception.ArrayIndexError@array.d(1): index [5] is out of bounds for array of length 3
Ah, Nirvana!How to fix it for C:
That actually really does exist already with CHERI CPUs, whose pointers are tagged with "capabilities," which catch buffer overruns at runtime.
https://tratt.net/laurie/blog/2023/two_stories_for_what_is_c...
https://msrc.microsoft.com/blog/2022/01/an_armful_of_cheris/
I personally find that googling stuff provides not much connection to the subject of study, very impersonal and try to avoid it.
For example I did google the concept, and found this https://github.com/cousteaulecommandant/ds9k.
Which is not trivial to parse, bing posited the answer as authoritative, and if you look at the code it is really nothing, it seems to be a folklore concept, and as such, it is much more aptly transmitted by speaking to a human and getting a live version than by googling an authoratitative static answer.
int foo(int (*a)[6]) { return a[5]; }
int main() {
int a[3];
return foo(&a);
}
Or for run-time length: int foo(int n, int (*a)[n]) { return (\*a)[5]; }
int main() {
int a[3];
return foo(ARRAY_SIZE(a), &a);
}
/app/example.c:4:38: runtime error: index 5 out of bounds for
type 'int[n]'
https://godbolt.org/z/dxx7TsKbK\* int foo(int n, int (*a)[n]) { return (\*a)[5]; }
int main() {
int a[3];
return foo(ARRAY_SIZE(a), &a);
}
That syntax is why array overflows remain the #1 problem with C bugs in shipped code. It isn't any better than: int foo(size_t n, int* a) { assert(5 < n); return a[5]; }
int main() {
int a[3];
return foo(ARRAY_SIZE(a), a);
}
as the array dimension has to be handled separately from the pointer.Contrast with how simple it is in D:
int foo(int[] a) { return a[5]; }
int main() {
int[3] a;
return foo(a);
}
and the proof is shown by array overflow bugs in the wild are stopped cold. It can be that simple and effective in C.