LINUX.ORG.RU

Защита от дурака в gcc?

 ,


0

2

По мотивам срача, где stevejobs предложил пример того, почему const не даёт никаких гарантий.

Я заметил такое поведение у себя:

#include <cstdio>
#include <cassert>

int main() {
    const int three = 3;
    printf( "three=%d\n", three );

    int *ptr;
    ptr = (int *)( &three );
    *ptr = 5;

    printf( "three=%d\n", three);
    assert(three == 3);

}

Выхлоп:

$ g++-4.7 -Wall -Wextra -O0 test.cpp -o test
$ ./test
three=3
three=3

При этом в отладчике:

(gdb) b 8
Breakpoint 1 at 0x4006ff: file test.cpp, line 8.
(gdb) r
Starting program: /home/del/test/const/test 
three=3

Breakpoint 1, main () at test.cpp:9
9	    ptr = (int *)( &three );
(gdb) p three
$1 = 3
(gdb) p &three
$2 = (const int *) 0x7fffffffe2d4
(gdb) n
10	    *ptr = 5;
(gdb) p ptr
$3 = (int *) 0x7fffffffe2d4
(gdb) n
12	    printf( "three=%d\n", three);
(gdb) p *ptr
$4 = 5
(gdb) p three
$5 = 5
(gdb) n
three=3

Что собственно происходит? Почему (судя по gdb) по адресу 0x7fffffffe2d4 лежит 5, и three == 5, но printf выводит 3, и не срабатывает assert() ?

Если убрать 'const', то всё нормально и никаких аномалий нету.

Тестировал на gcc 4.2, 4.6 и 4.7.

PS вообще C-style cast'ы зло, static_cast<> тут законно ругнётся.

☆☆☆☆☆
Ответ на: комментарий от stevejobs

Т.к. возможность «не пользоваться» может привести к WTF, все такие операции должны находиться под прагмой или именованным блоком кода UNSAFE_MEMORY.

У меня есть ощущение, что ты не понимаешь смысла плюсов. При всех своих возможностях, в корне это всё равно низкоуровневый язык.
Низкоуровневый тем, что когда ты пишешь «a + b» над стандартными типами, ты можешь быть уверен, что это будет ровно одно сложение, а не двадцать инструкций с условным переходом к рантайму. И это фича.

Причина вовсе не в совместимости.

intelfx ★★★★★
()
Ответ на: комментарий от intelfx

ты можешь быть уверен, что это будет ровно одно сложение

ты знаешь, какой код получится после O3? Уверен что там вообще будет какое-то сложение?

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от intelfx

ты можешь быть уверен, что это будет ровно одно сложение, а не двадцать инструкций с условным переходом к рантайму

всё равно все эти проверки придется писать руками. Если их не накодить, любой мимокрокодил сломает тебе весь код в хлам первым же патчем. Можно сэкономить время кодера и строчки кода (на нормальную ручную проверку всего на свете уходит тонна строчек кода). Зафигачить их прямо в компилятор — опционально. Не хочешь юзать это — ставишь прагму/небезопасный блок, и кодишь любое небезопасное говно какое пожелаешь.

stevejobs ★★★★☆
()
Ответ на: комментарий от stevejobs

После -O3? Точно не знаю. Но это будет или сложение, или что-то дешевле.

intelfx ★★★★★
()
Ответ на: комментарий от stevejobs

Мы говорим о проверках на константность переменной. Чтобы сломать код без таковых, нужно быть очень квалифицированным крокодилом.

Что-то содержательное компилятор не сможет самостоятельно проверить, а что-то простое (вроде указателей) проверять обычно нет надобности. Всё равно проверку сделает MMU процессора, и если она будет неудачной, результат в обоих случаях будет один и тот же: аварийное завершение работы программы.

intelfx ★★★★★
()

А ты попробуй использовать gcc, а не g++. Поменяется на 5.

dvl36
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.