UB explanation when data changes

I tried to demonstrate to a working friend that you can change the value of a variable with constant qualification if it really wants (and knows how), using some tricks, during my demonstration I found that there are two "flavors" of constant values: those that you cannot change, no matter what you do, and those that you can change using dirty tricks.

A constant value is invariable when the compiler uses the value of a literal value instead of the value stored on the stack (read here ), here is a piece of code that shows what I mean:

// TEST 1
#define LOG(index, cv, ncv) std::cout \
    << std::dec << index << ".- Address = " \
    << std::hex << &cv << "\tValue = " << cv << '\n' \
    << std::dec << index << ".- Address = " \
    << std::hex << &ncv << "\tValue = " << ncv << '\n'

const unsigned int const_value = 0xcafe01e;

// Try with no-const reference
unsigned int &no_const_ref = const_cast<unsigned int &>(const_value);
no_const_ref = 0xfabada;
LOG(1, const_value, no_const_ref);

// Try with no-const pointer
unsigned int *no_const_ptr = const_cast<unsigned int *>(&const_value);
*no_const_ptr = 0xb0bada;
LOG(2, const_value, (*no_const_ptr));

// Try with c-style cast
no_const_ptr = (unsigned int *)&const_value;
*no_const_ptr = 0xdeda1;
LOG(3, const_value, (*no_const_ptr));

// Try with memcpy
unsigned int brute_force = 0xba51c;
std::memcpy(no_const_ptr, &brute_force, sizeof(const_value));
LOG(4, const_value, (*no_const_ptr));

// Try with union
union bad_idea
{
    const unsigned int *const_ptr;
    unsigned int *no_const_ptr;
} u;

u.const_ptr = &const_value;
*u.no_const_ptr = 0xbeb1da;
LOG(5, const_value, (*u.no_const_ptr));

This leads to the following conclusion:

1.- Address = 0xbfffbe2c    Value = cafe01e
1.- Address = 0xbfffbe2c    Value = fabada
2.- Address = 0xbfffbe2c    Value = cafe01e
2.- Address = 0xbfffbe2c    Value = b0bada
3.- Address = 0xbfffbe2c    Value = cafe01e
3.- Address = 0xbfffbe2c    Value = deda1
4.- Address = 0xbfffbe2c    Value = cafe01e
4.- Address = 0xbfffbe2c    Value = ba51c
5.- Address = 0xbfffbe2c    Value = cafe01e
5.- Address = 0xbfffbe2c    Value = beb1da

UB ( const), , ; , .

, , , ( , memcpy ing), , ( undefined). , , :

  • , ?

AFAIK , :

  • ? ( )?

, , ( ):

// TEST 2
// Try with no-const reference
void change_with_no_const_ref(const unsigned int &const_value)
{
    unsigned int &no_const_ref = const_cast<unsigned int &>(const_value);
    no_const_ref = 0xfabada;
    LOG(1, const_value, no_const_ref);    
}

// Try with no-const pointer
void change_with_no_const_ptr(const unsigned int &const_value)
{
    unsigned int *no_const_ptr = const_cast<unsigned int *>(&const_value);
    *no_const_ptr = 0xb0bada;
    LOG(2, const_value, (*no_const_ptr));
}

// Try with c-style cast
void change_with_cstyle_cast(const unsigned int &const_value)
{
    unsigned int *no_const_ptr = (unsigned int *)&const_value;
    *no_const_ptr = 0xdeda1;
    LOG(3, const_value, (*no_const_ptr));
}

// Try with memcpy
void change_with_memcpy(const unsigned int &const_value)
{
    unsigned int *no_const_ptr = const_cast<unsigned int *>(&const_value);
    unsigned int brute_force = 0xba51c;
    std::memcpy(no_const_ptr, &brute_force, sizeof(const_value));
    LOG(4, const_value, (*no_const_ptr));
}

void change_with_union(const unsigned int &const_value)
{
    // Try with union
    union bad_idea
    {
        const unsigned int *const_ptr;
        unsigned int *no_const_ptr;
    } u;

    u.const_ptr = &const_value;
    *u.no_const_ptr = 0xbeb1da;
    LOG(5, const_value, (*u.no_const_ptr));
}

int main(int argc, char **argv)
{
    unsigned int value = 0xcafe01e;
    change_with_no_const_ref(value);
    change_with_no_const_ptr(value);
    change_with_cstyle_cast(value);
    change_with_memcpy(value);
    change_with_union(value);

    return 0;
}

:

1.- Address = 0xbff0f5dc    Value = fabada
1.- Address = 0xbff0f5dc    Value = fabada
2.- Address = 0xbff0f5dc    Value = b0bada
2.- Address = 0xbff0f5dc    Value = b0bada
3.- Address = 0xbff0f5dc    Value = deda1
3.- Address = 0xbff0f5dc    Value = deda1
4.- Address = 0xbff0f5dc    Value = ba51c
4.- Address = 0xbff0f5dc    Value = ba51c
5.- Address = 0xbff0f5dc    Value = beb1da
5.- Address = 0xbff0f5dc    Value = beb1da

, const change_with_*, , , , , const .

, , , unsigned int value main const unsigned int value:

// TEST 3
const unsigned int value = 0xcafe01e;
change_with_no_const_ref(value);
change_with_no_const_ptr(value);
change_with_cstyle_cast(value);
change_with_memcpy(value);
change_with_union(value);

, , TEST 2 ( ), , - , :

  • , const ?

, :

  • TEST 1.
    • const no-const , ?
    • ? ( )?
  • TEST 3
    • , const ?
0
1

, Undefined, , .

, , . , const, , const ( ), , , .

, , const, Undefined Behavior , Undefined.

, TEST 1 , , , , (), , . TEST 2 TEST 3 , 100% , ( TEST 2, ).

+2

All Articles