?

Log in

для программистов, знающих язык це - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

для программистов, знающих язык це [мар. 3, 2008|11:28 pm]
Anatoly Vorobey
Загадка: написать самую краткую программу на C, которая компилируется, запускается и падает. Под "компилируется" будем для ясности понимать, что "gcc -o example example.c" ее компилирует без ошибок и предупреждений, и создает исполняемый файл example, который при исполнении падает.

Вариант: то же самое, но разрешаются предупреждения при компиляции.

Теперь ответы - это не я придумал, а рассказал Даг Ландауэр (Doug Landauer) во внутренней рассылке, копирую сюда с его разрешения. Поэтому если хотите свой вариант придумать, не заглядывайте под кат:



Вариант без предупреждений: "int main;"

Вариант с предупреждениями: "main;"
СсылкаОтветить

Comments:
[User Picture]From: ohtori
2008-03-03 09:44 pm

Сначала не заметил условие "самую краткую" и долго тормозил: в чём же сложность задачи?
(Ответить) (Thread)
[User Picture]From: avva
2008-03-03 09:52 pm
Сейчас подчеркну специально.
(Ответить) (Parent) (Thread)
[User Picture]From: motto
2008-03-03 09:46 pm

вообще, надо бы об опциях договориться

gcc -Wall test2.c
test2.c:1: warning: ‘main’ is usually a function
(это для первого варианта)
(Ответить) (Thread)
[User Picture]From: avva
2008-03-03 09:48 pm

Re: вообще, надо бы об опциях договориться

Я и договорился: специально написал, как именно вызывать gcc :)
(Ответить) (Parent) (Thread)
(Удалённый комментарий)
[User Picture]From: avva
2008-03-03 09:51 pm
Правда ведь? Я тоже офигел.
(Ответить) (Parent) (Thread)
[User Picture]From: malfet_
2008-03-03 09:53 pm
int main(void) { return *((int *)0)=17;}
(Ответить) (Thread)
[User Picture]From: make4um
2008-03-03 09:56 pm
альтернативный вариант: char main; ;o)))))
(Ответить) (Thread)
[User Picture]From: shabunc
2008-03-03 10:05 pm
он длиннее на целый символ )))
(Ответить) (Parent) (Thread)
[User Picture]From: make4um
2008-03-03 10:06 pm
а, да :( :о)
(Ответить) (Parent) (Thread)
[User Picture]From: malfet_
2008-03-03 09:58 pm

C warningом

int (*main)(void);
(Ответить) (Thread)
[User Picture]From: malfet_
2008-03-03 11:09 pm

Немного подумав

Вообще это решение, так же как и авторское зависит от реализации libc. Я полагаю что можно найти комбинацию из libc+архитектуры на которой подобное переопределение символа main не будет приводить к исключению..
(Ответить) (Parent) (Thread)
From: a7sharp9
2008-03-03 10:08 pm
Ответ можно, наверное, reverse-engineer из псевдокода (вылить воду из чайника и выключить газ), если сообразить, что достаточно записать в инструкцию типа jmp идиотский адрес, и вспомнить про entry point.
(Ответить) (Thread)
[User Picture]From: jsn
2008-03-03 10:36 pm
да-да. в досовские времена на 386+ код ребута можно было вместить в четыре байта. поэтому самый короткий reboot.c, который я писал, выглядел как main = 0xнепомнючто.
(Ответить) (Thread)
[User Picture]From: spamsink
2008-03-03 11:02 pm
Да, сейчас посложнее будет. (В линуксе) нужно перед собственно системным вызовом занести в SI значение 0x28121969 (да-да, это именно то, что вы подумали), а в DI - 0xFEElDEAD.
(Ответить) (Parent) (Thread)
[User Picture]From: pargentum
2008-03-04 03:06 am

Угу

И это короткий майн тянул за собой пару килобайт из ctr0.obj.
(Ответить) (Parent) (Thread)
[User Picture]From: itman
2008-03-03 10:54 pm
Ха-ха, остроумно, все мы знаем, что не слинкуется, если нет символа main. Нате вам, жрите символ main :-)
(Ответить) (Thread)
From: 9000
2008-03-03 11:01 pm
круто 8-)
(Ответить) (Thread)
[User Picture]From: zigmar
2008-03-03 11:15 pm
Придумать вариант не удалось, так как выяснилось что Reader автоматически показывает текст по катом :)
(Ответить) (Thread)
[User Picture]From: vashik
2008-03-03 11:30 pm
main(int argc,char **argv)
{
return *argv[argc];
}


Написал, вставил, и увидел первую строчку под катом.
До второй дошел сам. Спасибо, занимательно.
(Ответить) (Thread)
From: urbanserj
2008-03-03 11:33 pm
браво!

сам додумался только до main(){main();}
(Ответить) (Thread)
[User Picture]From: getman
2008-03-04 06:29 am
Компайлер ждет здесь символ main'а...
(Ответить) (Thread)
[User Picture]From: flaass
2008-03-04 07:20 am
А программа, подвешивающая gcc? Или таких уже не осталось?
(Ответить) (Thread)
From: oblomov_jerusal
2008-03-04 08:36 am
Если на C++ c темплэйтами, то, наверно, можно вполне легальным способом сделать переполнение стэка или ввести в бесконечный цикл?
(Ответить) (Parent) (Thread)
[User Picture]From: flaass
2008-03-04 03:26 pm
Тут я усомнился. Переполнение же не подвесит компилятор - он честно выйдет по ошибке при исполнении. А вот как бы устроить бесконечный цикл?
(Ответить) (Parent) (Thread)
From: oblomov_jerusal
2008-03-04 04:42 pm
У меня не получилось - выдает ошибку когда в попытках проделать инстанциацию темплэйта возникает цикл (класс опосредованно инстанциирует сам себя с теми же параметрами) компилятор выдает ошибку.
(Ответить) (Parent) (Thread)
[User Picture]From: flaass
2008-03-04 05:06 pm
В идеальном мире (в котором компилятор вычищен от всех багов) и не должно получиться никак :)
Может, как-нибудь зациклить компилятор при вычислении константы, которую он обязан вычислить сам?
(Ответить) (Parent) (Thread)
From: oblomov_jerusal
2008-03-04 06:42 pm
Мне казалось, темплэйты эквивалентны машине Тьюринга (так ли это?) и потому должны иметь проблему останова. Может, ограничение на глубину стека их спасает.
(Ответить) (Parent) (Thread)
From: oblomov_jerusal
2008-03-04 08:45 am
Попробовал - похоже, циклы она выясняет и стоит ограничение на глубину в 500 темплэйтов.
(Ответить) (Parent) (Thread)
From: oblomov_jerusal
2008-03-04 09:04 am

Большое дерево

template class A1;
template class A2;
template class A : public  A1, A2 {
};
template <> class A<0>{};
template class A1: public A {
};
template class A2: public A {
};
main(int argc, char **argv)
{
        A<16> a;
}

(Ответить) (Parent) (Thread)
[User Picture]From: flaass
2008-03-04 09:25 am

чтоб виднее было

template< const int N > class A1;
template< const int N > class A2;
template< const int N > class A : public A1< N-1 >, A2< N-1 > { };
template
<> class A<0>{};
template< const int N > class A1: public A< N > { };
template< const int N > class A2: public A< N > { }; main(int argc, char **argv)
{ A<16> a; }

(Ответить) (Parent) (Thread)
[User Picture]From: b0rg
2008-03-04 09:36 am
следующим постом будет задание написать маленькую программу на це, которая компилицца, запускаецца и...
и работает :)
(Ответить) (Thread)
[User Picture]From: ahaxopet
2008-03-04 10:12 am
Красиво, но эта программа не обязана упасть. В переменной main может лежать любое число, в том числе и (совершенно случайно) адрес какого-нибудь куска программы. Если очень повезет, эта программа даже сделает что-нибудь осмысленное :-)
(Ответить) (Thread)
[User Picture]From: plakhov
2008-03-04 10:24 am
В переменной main может лежать любое число

Не может, глобальные переменные гарантировано инициализируются даже в С++.
(Ответить) (Parent) (Thread)
[User Picture]From: ahaxopet
2008-03-04 10:32 am
Здесь вроде бы про C разговор шел. Не помню, что в стандарте на этот счет написано, но gcc точно ничего не инициализирует:

GCC has the ability to warn the user about using the value of a uninitialized variable. Such value is undefined ...
(Ответить) (Parent) (Thread)
[User Picture]From: ahaxopet
2008-03-04 11:01 am
Извиняюсь, это я не разобрался. Там про локальные переменные речь идет, хотя явно нигде это не сказано. А глобальные таки инициализируются нулем, согласен.
(Ответить) (Parent) (Thread)
[User Picture]From: plakhov
2008-03-04 11:09 am
Стандарт ANSI-C это гарантирует.
Я последний раз работал с gcc лет восемь назад, поэтому ручаться за него не стану, но все же отмечу, что по Вашей ссылке ничего не говорится о глобальных переменных (локальные-то и по стандарту не должны инициализироваться автоматически).
(Ответить) (Parent) (Thread)
From: laruldan
2008-03-04 07:25 pm
Верно. Но это неважно. Четыре нуля вполне могут быть вполне легальной инструкцией (на x86 - это addb %al,(%eax)/addb %al,(%eax) — шансы на падение велики, но не 100% ;-)), а остальное — зависит от того, что линкер/либс уложит после main. Так что, увы, но данное решение всё-таки непереносимо — может и не упасть.
(Ответить) (Parent) (Thread)
From: laruldan
2008-03-04 07:40 pm
ага, насчёт шансов на падение я даже просчитался — в main не упало, $eax на входе в main указывал куда-то на стек, добежало по нулям до конца странички и только там свалилось.
(Ответить) (Parent) (Thread)
[User Picture]From: goshen
2008-03-04 07:44 pm

main()
{
*((int *) 0)=0;
}

gcc4 отказывается компилировать 0[0]=0
(Ответить) (Thread)
[User Picture]From: goshen
2008-03-04 07:48 pm
правильный ответ мощный
(Ответить) (Parent) (Thread)
[User Picture]From: _winnie
2008-03-05 03:00 pm
E:\asdf>dir *.cpp
 Том в устройстве E имеет метку Новый том
 Серийный номер тома: 607E-527F

 Содержимое папки E:\asdf

05.03.2008  18:02                 0 empty.cpp
               1 файлов              0 байт
               0 папок  32 510 574 592 байт свободно

E:\asdf>g++ empty.cpp -c > out.exe

E:\asdf>out.exe
Отказано в доступе.
E:\asdf>

(Ответить) (Thread)
From: (Anonymous)
2008-03-06 09:48 pm
Можно сделать из одного символа и без предупреждений, но с очевидным читингом.
% cat > short.c
X^D
% gcc short.c -o short -DX="int main;"
%
(Ответить) (Thread)