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();
}
★★★★☆

Последнее исправление: beastie (всего исправлений: 1)

$ ./a.out 
Segmentation fault (core dumped)

это нормально или надо что-то чинить?
P.S.: зачем тег c?

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

P.S.: зачем тег c?

Потому-что по факту код написан на С.

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

его лучше не юзать

UB на то и UB, что поджидает в самых неожиданных местах. Если конечно не знать стандарт наизусть.

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

а теперь шлангом с параметром -Os

Это говорит только о том, что оптимизация в шланге реализована криво. Когда-то давно и в gcc не рекомендовалось использовать оптимизации, особенно -O3. Будем надеяться, что и в шланге это когда-то пофиксят. А чтобы ускорить этот процесс, пошли им баг-репорт.

aureliano15 ★★
()

На gcc-5.4 не воспроизводится, пользователи шланга должны страдать.

$SUBJ

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

А что в таком поведении корректного? Статическая переменная в соответствии со стандартом инициализируется 0. Вызов 0, даже если поведение в этом случае неопределено, никак не может быть равнозначным вызову произвольной функции, просто из здравого смысла. Такой вызов может привести к краху программы, к выбрасыванию исключения или к обработке этой ошибки иным способом. В этом и смысл неопределённого поведения: компилятор может обрабатывать эту ошибку по-возможности корректно (но как — стандарт не предписывает) или вообще не обрабатывать. В последнем случае в защищённом режиме произойдёт ошибка сегментации, а в реальном — вызов кода по нулевому адресу, а там — хрен знает, к чему это приведёт. Но подставлять вместо 0 произвольное число компилятору никто права не давал. Этак можно договориться до того, что раз в стандарте не прописано, что 2*2==4, то компилятор имеет право возвращать любой произвольный результат при умножении 2*2.

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

просто из здравого смысла

Здравый смысл — вообще, понятие, которым пользуется лишь быдло и ГСМ-ы.

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

Стандарт говорит, что он точно описывает поведение в любой ситуации, которая не относится ко следующим классам: ill-formed, ill-formed no diagnostic required, implementation-defined behavior, unspecified behavior, undefined behavior.

То есть, UB - это не ill-formed («ошибка»), и не unspecified («может быть что угодно, но результат обязан быть корректным»).

Вот как в стандарте описан UB:

undefined behavior

behavior for which this International Standard imposes no requirements

[ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. Evaluation of a constant expression never exhibits behavior explicitly specified as undefined (8.20). — end

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

Весь UB там не от того, что язык не придумал, что надо делать, а от невозможности заставить окружение — ОС всегда выполнять определённую реакцию. Во времена изобретения C и Unix было всего 64к памяти на процесс, размер страницы 8к. Как вы себе представляете вот так просто взять и 1/8 часть всей памяти тупо поставить запрет на чтение только лишь для установки особого поведения разыменования адреса «0»? Даже запрет на запись почти всегда было неудобно делать, так как это означало, что сегмент данных должен начинаться после границы 8к, что могло опять же привести к потери 8k-1 памяти.

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

почему «было»? сейчас в эмбеддеде уже нет такого?

Сейчас разучились делать настоящие ОС на 64к. Если и есть такие архитектуры, то там вряд ли полноценная MMU.

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

Найти смешные архитектуры можно много, но на ОС общего назначения примененной в них вряд ли потянут. Вот если не уходить от темы, какая реакция должна быть при чтении из [0] там и почему? Это в ОС для человека можно тупо выплюнуть корку и обругать страшными словами, а на ваших картах небось всё должно стоять как штык и работать и работать.

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

Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

Вот вольный перевод:

Допустимо неопределённое поведение от полного игнора ситуации с неопределёнными результатами до поведения во время компиляции или выполнения документированным способом, в соответствии с характеристиками среды выполнения (с выдачей диагностического сообщения или без такового), прекращения компиляции или выполнения (с выдачей диагностического сообщения).

И где здесь написано про то, что можно вместо 0 подставлять произвольный адрес? Здесь, по-моему, наоборот чётко перечислены возможные действия:

  1. Игнор ситуации, т. е. вызов функции по адресу 0, что в Линуксе приведёт к ошибке сегментации.
  2. Поведение документированным способом в соответствии с характеристиками среды. Если под средой подразумевать ОС Линукс, то в данном случае это то же самое, что и п. 1. Если же под средой подразумевать clang, то он должен вести себя в соответствии с собственной документацией. Т. е. он может вызвать другую функцию, только если это отражено в документации clang.
  3. Также clang может прекратить компиляцию или выполнение программы, обнаружив вызов 0 адреса, с выдачей соответстветствующего сообщения.

Ни одно из этих условий не выполнено, а значит clang ведёт себя не в соответствии со стандартом, а просто глючит при использовании уровня оптимизации -Os.

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

И где здесь написано про то, что можно вместо 0 подставлять произвольный адрес?

это в той части, где неопределенные результаты

то он должен вести себя в соответствии с собственной документацией

то о чем ты говоришь про документацию - это implementation-defined behavior. Если в документации нету, но все равно подразумевается корректный результат - это unspecified.

а UB - это другое, это специальные места, где можно открывать портал в ад

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

Имел удовольствие как-то получить обратно баг-репорт от компиляторщиков с пометкой won't fix. Если вкратце - не совсем корректный код приводил к краху компилятора. Они считали что это нормально. При том что их компилятор вообще в рантайме запускался, унося с собой всю остальную программу, вообще-то. Странные программисты, пишушщие компиляторы, в последнее время взяли за моду начитавшись стандартов троллить программистов, которые кроме чтения стандартов занимаются ещё вообще-то и прикладными задачами. Вот от таких компиляторщиков и хочется свалить с C/C++ в какой-нибудь новый компилируемый язык с ясным, простым, определённым поведением.

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

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

То, что ты переводишь — записано в Note. А notes, как известно, informative, not normative.

Как clang может вести себя в не соответствии с тем, что с т.з. стандарта даже не является правилом?

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

где здесь написано про то, что можно вместо 0 подставлять произвольный адрес?

это в той части, где неопределенные результаты

Так ведь неопределённые результаты, а не произвольные действия.

Ещё раз процитирую то, что ты выделил жирным:

Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results

Т. е.

Допустимо неопределённое поведение от полного игнора ситуации с неопределёнными результатами

Но ведь игнор — это вовсе не подстановка произвольного адреса вместо 0. Это как я могу проигнорировать твоё сообщение, могу на него ответить, и это нормально (и то, и другое). Но если я процитирую тебя, заменив в цитате несколько ключевых слов, что изменит её смысл на противоположный, то это ненормально.

то он должен вести себя в соответствии с собственной документацией

то о чем ты говоришь про документацию - это implementation-defined behavior.

Я комментировал исключительно примечание (note) из твоей цитаты из стандарта о ub:

to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message)

Т. е.

до поведения во время компиляции или выполнения документированным способом, в соответствии с характеристиками среды выполнения (с выдачей диагностического сообщения или без такового)

UB - [skip] это специальные места, где можно открывать портал в ад

Портал в ад можно открывать в doom, quake и их клонах, но не в компиляторах, потому что компиляторы предназначены для других целей.

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

То, что ты переводишь — записано в Note. А notes, как известно, informative, not normative.

Т. е. note предназначен для того, чтоб включать в документ разную чепуху, не имеющую никакого отношения к этому документу?

Я всегда считал, что note — это просто примечание.

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

Имел удовольствие как-то получить обратно баг-репорт от компиляторщиков с пометкой won't fix.

Наверно, это был Поттеринг. А что за компилятор?

Вот от таких компиляторщиков и хочется свалить с C/C++ в какой-нибудь новый компилируемый язык с ясным, простым, определённым поведением.

В си и в си++ всё ясно, просто (ну, относительно) и определённо. А то, что кто-то интерпретирует стандарты по-своему, так это не проблема си/си++. Впрочем, думаю, что разработчики шланга уже прочитали сообщения об этом баге и скоро появится патч. Надеюсь, что не ошибаюсь. А пока юзай gcc, в нём такого бага нет.

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

Т. е. note предназначен для того, чтоб включать в документ разную чепуху, не имеющую никакого отношения к этому документу?

Прочитай требования к ISO-стандартам. Там написано, зачем нужны note.

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

Прочитай требования к ISO-стандартам. Там написано, зачем нужны note.

Так процитируй со ссылкой на цитируемый документ, если знаешь. А то я боюсь, что найду что-то не то, а там ещё будет 1000 страниц, которые я буду читать год, прежде чем выяснится, что нашёл не то.

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

Впрочем, думаю, что разработчики шланга уже прочитали сообщения об этом баге и скоро появится патч. Надеюсь, что не ошибаюсь.

И не надейся. clang-еры систематически держат курс на всё более строгое отношение к программам, содержащим UB.

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

настоящая проблема в том, что крестовики сначала придумывают некую розовую пушистую фантазию, с радугами и понями, и потом рассказывают что в С++ всё хорошо

И потом крестовик такой утвреждает: С++ хороший, это вы стандарт не правильно поняли. Создатели стандарта тоже так считают? Ну это потому что создатели стандарта - уроды, чего они там в коммитетах понимают, а вот на практике всё ок. Ой, разрабы самого крутого C++ компилятора Шланг ответили «won't fix» - ну это потому что шланг ненужен, да и вообще таких программ нет. Ой, такие программы есть? Ну... ну.... ну........

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

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

http://www.iec.ch/members_experts/refdocs/iec/isoiecdir-2{ed7.0}en.pdf#page=68

Спасибо за ссылку.

Notes are used for giving additional information intended to assist the understanding or use of the text of the document. The document shall be usable without the notes.

В переводе:

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

Т. е. для непонятливых примечания поясняют, что написано выше, а понятливые и так поймут (как я, ещё не читая этого примечания, сказал практически то же самое).

Notes should be written as a statement of fact.

Т. е.

Заметки должны писаться как констатация факта.

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

А то я боюсь, что найду что-то не то

В Foreword C++ стандарта написано:

International Standards are drafted in accordance with the rules given in the ISO/IEC Directives, Part 2.

Сложно найти «что-то не то».

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

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

И не надейся. clang-еры систематически держат курс на всё более строгое отношение к программам, содержащим UB.

Более строгое — это ошибка компиляции или выполнения. А запуск вместо 0 произвольного недокументированного кода — это менее строгое отношение. Так что продолжаю надеяться, хоть сам пользуюсь gcc, а clang поставил только чтобы откомпилять пример из верхнего поста с предложенными опциями.

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

Более строгое — это ошибка компиляции или выполнения.

Для отлова UB есть специальные опции -funidefined=...

В остальное время компилятор считает, что поданная ему на вход программа корректна.

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

Имел удовольствие как-то получить обратно баг-репорт от компиляторщиков с пометкой won't fix.

Наверно, это был Поттеринг. А что за компилятор?

AMD-шный компилятор OpenCL C, по сути - обрезанный и дополненный clang C99.

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

Т. е. для непонятливых примечания поясняют, что написано выше, а понятливые и так поймут

Да. Понятливым понятно, что «International Standard imposes no requirements» означает ровно то, что написано.

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

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

и потом рассказывают что в С++ всё хорошо

Я этого не рассказываю. Многое в си++ мне не нравится, особенно из новшеств последнего десятилетия. Но, конечно, не всё так плохо, как некоторым кажется.

Ой, разрабы самого крутого C++ компилятора Шланг

И почему шланг самый крутой? Почему не gcc?

ответили «won't fix»

Это не ко мне. Я не знаю, кто и на что конкретно так ответил. Дождёмся ответа tim239.

столкнувшись с жестокой реальностью

Жестокая реальность в том, что нигде кроме шланга этот баг не проявляется. Да и в шланге он проявляется только при включении оптимизации. И, кстати, даже с оптимизацией легко отключается, если описать переменную Do как volatile.

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

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

Да, это чувство когда хочется сказать разработчикам компилятора «Вот сами свой код таким компилятором и компилируйте, стандартодрочеры». И взять другой компилятор или язык, чесслово.

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

по сути, это конфликт между тобой и создателями стандарта. Ты говоришь, что это место должно быть unspecified, а они его классифицировали как undefined

теперь включи мозг и подумай, почему они сделали именно так, а не иначе. Они ведь могли написать там слово unspecified, но не сделали этого.

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

ответили «won't fix»

Это не ко мне. Я не знаю, кто и на что конкретно так ответил. Дождёмся ответа tim239.

Воу-воу, это не те ребята и не тот код, не надо смешивать в кучу. Я к тому, что у компиляторщиков, которые реально очень хорошо знают стандарт, сносит крышу настолько, что они - как пример - начинают считать что их чудо-компилятор может и крэшиться от UB. Конкретно в том случае было нарушение какого-то ограничения из 6.9.b стандарта OpenCL 1.2, с переменной типа image2d_t делалось что-то неправильное, что вообще должно было компилятором выдаться как ошибка, но код работал до поры до времени - пока функция, где происходило безобразие, инлайнилась. Как только она перестала - компилятор стал крэшиться. И мы им такие:

- Смотрите, у вас баг!

- Нет, у вас!

- Но мы то у себя поправим, но ведь рантайм компилятор же не должен крашиться?

- Вот и славно, мы исправлять не будем.

В примере из этой темы - лучше бы клэнг крэшился.

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

Да тебе кто-то запрещает, что ли? Говори разработчикам компилятора что хочешь, бери другой компилятор и язык.

Это само собой, но и на форуме нужно поныть.

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

В примере из этой темы - лучше бы клэнг крэшился.

А если у меня в другом файле определён глобальный объект, чей конструктор вызывает NeverCalled? Тогда поведение будет полностью определено.

utf8nowhere ★★★
()

Содрал с реддита и типа сам придумал. Давно уже обсосали эту тему.

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

там, где явно сказано, что никаких требований нет?

Он не должен падать или не падать. Он должен выполнять одно из действий, описанных в процитированном note, потому что note — это

a statement of fact.

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

по сути, это конфликт между тобой и создателями стандарта.

Нет. Это правильное понимание стандарта мною и неправильное понимание его тобой и utf8nowhere.

Впрочем, не всё так страшно. Ошибки случаются у всех, и, повторюсь, убеждён, что разработчики шланга уже начали править этот баг. Поживём — увидим.

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

- Смотрите, у вас баг!

- Нет, у вас!

- Но мы то у себя поправим, но ведь рантайм компилятор же не должен крашиться?

- Вот и славно, мы исправлять не будем.

Точно Поттеринг! Его слова один в один! :-)

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

Он должен

Почему должен? Повторяю для непонятливых: notes are informative. В normative части стандарта сказано «no requirements», так что забудь про слово «должен».

одно из действий

В note написано «ranges from ... to ..., to ...». Как ты собираешься доказывать, что поведение clang не попадает в этот range?

note — это a statement of fact.

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

А с чего ты прицепился к выражению «statement of fact», что тебе тут мерещится, мне ещё более неясно.

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

В note написано «ranges from ... to ..., to ...». Как ты собираешься доказывать, что поведение clang не попадает в этот range?

Потому что такое поведение абсурдно и ни разу не похоже на то, что написано в note.

note — это a statement of fact.

что тебе тут мерещится

Констатация факта. И там ни разу не констатируется, что 0 можно заменить другим адресом.

Почему должен? Повторяю для непонятливых: notes are informative.

Значит, мы по-разному понимаем стандарт. Что ж, пусть каждый остаётся при своём мнении, т. к. всё равно никто никого не переубедит, — это уже понятно. А что думают по этому поводу разработчики шланга, мы скоро увидим по их реакции на этот баг или по отсутствию таковой.

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

В примере из этой темы - лучше бы клэнг крэшился.

А если у меня в другом файле определён глобальный объект, чей конструктор вызывает NeverCalled? Тогда поведение будет полностью определено.

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

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

такое поведение абсурдно

Нет, в корректной программе только такое поведение и могло быть. А некорректные программы абсурдны сами по себе.

ни разу не похоже на то, что написано в note.

Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results.

Clang полностью проигнорировал, что функция NeverCalled может не вызываться и получился unpredictable results. Всё в соответствие с note. :-)

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

А что думают по этому поводу разработчики шланга, мы скоро увидим по их реакции на этот баг или по отсутствию таковой.

Вот боюсь они думают «Мы стандарт выучили от корки до корки - и вам придётся».

tim239 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.