Оживший юзерпик - Хихикс
Авг. 30, 2012
06:49 pm - Хихикс
Что напечатает эта программа? При каких условиях? Почему? :)
#include <stdio.h> void foo( void ) { int a = 42; } int bar( void ) { int b; return b; } void main( void ) { int c; foo(); c = bar(); printf( "%d\n", c ); }
Настроение: giggly
Comments:
Mass Action
Групповое действие над комментариями:
gcc: не заданы входные файлы
[root@localhost ~]# vi 1.c
[root@localhost ~]# gcc 1.c
1.c: In function ‘main’:
1.c:15: предупреждение: return type of ‘main’ is not ‘int’
[root@localhost ~]# ./a.out
42
[root@localhost ~]# gcc -O3 ./1.c
./1.c: In function ‘main’:
./1.c:15: предупреждение: return type of ‘main’ is not ‘int’
[root@localhost ~]# ./a.out
-1081113660
[root@localhost ~]#
но может [не]повезти и напечатает 42
Edited at 2012-08-30 18:55 (local)
http://tobotras.livejournal.com/580
Точнее, в случае с gcc без оптимизации это будет 42, так как он выделил память ровно под 1 переменную, так как в каждый момент времени исполнения у нас есть только 1 инт, а что он каждый раз по-разному обозван, так это проблемы тех, но не инициализирует и не очищает память.
Кстати, такие уязвимости были в SSH, кажется.
Нотариально заверенный скриншот:
[root@localhost ~]# vi 1/c
[root@localhost ~]# vi 1.c
[root@localhost ~]# gcc 1.c
1.c: In function ‘main’:
1.c:15: предупреждение: return type of ‘main’ is not ‘int’
[root@localhost ~]# ./a.out
42
[root@localhost ~]# gcc -O3 ./1.c
./1.c: In function ‘main’:
./1.c:15: предупреждение: return type of ‘main’ is not ‘int’
[root@localhost ~]# ./a.out
-1081113660
[root@localhost ~]#
Edited at 2012-08-30 19:03 (local)
gcc -O1 - 0
gcc -O2 - 0
void foo( void )
{
int a = 42;
int b = 43;
}
?
С максимумами распределения на "42" (автоматические переменные без явного указания не инициализируются, выделяются в одном и том же месте, например в стеке, и это "место" совпало для a и b), и нуле (если автоматические переменные по умолчанию зануляются, или a и b оказались в разных местах, при этом b попало на заранее очищенную область).
только всё это - дрочилово на устаревшие технологии.
если пишешь на си - не допускай чужого бинарного кода, вообще.
- присваивание может быть выкинуто оптимайзером вообще.
- любая функция может быть заинлайнена, и тогда, возможно, компайлер выделит разные регистры.
- для временных переменных и для возврата могут быть запланированы разные регистры.
И т.п.
На x86 вполне может и 42 принтануть, если компайлер выделит eax для переменной в foo.
Боре Тоботрасу, ответ на вопрос
$ gcc -O a.c
$ ./a.out
0
А вот любопытная задачка
42 и 43
http://dinozavr.dreamwidth.org/2377
Они размещают локальные переменные в стеке в разном порядке. Так что этот пример гораздо занимательнее, чем оригинальный, надо его туда запостить :)
gcc 4.6.3 32bit:
foo:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $42, -8(%ebp)
movl $43, -4(%ebp)
leave
ret
gcc 4.4.5 64bit:
foo:
pushq %rbp
movq %rsp, %rbp
movl $42, -8(%rbp)
movl $43, -4(%rbp)
leave
ret
gcc 4.4.3 32bit:
foo:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $42, -4(%ebp)
movl $43, -8(%ebp)
leave
ret
Век живи - век учись!