tobotras: (emacs)
[personal profile] tobotras
Что напечатает эта программа? При каких условиях? Почему? :)

#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 );
}

Date: 2012-08-30 02:51 pm (UTC)
vitus_wagner: My photo 2005 (white)
From: [personal profile] vitus_wagner
Интересно, а компиляторы уже научились to optimize out такие вещи как foo()?

Date: 2012-08-30 03:02 pm (UTC)
From: [identity profile] shaman007.livejournal.com
[root@localhost ~]# gcc
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 ~]#

Date: 2012-08-30 05:16 pm (UTC)
vitus_wagner: My photo 2005 (white)
From: [personal profile] vitus_wagner
А зачем gcc без параметров в начале? Может gcc --version имелось в виду?

Date: 2012-08-30 08:28 pm (UTC)
From: [identity profile] shaman007.livejournal.com
Это просто я хост с gcc искал. Вышел LOR.

Date: 2012-08-30 05:12 pm (UTC)
From: [identity profile] alexott.livejournal.com
я один раз чуть не сошел с ума, пытаясь понять почему у меня в test case memchr не вызывается - поскольку я ничего не делал с его результатом, то компилятор просто выкинул соответствующий вызов :-)

Date: 2012-08-30 02:52 pm (UTC)
From: [identity profile] http://users.livejournal.com/_slw/
в зависимости от компилятора, ключей оптимизации и ос -- что угодно.
но может [не]повезти и напечатает 42

Date: 2012-08-30 02:54 pm (UTC)
From: [identity profile] maksa.livejournal.com
Похоже, что-то сугубо практическое спрашивается. Видимо, ответ зависит от компилятора. Да?
Edited Date: 2012-08-30 02:55 pm (UTC)

Date: 2012-08-30 03:01 pm (UTC)
From: [identity profile] shaman007.livejournal.com
Есть вероятность, что 42.

Точнее, в случае с 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 Date: 2012-08-30 03:03 pm (UTC)

Date: 2012-08-30 03:05 pm (UTC)
From: [identity profile] caml-programmer.livejournal.com
gcc -O0 - 42
gcc -O1 - 0
gcc -O2 - 0

Date: 2012-08-30 03:08 pm (UTC)
From: [identity profile] norian.livejournal.com
а если

void foo( void )
{
int a = 42;
int b = 43;
}

?

Date: 2012-09-04 11:38 pm (UTC)
From: [identity profile] k001.livejournal.com
Пытаюсь вспомнить, кажется, в IA64 стек растёт вверх, а не вниз. Впрочем, то же самое будет.

Date: 2012-08-30 03:13 pm (UTC)
From: [identity profile] tarkhil.livejournal.com
Как уже отметили - в зависимости от компилятора, ОС и защиты стека - все, что угодно, включая fatal exception...

Date: 2012-08-31 12:33 am (UTC)
From: [identity profile] bish0nen.livejournal.com
Не зависит ни от компилятора, ни от ОС, ни от защиты стека. Зависит от оптимизатора или отсутствия оптимизационного прохода.

Date: 2012-08-31 03:59 am (UTC)
From: [identity profile] dz.livejournal.com
от компилятора, очевидно, зависит. eax обязателен для возврата значения, но вот выделять регистры под темпы можно начиная хоть с edi.

Date: 2012-08-31 05:34 am (UTC)
From: [identity profile] bish0nen.livejournal.com
Зависит, скорее, от ABI, а компилятор энфорсит какой-то определённый ABI или позволяет выбирать из нескольких. Ничто не запрещает мне вернуть значение(-я) на стеке, регистры используются только потому, что к ним быстрее доступаться.

Date: 2012-08-31 04:04 am (UTC)
From: [identity profile] tarkhil.livejournal.com
Всякие штуки с зачисткой стека по возврату из функции мне приглючились?

Date: 2012-08-31 05:39 am (UTC)
From: [identity profile] bish0nen.livejournal.com
Куда они денутся-то. Только возвращаемое значение можно и на верхушку стека положить - как ABI велит - а потом и почистить стек, включая возвращённое значение.

Date: 2012-08-30 03:16 pm (UTC)
From: [identity profile] dibr.livejournal.com
Да что угодно в принципе, вплоть до фрагмента рутового пароля к серверу пентагона (если перед этим на этом компьютере сотрудник пентагона отсылал пароль по электронной почте коллеге, а ОС или рантайм не очищают память перед запуском задачи) :-)
С максимумами распределения на "42" (автоматические переменные без явного указания не инициализируются, выделяются в одном и том же месте, например в стеке, и это "место" совпало для a и b), и нуле (если автоматические переменные по умолчанию зануляются, или a и b оказались в разных местах, при этом b попало на заранее очищенную область).

Date: 2012-08-31 03:58 am (UTC)
From: [identity profile] dz.livejournal.com
посмотри неинтеловские calling conventions и распределения регистров - есть процессоры, в которых возврат и временные хранятся в разных регистрах. там не сработает.

только всё это - дрочилово на устаревшие технологии.
если пишешь на си - не допускай чужого бинарного кода, вообще.

Date: 2012-08-31 09:49 am (UTC)
From: [identity profile] dibr.livejournal.com
Навскидку не покажу, но думаю, такие существуют - реализаций языка Си очень много, где-то это может оказаться особенностью архитектуры, где-то - внутренними требованиями по безопасности (почему нет), где-то - предельно упрощённый компилятор, на всякий случай инициализирующий всё...

Date: 2012-08-30 04:21 pm (UTC)
From: [identity profile] yurvor.livejournal.com
И ведь 42-то тут неспроста... Ох неспроста :)

Date: 2012-09-01 07:06 pm (UTC)
From: [identity profile] anka-sergevna.livejournal.com
а так же ответ на все остальные вопросы )

Date: 2012-08-30 08:14 pm (UTC)
From: [identity profile] votez.livejournal.com
а должно написать "криворукий программист, учи си шарп и не претендуй!". Если не пишет - нужен патч. Во все компиляторы под все платформы.

Date: 2012-08-31 03:52 am (UTC)
From: [identity profile] dz.livejournal.com
Вообще бы она должна напечатать "не занимайтесь хуйнёй и не используйте ЯП, которые культивируют занятия хуйнёй", но, к сожалению, в зависимости от процессора, оптимизации и calling convention она может напечатать много разнообразного мусора из разных регистров и мест стека.

- присваивание может быть выкинуто оптимайзером вообще.
- любая функция может быть заинлайнена, и тогда, возможно, компайлер выделит разные регистры.
- для временных переменных и для возврата могут быть запланированы разные регистры.

И т.п.

На x86 вполне может и 42 принтануть, если компайлер выделит eax для переменной в foo.

42 и 43

Date: 2012-09-04 07:30 am (UTC)
From: [identity profile] dinozavr.livejournal.com
К вопросу о правильном ответе: наши корреспонденты из Ирландии сообщают, что gcc не так прост

http://dinozavr.dreamwidth.org/2377677.html?view=6728653&posted=1#cmt6728653

Они размещают локальные переменные в стеке в разном порядке. Так что этот пример гораздо занимательнее, чем оригинальный, надо его туда запостить :)

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

Век живи - век учись!

Profile

tobotras: (Default)
tobotras

December 2024

S M T W T F S
123 4567
891011121314
15161718192021
22232425262728
293031    

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Feb. 14th, 2026 05:34 am
Powered by Dreamwidth Studios