LINUX.ORG.RU

Вызов никогда не вызываемой функции

 , ,


3

5

Ваши ставки, господа: насколько безопасно на своём компьютере запускать такую программу? Не сотрет ли она вам корень?

Люблю C++.

#include <cstdlib>

typedef int (*Function)();

static Function Do;

static int EraseAll() {
  return system("yes");
}

void NeverCalled() {
  Do = EraseAll;  
}

int main() {
  return Do();
}
★★☆☆☆
static Function Do;

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

tim239 ()

А в чём подвох? Увидят ли причину (Dо=0) по которой всё валится? Или всё таки имелось в виду, что Do указывает по умолчанию на hello world? Так и спрятать system в виде fork+exec и криптоформирование строк «/bin/rm» "-rf" «/» тоже можно хорошо.

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

ну так ведь NeverCalled никогда и не запишет в Do что-либо когда-либо, почему надо думать что может быть иначе?

и вообще, что за привычка ставить ржавый капкан и топтать его в надежде что захлопнется?

насколько безопасно на своём компьютере запускать такую программу

под юзверем не потрет, даже хомяк как мне кажется

I-Love-Microsoft ★★★★★ ()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)

мда...

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

что ему можно сказать тут? я даже не знаю. коварен С++.

ckotinko ★★☆ ()
Ответ на: комментарий от I-Love-Microsoft

ну так ведь NeverCalled никогда и не запишет в Do что-либо когда-либо

Ф-я NeverCalled видима снаружи, так что её могут вызывать из других translation units. Ну и clang справедливо полагает, что это произошло — NeverCalled была вызвана где-то. Иначе в коде присутствовал бы UB.

utf8nowhere ()
Последнее исправление: utf8nowhere (всего исправлений: 1)
Ответ на: комментарий от ckotinko

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

И вероятность найти там не ноль оказалась равна единице.

utf8nowhere ()

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

anonymous ()
Ответ на: комментарий от utf8nowhere

Ф-я NeverCalled видима снаружи, так что её могут вызывать из других translation units. Ну и clang справедливо полагает, что это произошло — NeverCalled была вызвана где-то. Иначе в коде присутствовал бы UB.

что за бред?

anonymous ()
Ответ на: комментарий от utf8nowhere

ну поздравляю, еще один лютобаг в компиляторе, который будут оправдывать UB.

есть переменная, она static, значит лежит в bss. Оный сегмент при загрузке инициализируется нулями. static = 0. Есть процедура, которая пишет в эту переменную. Она не вызывается. То есть запись в переменную не происходит. Это у нормальных людей. Не вызываем процедуру - не происходит действия.

А говноеды думают, что раз где-то появилось сочетание латинских букв U и B, то это дает им право «оптимизировать».

ckotinko ★★☆ ()

Забавно, но в данном случае все логично, использование нулевого указателя - UB, чтоб было использовано оптимизатором для генерации более быстрого кода. И даже больше, в реальном коде, если бы погромист налажал с инициализацией, то код сработал бы корректно и была бы вызвана нужная функция.

anonymous ()
Ответ на: комментарий от utf8nowhere

Это в каком разделе стандарта написано?

А что, может быть как то ещё до оптимизатора? «a part of the data segment containing statically-allocated variables represented solely by zero-valued».

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

Доказать можешь?

user@user-desktop:~$ echo "int main() {\
>  return Do();\
> }\
> " > test.cpp
user@user-desktop:~$ cat test.cpp
int main() { return Do();}
user@user-desktop:~$ cat test.cpp | grep Function
user@user-desktop:~$

вызова нету-с.

Это в каком разделе стандарта написано?

весь static по определению идет либо в bss, либо в data, если его значение можно вычислить в compile time. просто больше негде хранить переменные. ну только если ты сам через аттрибуты секцию пропишешь.

вообще если уж разрабы компилятора считают, что значение «не определено», это означает что оно реально не определено - туда не пишется никакое значение.

Upd.

void NeverCalled()
{
  asm("inb $0x61,%al");
  Do = EraseAll;  
}
оуууу. вы чо, серьезно что ли? обалдели там.

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

вообще если уж разрабы компилятора считают, что значение «не определено», это означает что оно реально не определено - туда не пишется никакое значение.

Тут разрабы компилятора скорее решили, что вызов функции по нулевому адресу не определен, а не значение переменной, которое наверняка будет 0.

anonymous ()
Ответ на: комментарий от ckotinko

весь static по определению идет либо в bss, либо в data

Малось по сложнее. Опустим про константный сегмент. Даже без оптимизатора может и не быть переменной вовсе, она же static и не volatile, то есть её не обязательно заводить, достаточно «в уме» держать все операции с ней. Вот в clang и дооптимизировались до того, что раз static и инициализируется в одном месте, но юзается в main разыменовываясь, то можно тупо и выкинуть переменную вообще. Вот и получилось, что получилось.

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

значение «не определено»

Не знаю, как в твоём манямирке, а в стандарте не определено поведение, так что программа имеет право как вызвать EraseAll, так и сделать что угодно ещё.

Softwayer ()
Ответ на: комментарий от anonymous

это расширительная трактовка «не определённости». есть переменная в которую могут записать значение, в частности это делает функция, которую могут вызвать. это не значит, что в переменную обязательно будет записано значение именно этой функцией.

может != будет.

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

собственно, те же соображения у меня были и по поводу UB при переполнении, где все кричали - тут UB так можно делать.

Окей, вы можете оптимизировать выражения со знаком без учета переполнения при арифметических операциях. Но оптимизация не должна приводить заведомо невозможным результатам. Т.е. если у меня есть выражение A & (B+C), где A=const а результат B+C может быть undefined, то это не значит что он будет undefined и тем более это не значит, что можно выкидывать операцию И - её именно выкинули, т.к. 8191 & x не может стать отрицательным ни при каком х длиной >=16 бит.

оптимизация != генерации самопального кода.

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

он не то что генерит код, наоборот - удоляет. Ему хочется заинлайнить всё (это ведь оптимизация, не будешь спорить?). Понять как инлайнить в данном случае он не может - поэтому заменяет на первое что нашел. Заменить на рандомное он имеет право, потому что стандарт не обязывает.

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

заменяет на первое что нашел

Не первое, а единственное. Если переменная может принимать единственное валидное значение, то естественно его сразу и взять.

anonymous ()