LINUX.ORG.RU

Если вам не хватало UB в C, то вам принесли ещё

 ,


1

3

Привет, мои дорогие любители сишки!

Если вам начало казаться, что разработчики стандарата языка C стали предсказуемыми и больше не могут удивлять вас новыми идеями, то вы ошибались. В новом стандарте C23, комитет постановил:

— zero-sized reallocations with realloc are undefined behavior;

То есть вот это валидный код:

void *ptr = malloc(0);
free(ptr);

А вот это – UB:

void *ptr = malloc(4096);
ptr = realloc(ptr, 0); <-- хаха UB

И это несмотря на то, что в манах уже давно написано следующее:

If size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr)

Изменение вносится задним числом, наделяя кучу корректного (согласно документации glibc) кода способностью полностью изменить логику работы программы. Ведь это то, чего нам так не хватало!

В тред призываются известные эксперты по C: @Stanson и @alex1101, возможно они смогут нам объяснить, зачем разработчики стандарта C постоянно пытаются отстрелить себе обе ноги самыми нелепыми способами.



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

Ответ на: комментарий от monk

В Rust есть UB. В Java нет.

Ага, то есть вы нашли UB в unsafe коде (он там и обязан быть ибо зачем тогда этот unsafe нужен вообще) и это даёт вам некое формальное право утверждать «В Rust свои UB», что чисто грамматически корректно, но тупо по сути. Если подобным спекулятивным мышлением овладеть в полной мере, то UB можно найти вообще где угодно - в питоне, потому что 95% питоньей библиотеки написано на Си, а в Си есть UB. В джаве, потому что JNI, а там UB, в C# - там тоже есть unsafe. Только вопрос, нахрена такие упражнения в демагогии нужны, чтобы что?

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

unsafe нет, UB есть:

fn helper<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }

pub fn make_static<'a, T>(input: &'a T) -> &'static T {
    let f: fn(_, &'a T) -> &'static T = helper;
    f(&&(), input)
}

fn main() {
    let memory = make_static(&vec![0; 1<<20]);
    println!("{:?}", memory);
}
monk ★★★★★
()
Ответ на: комментарий от cumvillain

Если я в жаву засуну inline assembly, который NULL поинтер позовет, это тоже будет UB.

В смысле Си не будет. Программа может упасть, но не может, как в Си, внезапно превратится в совершенно другую программу.

А в Rust может, потому что LLVM.

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

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

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

Только этот баг много лет никак устранить не могут.

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

cumvillain
() автор топика
Ответ на: комментарий от monk

Только этот баг много лет никак устранить не могут.

Вы читали топик вообще? На шести страницах уже до блеска обсосали, что такое UB, и чем оно отличается от бага, от особенностей конкретного компилятора, от DI, от шумов в голове. Для вас персонально надо весь срач сначала начинать?

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

Компилятор не должен позволять выстрелить себе в ногу

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

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

В данной ситуации оно и так хрен пойми как работало(в этом компиляторе так, в том по-другому).

Не компиляторе а libc. Компилятор ни при чём. И C-стандарты вобщем-то тоже ни при чём, авторы libc их скорее всего в большинстве своём не читают, они делают продукт для полезного использования существующими приложениями а не какую-то абстракцию.

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

Почему в Rust смогли, а в C – нет? Просто признаем, что в C23 весь код должен вести себя нормально и сильно убираем весь attack surface. Те, кто не согласен – пожалуйста, для вас есть C17. А в итоге мы опять имеем кашу из C standard, POSIX standard и отдельные варианты gnuc11. Кеклол.

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

Просто признаем, что в C23 весь код должен

Эта фраза выглядит так: «а давайте теперь писать код в соответствии с правилами, которые я только что придумал». Ответ: нет, не давайте, у нас свои правила (устоявшиеся за десятки лет) и нам они нравятся больше - если хочешь пиши сам по-своему. Только всё ещё печальнее, ведь комитет код не пишет, только тексты.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)

https://github.com/regehr/ub-canaries collection of C/C++ programs that try to get compilers to exploit undefined behavior

https://blog.regehr.org/archives/1234 UB Canaries

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

https://ru.stackoverflow.com/questions/1196125/Почему-знаковое-переполнение-э...

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1705r1.html P1705R1 Enumerating Core Undefined Behavior Draft Proposal, 2019-09-28

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 5)
Ответ на: комментарий от firkax

Эта фраза выглядит так: «а давайте теперь писать код в соответствии с правилами, которые я только что придумал». Ответ: нет, не давайте, у нас свои правила (устоявшиеся за десятки лет) и нам они нравятся больше - если хочешь пиши сам по-своему. Только всё ещё печальнее, ведь комитет код не пишет, только тексты.

У кого у вас? Тебя с твоими голосами?

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

У нас уже был py2 -> py3. В итоге все переехали и про py2 никто и не помнит.

Опять одна организация (и даже наверно один человек), который и придумывает язык и пишет интерпретатор. И возрастом на порядок поменьше чем Си (как и раст). Си - общественное достояние, в работе над которым задействовано очень много реально независимых друг от друга субъектов, и все попытки его приватизировать и монопольно издавать правила провалятся.

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

Опять одна организация (и даже наверно один человек), который и придумывает язык и пишет интерпретатор. И возрастом на порядок поменьше чем Си (как и раст).

У питона больше одной реализации. И ничего, живут как-то.

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

Что за шизу ты несешь? У C есть стандарт, ему стараются следовать настолько четко, насколько это вообще возможно. Твои странные пассажи про какой-то антагонизм между разработчиками компиляторов и стандартизаторами какой-то упоротый.

cumvillain
() автор топика
Ответ на: комментарий от fsb4000

This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven.

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

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

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

ЧСХ в расте ты можешь собрать бесконечный цикл и он будет работать без UB. Потому что оптимизировать бесконечные циклы – бесполезное занятие.

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

Если я в жаву засуну inline assembly, который NULL поинтер позовет, это тоже будет UB.

В ассемблере разыменование NULL как раз точно не UB, а зависит от проца и ОС. UB в ассемблере это использование несуществующих кодов операций и только оно (в 8086/8088 это было прям совсем UB т.к. у проца не было механизма исключений и он исполнял как получится всё что встретится в т.ч. некорректное).

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

обсосали, что такое UB, и чем оно отличается от бага

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

no-such-file ★★★★★
()
Ответ на: комментарий от cumvillain

Твой сарказм неуместен. Наверно в учебнике русского языка этот оборот где-то разъяснён. Это предполагаемый ответ от неких людей, которым поступило указанное предложение.

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

В ассемблере вообще все поведение очень четко defined.

Вообще нет. Четко определено оно только на конкретном процессоре, и то, с нынешними спекулятивными суперскалярами всплывают всякие приколы в духе meltdown.

no-such-file ★★★★★
()
Ответ на: комментарий от firkax

Твой сарказм неуместен. Наверно в учебнике русского языка этот оборот где-то разъяснён.

Это не сарказм. В семантике ASM просто нет UB, потому что там пяток операций и нет как такового компилятора.

cumvillain
() автор топика
Ответ на: комментарий от no-such-file

Вообще нет. Четко определено оно только на конкретном процессоре, и то, с нынешними спекулятивными суперскалярами всплывают всякие приколы в духе meltdown.

Это не относится к языку. Если я напишу puts(«хаха мамку твою вертел»), а пользователь выкинет ляптоп в окно, это не сделает программу некорректной.

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

У питона больше одной реализации. И ничего, живут как-то.

Мейнстримная одна и в любом случае питон, как «торговая марка» (не в курсе насчёт официального статуса, речь не о нём), принадлежит кому-то конкретному и им же регулируется.

У C есть стандарт, ему стараются следовать настолько четко

Мнение кого-то из GNU на этот счёт, приведённое где-то на их сайтах (ссылку не запомнил): для упёртых фанатиков комитета (чтоб те не обвиняли нас в неспособности реализовать комитет-стандарт) мы сделали флаг -pedantic для gcc, но реальных причин им пользоваться нет.

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

Прими как данность. Инициатива в руках у тех кто делает реальную реализацию.

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

Мейнстримная одна и в любом случае питон, как «торговая марка» (не в курсе насчёт официального статуса, речь не о нём), принадлежит кому-то конкретному и им же регулируется.

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

Прими как данность. Инициатива в руках у тех кто делает реальную реализацию.

Инициатива может быть где угодно, но gnu11 и c11 это разные таргеты в GCC.

cumvillain
() автор топика
Ответ на: комментарий от FishHook

Ладно, не на порядок.

C - 1972, Python 0.9 - 1991, Python 2.0 - 2000.

Если строго то чуть больше чем в полтора раза, но всё-таки, с учётом динамики развития ИТ в разные годы и с учётом того, что на Си сразу после (или даже одновременно) его создания была написана ОС, а питон был весьма малоизвестным долгое время, я склоняюсь к тому что реальная разница между ними всё-таки заметно больше, хоть и не в 10 раз.

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

Так и сишка принадлежит комитету.

Это комитет так думает (а может и не думает, а только пытается не особо убедительно делать вид). А по факту Си это общественное достояние и никому он не принадлежит. Я могу хоть сам выпустить Си-компилятор, не совместимый ни со стандартами комитета, ни с gcc, но при этом следующий общим принципам языка и успешно компилирующий большую часть существующего кода - и ничего не помешает называть его Си, ни в юридическом плане, ни в плане морали/приличий. А вот если кто-то сделает альтернативный питон с другим поведением это будет как минимум некрасиво.

Инициатива может быть где угодно, но gnu11 и c11 это разные таргеты в GCC.

Разные, и ни один из них не совпадает с ISO C11. Ну и что?

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

Это комитет так думает (а может и не думает, а только пытается не особо убедительно делать вид). А по факту Си это общественное достояние и никому он не принадлежит.

Это круто, только сишники из-за этого регулярно срут себе в штаны.

Я могу хоть сам выпустить Си-компилятор, не совместимый ни со стандартами комитета, ни с gcc, но при этом следующий общим принципам языка и успешно компилирующий большую часть существующего кода - и ничего не помешает называть его Си, ни в юридическом плане, ни в плане морали/приличий.

Только пользоваться этим никто не будет. А так конечно можешь.

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

Реализаций питона с десяток, не все из них bug-by-bug compatible.

Разные, и ни один из них не совпадает с ISO C11. Ну и что?

То, что c11 таки совпадает с ISO C11, кроме тех случаев, когда разработчики компилятора не шмогли. И этих случаев не то чтобы очень много.

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

На benchmark games нет unsafe, приводящего к UB, но почему-то не тормозит.

Там сложных структур нет, поэтому без unsafe справляются. LRU cache без unsafe не тормозящий можно сделать?

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

Там сложных структур нет, поэтому без unsafe справляются. LRU cache без unsafe не тормозящий можно сделать?

Без unsafe или без оптимизаций вокруг UB? Потому что unsafe { intrinsic() } к оптимизациям вокруг UB отношения не имеет, если ты там внутри не начал лупить по поинтерам.

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

То, что c11 таки совпадает с ISO C11, кроме тех случаев, когда разработчики компилятора не шмогли. И этих случаев не то чтобы очень много.

Да нет, причины совсем другие и первая из них наверно в том что в ISO C11 даже системные .h упадут с ошибкой компиляции, а режим где нельзя сделать include <stdio.h> вряд ли кому нужен.

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

Да нет, причины совсем другие и первая из них наверно в том что в ISO C11 даже системные .h упадут с ошибкой компиляции, а режим где нельзя сделать include <stdio.h> вряд ли кому нужен.

лолшто?

cumvillain
() автор топика