C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Error on out-of-bounds index, and syntax for conversion

From: Levo D <levoplusplus_at_[hidden]>
Date: Sat, 23 Aug 2025 22:25:42 +0000
On Sat, Aug 23, 2025 at 09:47:14AM +0100, Jonathan Wakely wrote:
> On Fri, 22 Aug 2025, 21:04 Levo D via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
> > I'd be happy to work on this proposal with others.
> >
> > This document is about bound-checking on arrays, not containers,
> > which can be added in the future after a successful implementation.
> >
> > If we look at the following program, we'll notice several problems.
> > Comments will explicitly explain them.
> > The two biggest issues are
> > 1) no easy way to convert a large array into a smaller array
> > 2) Compilers don't need to error when the size is known and a
> > literal index is outside of it
> >
> > #include <cstddef>
> >
> > void test16(char (&arr)[16]) { arr[15] = 0x12; }
> > void test32(char (&arr)[32]) { arr[31] = 0x34; }
> >
> > // Sanitizers won't catch this if you change 257 to 255
> > void test256(char (&arr)[256]) { arr[257] = 0x56; }
> >
>
> Is your comment backwards? Do you mean sanitizers don't catch it if you
> accidentally write past the end of the array? I disagree, and compilers can
> warn about the index being out of bounds.

Not backwards. Changing the 257 to 255 has no errors from a sanitizer, but I would prefer if someone else could confirm.

> prog.cc: In function 'void test256(char (&)[256])':
> prog.cc:7:41: warning: array subscript 257 is above array bounds of 'char
> [256]' [-Warray-bounds=]
> 7 | void test256(char (&arr)[256]) { arr[257] = 0x56; }
> | ~~~~~~~^
> prog.cc:7:21: note: while referencing 'arr'
> 7 | void test256(char (&arr)[256]) { arr[257] = 0x56; }
> | ~~~~~~~^~~~~~~~~
>
> You can is -Werror=array-bounds to get the error you want.

That works on clang, I get nothing from gcc, until I pass -O2 like the other reply mentioned.

> > template <size_t N> void testN(char (&arr)[N]) {
> > //test16(arr); // error because size is not exact
> > test32(arr); // exact, compiles
> > // Typecasting is bad, as we know
> > test16(reinterpret_cast<char (&)[16]>(arr)); // compiles
> >
>
> So don't do this, it's obviously wrong and should never be used.
>
> test256(reinterpret_cast<char (&)[256]>(arr)); // compiles and will
> > overwrite memory
> >
>
> Same here.
>
> }
> >
> > int main() {
> > char buf[32]{};
> > testN(buf); // two problems, 32 is smaller than 256 and
> > // test256 writes to 257, which is clearly out of range
> > // the below doesn't cause a warning (or error) in some compilers
> > buf[-1] = 0x78;
>
>
> I'm not sure why GCC doesn't warn here, probably because it's just silly
> code that nobody writes.

When I hit bounds errors (including other languages) it's usually when upgrading libraries or refactoring code, people will expect a number to always be the same, and it breaks when that changes.
 
> ubsan catches it:
>
> prog.cc:22:15: runtime error: index -1 out of bounds for type 'char [32]'
>
>
>
> > // I much rather the previous line be written as
> > *(buf-1) = 0x78;
> > }
> >
> >
> > By having 'arr[257]' and 'buf[-1]' become an error, obvious mistakes will
> > be caught immediately.
> >
>
> They're both undefined and can be diagnosed at compile time, including by
> failure to compile the code.

Received on 2025-08-23 22:25:47