LINUX.ORG.RU

Навеяно свежей дырой в Xorg

 , ,


9

7

Привет, ЛОР!

Ты, наверное, уже видел свежую дыру в Xorg, патч для которой выглядит буквально вот так:

-        else
+        else {
             free(to->button->xkb_acts);
+            to->button->xkb_acts = NULL;
+        }

В связи с этим у меня возник вопрос: а почему в стандартной библиотеке C нет макроса SAFE_FREE()?

#define SAFE_FREE(ptr) do{free(ptr);(ptr)=NULL;}while(0)

Напомню, что значение указателя после вызова free() является неопределённым согласно стандарту. Не только значение памяти, на которое он указывает, но и значение самого указателя, и работа с ним представляет собой жуткое undefined behaviour, а значит единственное что можно сделать – занулить его.

Так вот, почему даже таких банальных вещей нет? Я уже не говорю про строковый тип, а то даже Эдичка тут строки не осилил.

Моя гипотеза тут: C – это язык культа страданий во имя страданий.

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

Вот такие как вы.

Так это какие? Чуваки с портретом 18 века на аватарке? Или кто?

со злым умылом

С каким именно? Так и представляю себе. Сидят комитетчики, пьют чинно чай, и тут один из них заявляет:

  • Господа, а давайте вот сюда UB сунем?

  • Да, я поддерживаю. И ещё вот сюда! Пусть сишники страдают!

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

Это какие? Я наоборот не хочу никакого UB и считаю, что если бы в C его вообще не было, язык был бы только лучше.

JeanHeyd Meneide wg14@soasis.org

https://thephd.dev/c23-is-coming-here-is-what-is-on-the-menu#oh-no-those-evil-committee-people-are-ruining-my-favorite-language%E2%93%A1-with-c-nonsense%E2%93%92

и

https://thephd.dev/c-undefined-behavior-and-the-sledgehammer-guideline

Honestly? I kind of wish I could ruin C sometimes, but believe it or not: we can’t!

C and C++ are already broken.

You can ignore the minutia of Undefined or Implementation-defined or Unspecified or whatever behavior. You could simply just use tools that don’t treat you like you’re too stupid to write what you mean. (ссылка на Rust)

😊

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

А что тут «предметно» и «технически» обсуждать? Большая часть кода на C сломана согласно стандарту языка, и программисты об этом даже понятия не имеют. Тут не обсуждать надо, а посыпать голову пеплом.

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

For all the talk C programmers love to make about how “close to the metal” they are, they never really were

Ну вот типа да. Сишечка не является низкоуровневым близким к железу язычком уже лет наверное под 40.

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

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

Я отсылку в статье об Undefined Behavior выше нашёл о том же самом(https://arxiv.org/pdf/2201.07845.pdf):

2011, Chris Lattner, the main architect of the Clang/LLVM:«To me, this is deeply dissatisfying, partially because the compiler inevitably ends up getting blamed, but also because it means that huge bodies of C code are land mines just waiting to explode. This is even worse because there is no good way to determine whether a large scale application is free of undefined behavior, and thus not susceptible to breaking in the future.»

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

Это какие? Я наоборот не хочу никакого UB и считаю, что если бы в C его вообще не было, язык был бы только лучше.

Си без UB называется Java. Оптимизируется заметно хуже.

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

Си без UB называется Java. Оптимизируется заметно хуже.

Круто. Но тот же Rust в compiler benchmark game почему-то показывает сравнимые с C показатели по скорости, а таких идиотских примеров UB в нём нету. Как же так?

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

В конце-концов значение указателя – это просто набор бит.

Не совсем.

Может быть p == q && *p != *q. Кстати с неинициализированными значениями аналогичное поведение:

{
    bool p; // uninitialized local variable
    if (p)  // UB access to uninitialized scalar
        std::puts("p is true");
    if (!p) // UB access to uninitialized scalar
        std::puts("p is false");
}

может вывести

p is true
p is false

И в твоём примере компилятор имеет право

if(ptr != NULL) { // (1)

приравнять к

if(false) { // (1)

Потому что условие выше указывает, что если бы ptr != NULL было истинным, то уже выполнилось бы free, что недопустимо.

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

В тыщу раз меньше и на нём написано «В РОТ НЕ КЛАСТЬ». Видишь разницу?

Без unsafe мало что написать можно.

Чо? Практически весь мой код на Rust без unsafe. Внутри блоков unsafe{} наверное меньше 1% от всего кода. В отличие от 100% кода на C.

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

я решил изучить Си, и написал программу что случайно отформатировала мне все диски.

Почему в си нет макроса, что защитил бы от этого???

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

Ещё как вызывает. И?

Ещё раз, внутри unsafe{} минимум кода, и поэтому его проще оттестировать и выявить в нём ошибки. Плюс, случаев UB даже внутри unsafe{} в Rust сильно меньше, и их гораздо легче обнаружить. Поэтому вероятность нарваться на UB в Rust несоизмеримо меньше чем в C.

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

Может быть p == q && *p != *q.

Это уже не тот случай, про который я говорю. Вы тут делаете разыменование указателей.

И в твоём примере компилятор имеет право

if(ptr != NULL) { // (1)

приравнять к

if(false) { // (1)

Потому что условие выше указывает, что если бы ptr != NULL было > истинным, то уже выполнилось бы free, что недопустимо.

А что было бы, если бы free вызывался не прямо в этой функции, а внутри какой-нибудь вспомогательной:

void data_cleanup(data * ptr) {
  if(ptr != NULL) {
    do_cleanup_related_actions(ptr);
  }
  else {
    ... // Какие-то другие действия. Допустим, просто
        // печать в лог о том, что data_cleanup был вызван.
  }

  ... // Еще какие-то действия, которые не зависят от
      // значения ptr.

  // А здесь нужно еще что-то сделать если ptr не был NULL.
  if(ptr != NULL) { // (1)
    ... 
  }
}

где do_cleanup_related_actions – это функция, реализованная в другой единице трансляции.

Более того, do_cleanup_related_actions может быть указателем на функцию, который принимает свое значение уже в run-time.

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

ты слишком зациклен )

прямой связи стандарт-разработчик не существует.

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

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

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

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

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

прямой связи стандарт-разработчик не существует.

Потому что сишники читать не умеют. Это я уже выяснил.

так ли плох UB как его малюют? UB (часто) сам по себе не плох, он открывает возможности для оптимизации, а оптимизации это хорошо.

Ну, да. Если выкинуть часть кода, то будет работать быстрее. А в остальном UB без возможности его легко отследить и убрать – это просто треш и ад.

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

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

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

вопрос тут не в языке, а в культуре разработки.

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

А что было бы, если бы free вызывался не прямо в этой функции, а внутри какой-нибудь вспомогательной:

Так даже без этого всего имеет право но не обязан. Если сможет вывести через логику программы, что к этому моменту или free вызвался или ptr == NULL, то выкинет блок. Не сможет доказать, не выкинет.

Сейчас такое же уже работает разыменованием и сравнением с NULL. И с теми же ограничениями на блок компиляции.

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

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

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

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

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

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

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

Схожую, но меньше. Можно и на Си без UB писать: MISRA C в помощь.

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

да никого в индустрии производительность особо не напрягает

Не напрягала бы, никто не писал бы на Си++ (есть же Ява).

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

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

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

Сейчас такое же уже работает разыменованием

Про разыменование не интересно.

По сути же получается, что практически любое сравнение указателей (или даже печать значения указателя) – это потенциальный UB, т.к. хз что компилятор может вывести из анализа кода (или не сможет вывести).

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

ну да, пишут )

комитетчики, компиляторостроители и разработчики регулярно ругаются и портят друг другу кровь. в каждой избушке свои погремушки. где-то по-другому? )

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

Схожую, но меньше. Можно и на Си без UB писать: MISRA C в помощь.

Так хер ли не пишут-то? Тут каждый второй сишник про MISRA C и Frama-C заявляет, но никто ими никогда не пользовался и даже близко не подходил. Посмотришь код таких сишников, а там говно на говне и стэк просран.

Уже 40 лет ведущие умы планеты пытаются вывести программистов, способных победить проблемы с памятью в коде на C, но пока что упс и ах.

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

в силу примитивности (и документированности) ее абстрактной машины

Ээээ што? Опять же, ты спеку читал? Абстрактная машина C нихрена не примитивна. Одна только плоская модель памяти чего стоит.

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

По сути же получается, что практически любое сравнение указателей (или даже печать значения указателя) – это потенциальный UB, т.к. хз что компилятор может вывести из анализа кода (или не сможет вывести).

Да, также как и разыменование. Единственная разница: NULL нельзя разыменовывать, но можно сравнивать.

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

По сути же получается, что практически любое сравнение указателей (или даже печать значения указателя) – это потенциальный UB

Не по сути, а по стандарту лул :DDDD

Пункт 6.5.8:

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object or incomplete types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.
hateyoufeel ★★★★★
() автор топика
Последнее исправление: hateyoufeel (всего исправлений: 3)
Ответ на: комментарий от monk

Не напрягала бы, никто не писал бы на Си++ (есть же Ява).

а на крестах и не пишут)

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

сейчас вот java научилась в нейтив компиляться, посмотрим как изменится ландшафт.

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

Абстрактная машина C нихрена не примитивна.

она простая )

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

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

она простая )

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

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

Нашёл тикет 11-летней давности. Молодец.

error: this arithmetic operation will overflow
 --> shift.rs:2:18
  |
2 |     let i: u32 = (1u32 << 32u32);
  |                  ^^^^^^^^^^^^^^^ attempt to shift left by `32_u32`, which would overflow
  |
  = note: `#[deny(arithmetic_overflow)]` on by default
hateyoufeel ★★★★★
() автор топика
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от fluorite

Починили давно уже. Теперь код с такой ошибкой тупо не собирается. Тикет который ты притащил сделан до выхода версии 1.0, т.е. когда язык был в стадии «НЕ ТРОГАТЬ».

Чо сказать-то хочешь?

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

Только то, что UB сишки и плюсов не просто так появились. Растоманы просто не понаступали ещё на достаточное количество граблей. Поэтому и думают, что UB - для старых пердунов, а они - красавчики. Собственно по растопроектам это хорошо видно - берутся переписывать какой-то проект, на середине понимают почему именно старый код именно такой. Пробуют сделать нормально, но уложиться во все требования без костылей не вывозят. В итоге бросают и начинают что-то другое.

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

Только то, что UB сишки и плюсов не просто так появились.

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

Расскажи же мне, какую важную роль сейчас играет UB из оригинального поста?

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