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

Согласно этой ветке комментариев reddit, не определено, если попытка чтения памяти была сделана раньше это было написано. Я имею в виду нормальную память кучи, которая была успешно malloc использована.

... обратите внимание, что это не строго допустимый C: компилятор / исполняющая система может инициализировать неинициализированную память с так называемыми представлениями ловушек, которые вызывают неопределенное поведение при доступе.

Мне трудно в это поверить. Есть ли стандартная цитата?

Конечно, я понимаю, что нет гарантии, что память обнулилась. Значения в этой неинициализированной памяти по существу псевдослучайны или произвольны. Но я действительно не могу поверить, что в Стандарте это будет называться неопределенным поведением (в том смысле, что это может быть segfault, или удалить все ваши файлы, или что-то еще). Остальная часть ветки Reddit не пролила больше света на эту проблему.


person Aaron McDaid    schedule 09.02.2012    source источник
comment
Эээ, как вы думаете, что означает неопределенное поведение? (Да, использование выделенной памяти до ее инициализации приводит к неопределенному поведению)   -  person Brian Roach    schedule 10.02.2012
comment
@Brian Я предполагаю, что он спрашивает, не определено ли все поведение (т.е. будет ли этот segfault) или только значение, которое будет результатом чтения.   -  person Owen    schedule 10.02.2012
comment
@Owen, правильно, я обновил вопрос соответственно.   -  person Aaron McDaid    schedule 10.02.2012
comment
У вас не может быть подмножества undefined. Это означает, что поведение не определено. Будет ли это ошибка? Кто знает; поведение undefined. Это не значит, что он будет segfault или удалит ваши файлы, на самом деле он вероятно не сделает ничего плохого ... но вы не можете полагаться на это, потому что нечего сказать, что он выиграл ' т.   -  person Brian Roach    schedule 10.02.2012
comment
Память является неопределенной, и это указано как неопределенное поведение в ненормативном Приложении J (Переносимость), но я не смог найти ничего нормативного, прямо заявляющего, что доступ к неопределенной памяти является U.B.   -  person David Thornley    schedule 10.02.2012
comment
Если вы хотите выделить инициализированную память, calloc - ваш друг.   -  person undur_gongor    schedule 10.02.2012


Ответы (3)


Если доступ осуществляется через char*, это определяется. Но в остальном это неопределенное поведение.

(C99, 7.20.3.3) «Функция malloc выделяет пространство для объекта, размер которого определяется размером, а значение неопределено».

по неопределенному значению:

(C99, 3.17.2p1) «неопределенное значение: либо неопределенное значение, либо представление прерывания»

при чтении представления ловушки через несимвольный тип, имеющий неопределенное поведение:

(C99, 6.2.6.1p5) «Определенные представления объектов не обязательно должны представлять значение типа объекта. Если сохраненное значение объекта имеет такое представление и читается выражением lvalue, не имеющим символьного типа, поведение будет undefined. [...] Такое представление называется представлением ловушки ".

person ouah    schedule 09.02.2012
comment
Добавьте стандартную цитату, в которой говорится, что доступ к представлению ловушки приводит к неопределенному поведению, и у вас будет полная цепочка. (Но, несмотря на этот комментарий, вам все еще не хватает этого.) - person Brooks Moses; 10.02.2012
comment
@BrooksMoses, это большой вопрос. Что означает представление ловушки? - person Aaron McDaid; 10.02.2012
comment
@ouah, значит он четко определен (но произвольно / неопределенно), если используется char*? - person Aaron McDaid; 10.02.2012
comment
@AaronMcDaid, если вы разыменовываете char * да: стандарт проясняет, что типы символов не имеют представления ловушек. - person ouah; 10.02.2012
comment
Есть ли другие типы, для которых он четко определен? Неужто что-нибудь простое вроде int? Есть ли хороший пример типа, в котором он не четко определен? Может быть, есть какие-то наборы битов, которые не представляют действительный double, или что-то в этом роде? - person Aaron McDaid; 10.02.2012
comment
Гарантируется, что только символьные типы @AaronMcDaid не имеют представления ловушек. Если вам нужна дополнительная информация о представлении ловушек, есть хорошее объяснение в PDF-файле New C Standard, написанном Дереком М. Джонсом. - person ouah; 10.02.2012
comment
@ouah, я сделал небольшое изменение, чтобы подчеркнуть, что char* в порядке. Не стесняйтесь редактировать или возвращать, если я допустил ошибку. А в остальном спасибо! - person Aaron McDaid; 10.02.2012
comment
@AaronMcDaid: достаточно четко определено, является ли ИМО ошибкой - поведение либо определено, либо нет; для разумного нет серой зоны. Итак, я немного отредактировал вашу правку. :) - person Brooks Moses; 10.02.2012
comment
:-) @BrooksMoses. Это определено как неопределенное значение (что кажется странным способом выразить это). В любом случае, любой, кто прочитает вопрос, поймет, что мы имеем в виду. Итак, я доволен этим изменением, если предположить, что все остальные. - person Aaron McDaid; 10.02.2012
comment
Даже без представлений прерываний в приложении к UB утверждается, что доступ к неопределенному значению всегда осуществляется через UB. Однако я не могу найти какой-либо нормативный язык, чтобы обосновать это утверждение ... По константам в limit.h и изучению sizeof легко увидеть, что в реализациях, которые вас интересуют, отсутствуют представления ловушек. - person R.. GitHub STOP HELPING ICE; 10.02.2012
comment
@ouah: Разве типы структур не гарантированно не имеют представления ловушек? Учитывая struct { double x, y; } foo,bar, если foo.x был записан, а foo.y - нет, тогда foo.y может содержать представление ловушки, но bar=foo; `не будет разрешено перехватить, но последующий доступ к bar.y будет. - person supercat; 23.03.2016

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

Читая стандарт, ключевой вопрос заключается в том, являются ли значения памяти с ошибками «неопределенными значениями» (которые должны быть некоторым читаемым значением) или «неопределенными значениями» (которые могут содержать представления ловушек; см. Определение 3.17.2.)

В соответствии с 7.20.3.3, указанным в других ответах, malloc возвращает блок памяти, который содержит неопределенные значения и, следовательно, может содержать представления ловушек. Соответствующее обсуждение представлений ловушек см. В 6.2.6.1, часть 5:

Некоторые представления объектов не обязательно должны представлять значение типа объекта. Если сохраненное значение объекта имеет такое представление и читается выражением lvalue, не имеющим символьного типа, поведение не определено. ... Такое представление называется представлением ловушки.

Итак, поехали. По сути, реализации C разрешено обнаруживать (т. Е. «Перехватывать») ссылки на неопределенные значения и обрабатывать эту ошибку так, как она выбирает, в том числе неопределенными способами.

person Brooks Moses    schedule 09.02.2012
comment
Почему необходимо, чтобы такие инструменты, как Valgrind, вели себя как полностью соответствующие реализации C? Я бы предположил, что во многих случаях для них было бы более полезно иметь возможность настраивать ловушки для множества вещей, которые считаются полностью определенными стандартом, но которые, как знает программист, никогда не произойдут, кроме как случайно. - person supercat; 23.03.2016

ISO / IEC 9899: 1999, 7.20. 3.3 Функция malloc:

Функция malloc выделяет пространство для объекта, размер которого определяется размером и значение которого не определено.

6.2.6.1 Представление типов, §5:

Определенные представления объектов не обязательно должны представлять значение типа объекта. Если сохраненное значение объекта имеет такое представление и читается выражением lvalue, не имеющим символьного типа, поведение не определено.

А сноска 41 делает это еще более явным (по крайней мере, для автоматических переменных):

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

person undur_gongor    schedule 09.02.2012
comment
У меня нет проблем с «неопределенным значением». Это ясно из ответа. Вопрос в том, является ли поведение полностью неопределенным (ошибки сегментации и т. Д.). - person Aaron McDaid; 10.02.2012
comment
Значит, через char* все в порядке? Вы можете привести пример такого объекта? Я пытаюсь вспомнить, как представлены doubles - возможно, не все битовые конфигурации соответствуют действительному double. Это то, о чем здесь говорится? - person Aaron McDaid; 10.02.2012
comment
Существуют различные виды NaN (не числовых) значений, которые являются частью стандартного представления double, но они все еще действительны. - person Brooks Moses; 10.02.2012
comment
Я только что заметил, что я сказал «неопределенное значение», тогда как я должен был сказать что-то «неопределенное значение». Мне кажется, что они оба означают одно и то же, но, похоже, они имеют разные значения в стандартном языке Си! - person Aaron McDaid; 10.02.2012
comment
@AaronMcDaid: Не определено! = Segfault. Например, выражение a++ + a++ вызывает неопределенное поведение, но вам будет сложно найти платформу, которая действительно откажется от этого (если вы это сделаете, eek). Хотя, честно говоря, мы говорим здесь о ловушках. - person John Bode; 10.02.2012