Вы читаете свой журнал

  • Cвежие комментарии
  • Управление записями
  • Календарь

Оживший юзерпик - Хихикс

Авг. 30, 2012

06:49 pm - Хихикс

Previous Entry Редактировать запись Редактировать метки В избранное Поделиться Отслеживать Next Entry

Что напечатает эта программа? При каких условиях? Почему? :)

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

Настроение: gigglygiggly

Comments:

[User Picture]
From:vitus_wagner
Date:30 Август 2012 18:51 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Интересно, а компиляторы уже научились to optimize out такие вещи как foo()?
(Ответить) (Thread)
[User Picture]
From:_slw
Date:30 Август 2012 18:52 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
да
(Ответить) (Parent) (Thread)
[User Picture]
From:shaman007* — Андрей Бондаренко
Date:30 Август 2012 19:02 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
[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 ~]#
(Ответить) (Parent) (Thread)
[User Picture]
From:vitus_wagner
Date:30 Август 2012 21:16 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
А зачем gcc без параметров в начале? Может gcc --version имелось в виду?
(Ответить) (Parent) (Thread)
[User Picture]
From:shaman007* — Андрей Бондаренко
Date:31 Август 2012 00:28 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Это просто я хост с gcc искал. Вышел LOR.
(Ответить) (Parent) (Thread)
[User Picture]
From:alexott
Date:30 Август 2012 21:12 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
я один раз чуть не сошел с ума, пытаясь понять почему у меня в test case memchr не вызывается - поскольку я ничего не делал с его результатом, то компилятор просто выкинул соответствующий вызов :-)
(Ответить) (Parent) (Thread)
[User Picture]
From:_slw
Date:30 Август 2012 18:52 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
в зависимости от компилятора, ключей оптимизации и ос -- что угодно.
но может [не]повезти и напечатает 42
(Ответить) (Thread)
[User Picture]
From:maksa
Date:30 Август 2012 18:54 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Похоже, что-то сугубо практическое спрашивается. Видимо, ответ зависит от компилятора. Да?

Edited at 2012-08-30 18:55 (local)
(Ответить) (Thread)
[User Picture]
From:tobotras
Date:31 Август 2012 06:49 (местное)
Edit Удалить Скрыть Заморозить Track This
(Link)
Сугубо :)

http://tobotras.livejournal.com/580866.html?thread=8457730#t8457730 :)
(Ответить) (Parent) (Thread)
[User Picture]
From:shaman007* — Андрей Бондаренко
Date:30 Август 2012 19:01 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Есть вероятность, что 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 at 2012-08-30 19:03 (local)
(Ответить) (Thread)
[User Picture]
From:caml_programmer
Date:30 Август 2012 19:05 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
gcc -O0 - 42
gcc -O1 - 0
gcc -O2 - 0
(Ответить) (Thread)
[User Picture]
From:norian
Date:30 Август 2012 19:08 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
а если

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

?
(Ответить) (Thread)
[User Picture]
From:tobotras
Date:31 Август 2012 06:43 (местное)
Edit Удалить Скрыть Заморозить Track This
(Link)
Думаю, будет 42. bar() же верх стек-фрейма переиспользует, что там ниже, неважно.
(Ответить) (Parent) (Thread)
[User Picture]
From:k001
Date:5 Сентябрь 2012 03:38 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Пытаюсь вспомнить, кажется, в IA64 стек растёт вверх, а не вниз. Впрочем, то же самое будет.
(Ответить) (Parent) (Thread)
[User Picture]
From:tarkhil
Date:30 Август 2012 19:13 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Как уже отметили - в зависимости от компилятора, ОС и защиты стека - все, что угодно, включая fatal exception...
(Ответить) (Thread)
[User Picture]
From:bish0nen
Date:31 Август 2012 04:33 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Не зависит ни от компилятора, ни от ОС, ни от защиты стека. Зависит от оптимизатора или отсутствия оптимизационного прохода.
(Ответить) (Parent) (Thread)
[User Picture]
From:dz
Date:31 Август 2012 07:59 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
от компилятора, очевидно, зависит. eax обязателен для возврата значения, но вот выделять регистры под темпы можно начиная хоть с edi.
(Ответить) (Parent) (Thread)
[User Picture]
From:bish0nen
Date:31 Август 2012 09:34 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Зависит, скорее, от ABI, а компилятор энфорсит какой-то определённый ABI или позволяет выбирать из нескольких. Ничто не запрещает мне вернуть значение(-я) на стеке, регистры используются только потому, что к ним быстрее доступаться.
(Ответить) (Parent) (Thread)
[User Picture]
From:tarkhil
Date:31 Август 2012 08:04 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Всякие штуки с зачисткой стека по возврату из функции мне приглючились?
(Ответить) (Parent) (Thread)
[User Picture]
From:bish0nen
Date:31 Август 2012 09:39 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Куда они денутся-то. Только возвращаемое значение можно и на верхушку стека положить - как ABI велит - а потом и почистить стек, включая возвращённое значение.
(Ответить) (Parent) (Thread)
[User Picture]
From:tobotras
Date:31 Август 2012 11:26 (местное)
Edit Удалить Скрыть Заморозить Track This
(Link)
Однозначно. Это ж какой оверхед.
(Ответить) (Parent) (Thread)
[User Picture]
From:dibr
Date:30 Август 2012 19:16 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Да что угодно в принципе, вплоть до фрагмента рутового пароля к серверу пентагона (если перед этим на этом компьютере сотрудник пентагона отсылал пароль по электронной почте коллеге, а ОС или рантайм не очищают память перед запуском задачи) :-)
С максимумами распределения на "42" (автоматические переменные без явного указания не инициализируются, выделяются в одном и том же месте, например в стеке, и это "место" совпало для a и b), и нуле (если автоматические переменные по умолчанию зануляются, или a и b оказались в разных местах, при этом b попало на заранее очищенную область).
(Ответить) (Thread)
[User Picture]
From:tobotras
Date:31 Август 2012 06:48 (местное)
Edit Удалить Скрыть Заморозить Track This
(Link)
Покажешь мне реализацию С, где автоматические переменные обнуляются? ;-)
(Ответить) (Parent) (Thread)
[User Picture]
From:dz
Date:31 Август 2012 07:58 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
посмотри неинтеловские calling conventions и распределения регистров - есть процессоры, в которых возврат и временные хранятся в разных регистрах. там не сработает.

только всё это - дрочилово на устаревшие технологии.
если пишешь на си - не допускай чужого бинарного кода, вообще.
(Ответить) (Parent) (Thread)
[User Picture]
From:dibr
Date:31 Август 2012 13:49 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Навскидку не покажу, но думаю, такие существуют - реализаций языка Си очень много, где-то это может оказаться особенностью архитектуры, где-то - внутренними требованиями по безопасности (почему нет), где-то - предельно упрощённый компилятор, на всякий случай инициализирующий всё...
(Ответить) (Parent) (Thread)
[User Picture]
From:yurvor
Date:30 Август 2012 20:21 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
И ведь 42-то тут неспроста... Ох неспроста :)
(Ответить) (Thread)
[User Picture]
From:tobotras
Date:31 Август 2012 06:48 (местное)
Edit Удалить Скрыть Заморозить Track This
(Link)
Конечно, неспроста. Это — мой возраст! Почти :)
(Ответить) (Parent) (Thread)
[User Picture]
From:anka_sergevna
Date:1 Сентябрь 2012 23:06 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
а так же ответ на все остальные вопросы )
(Ответить) (Parent) (Thread)
[User Picture]
From:votez
Date:31 Август 2012 00:14 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
а должно написать "криворукий программист, учи си шарп и не претендуй!". Если не пишет - нужен патч. Во все компиляторы под все платформы.
(Ответить) (Thread)
[User Picture]
From:dz
Date:31 Август 2012 07:52 (местное)
Удалить Spam Скрыть Заморозить Track This
(Link)
Вообще бы она должна напечатать "не занимайтесь хуйнёй и не используйте ЯП, которые культивируют занятия хуйнёй", но, к сожалению, в зависимости от процессора, оптимизации и calling convention она может напечатать много разнообразного мусора из разных регистров и мест стека.

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

И т.п.

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

(Ответить) (Thread)
[User Picture]
From:dil
Date:2 Сентябрь 2012 16:24 (местное)
Удалить Spam Раскрыть Заморозить Track This
(Link)
Попробовал gcc на mipsel, там без оптимизации тоже получается 42, с оптимизацией - 0.
(Unscreen to reply) (Parent) (Thread)
[User Picture]
From:livejournal
Date:2 Сентябрь 2012 13:44 (местное)
Удалить Spam Раскрыть Заморозить Track This

Боре Тоботрасу, ответ на вопрос

(Link)
Пользователь dinozavr сослался на вашу запись в «Боре Тоботрасу, ответ на вопрос» в контексте: [...] вопрос: http://tobotras.livejournal.com/580866.html [...]
(Unscreen to reply) (Thread)
[User Picture]
From:dil
Date:2 Сентябрь 2012 15:19 (местное)
Удалить Spam Раскрыть Заморозить Track This
(Link)
Как уже сказано выше, она может напечатать что угодно. В частности, и 42, но никто не обещал.

$ gcc -O a.c
$ ./a.out
0

(Unscreen to reply) (Thread)
[User Picture]
From:livejournal
Date:3 Сентябрь 2012 15:45 (местное)
Удалить Spam Раскрыть Заморозить Track This

А вот любопытная задачка

(Link)
Пользователь dil сослался на вашу запись в «А вот любопытная задачка» в контексте: [...] по мотивам http://tobotras.livejournal.com/580866.html [...]
(Unscreen to reply) (Thread)
[User Picture]
From:dinozavr
Date:4 Сентябрь 2012 11:30 (местное)
Удалить Spam Скрыть Заморозить Track This

42 и 43

(Link)
К вопросу о правильном ответе: наши корреспонденты из Ирландии сообщают, что 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

Век живи - век учись!
(Ответить) (Thread)

Mass Action

Групповое действие над комментариями: