GCC warning for unintended pointer arithmetic on string literals

147 views Asked by At

With the constant chopping and changing back and forth between different languages, every now and then I find myself trying to write fragments of Python or JS syntax in C/C++.

One that's caught me out more than once is trying to append a number to a string literal with a + operator:

foo(const char*);

foo("the number is " + 6);

Which happily compiles to pass a char* pointer to the string "mber is " into my function. Even more fun, if I write:

foo("the number is " + 20);

Is anyone aware of a warning option that can catch this?

2

There are 2 answers

0
user17732522 On BEST ANSWER

GCC does warn about the out-of-bound pointer arithmetic as one would expect, via the -Warray-bounds warning that is included in -Wall. However optimizations need to be enabled for this to work, e.g. with the options -Wall -O2 GCC 13 produces:

<source>:4:45: warning: array subscript 20 is outside array bounds of 'const char [15]' [-Warray-bounds=]
    4 |     some_function_that_takes_a_const_chr_ptr("the number is " + 20);
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~

For the in-bounds case Clang has a -Wstring-plus-int warning, but GCC currently does not have an equivalent.

A patch to implement an equivalent was submitted in 2017, but seems to have never proceeded further.

5
Eric Postpischil On

Because macro replacement will not replace a macro found in its own replacement, you can interpose a macro in a function call. Consider this macro:

#define foo(argument)   foo(*&(argument))

If argument is the array of a string literal, we can take its address with &, and then the dereference with * produces the array, after which the usual array-to-pointer conversion occurs, and the function foo is called.

if argument is a string literal plus an integer, then array-to-pointer conversion occurs before & applies, so the operand of & is an rvalue, not an lvalue, and the compiler will complain.

Thus we have:

#include <stdio.h>


void foo(const char *x)
{
    printf("I am happy.\n");
}


#define foo(argument)   foo(*&(argument))


int main(void)
{
    foo("the number is ");      // This will compile without complaint.
    foo("the number is " + 6);  // This will get an error.
}