Comment by mananaysiempre

5 hours ago

> Turns out, these two are equivalent in practice

Not in the x86-64 SysV ABI they aren’t. The arguments will be passed in registers (yes, even the variadic ones), so how your compiler will interpret 1[&a] is anybody’s guess. (For me, x86_64-unknown-linux-gnu-g++ -O2 yields, essentially, return a+a+a+a; which is certainly an interpretation. I’m also getting strange results from i686-unknown-linux-gnu-g++ -O2, but my x87 assembly is rusty enough that I don’t really get what’s going on there.)

> return a+a+a+a; which is certainly an interpretation.

Zero is the only valid index of &a, so I presume the compiler just assumes that all the indexes in 1[&a] + 2[&a] etc must be zero. Even though they're in this case compile-time constants – the optimizer could check but why bother given that it's UB anyway. I assume modern C/C++ compilers have some flag to diagnose indexing that's known to be OOB at compile time.

  • I’m so used to sticking -Wall in my compilation flags the moment I write a build script that I didn’t realize it wasn’t there for this quick experiment. Yes, thank you, there are indeed diagnostics once you ask for them:

      test.cpp: In function ‘double solve(double, ...)’:
      test.cpp:4:20: warning: array subscript 1 is outside array bounds of ‘double [1]’ [-Warray-bounds=]
          4 |     return a + 1[&a] + 2[&a] + 3[&a];
            |                ~~~~^
      test.cpp:3:58: note: at offset 8 into object ‘a’ of size 8
          3 | extern "C" __attribute__((noinline)) double solve(double a, ...) {
            |                                                   ~~~~~~~^
      [repeat twice more for the other two accesses]