Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Example of undefined behaviour involving the use of const_cast

For illustrative purposes, I have been trying to find an example, by using gcc, where the output of a program is different with and without optimization enabled (with and without -O3). The purpose of finding such example is to show how optimizations could make an apparently correct program behave different after optimizations have been active if the code contains undefined behaviour.

I have been trying different "combos" of the following program:

// I have tried defining blind in this and in a separate module. The result is the same.
void blind(int const* p) { ++*const_cast<int*>(p); }

#include <iostream>

int constant() { return 0; }

int main()
{
    int const p = constant();
    blind(&p);
    std::cout << p << std::endl;
    return 0; 
}

I was expecting that, without optimizations enabled, this program will show 1, but with optimizations enabled (-O3) it will show 0 (by replacing std::cout << p by std::cout << 0 directly), but that's not the case. If I replace the initialization by int const p = 0, it will print 0 with and without optimizations enabled, and so the behaviour is again the same.

I have tried different alternatives like doing arithmetic operations (expecting the compiler to prefer to "pre-compute" the value or something), calling blind several times, etc. But nothing works.

  • I would like to find a variation of the program above whose behaviour change when activating optimizations.
  • Or... another different example that could help to illustrate that optimizations can change the observable behaviour of a program if such program contains undefined behaviour.

NOTE: Preferably, one example where the program won't probably crash in the optimized version.

like image 439
Peregring-lk Avatar asked Dec 21 '25 09:12

Peregring-lk


1 Answers

Now may be my time to shine. I asked this question a while ago and it seems to perfectly demonstrate an example of what you are looking for in a very short/simple program, which I will include below for completeness:

#include <iostream>

int broken_for_loop(){
    for (int i = 0; i < 10000; i+= 1000){
        std::cout << i << std::endl;
    }
}

int main(int argc, char const *argv[]){
    broken_for_loop();
}

You can see the discussion/explanation there (long story short, I don't return from a function that should return an int), but I think it does a good job of demonstrating how some UB can be pretty sneaky in presenting itself only in optimized binaries if you're not thinking about it/paying attention to compiler warnings.

Adding in case it wasnt clear: When compiled without optimization, the program prints 0...9000 and then exits properly. When compiled with -O3 the loop runs forever.

Compiled with: g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0

like image 186
Douglas B Avatar answered Dec 24 '25 00:12

Douglas B



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!