LINUX.ORG.RU

Скучная сишка

 ,


0

0

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

As a boring platform for the portable parts of boring crypto software, I'd like to see a free C compiler that clearly defines, and permanently commits to, carefully designed semantics for everything that's labeled «undefined» or «unspecified» or «implementation-defined» in the C «standard». This compiler will provide a comprehensible foundation for people writing C code, for people auditing C code, and for people formally verifying C code.

...

Overall I think that these people simply don't understand what most C programmers want. A boring C compiler will very quickly gain users---not merely for security but also for predictability in general; people will appreciate, e.g., having variables automatically initialized to 0. Of course, the compiler has to support the usual C ABI, so that programs compiled with this compiler can be linked to libraries compiled with other compilers (including other languages), and vice versa, allowing an incremental upgrade process.

А я бы юзал. Чем вспоминать каждый раз, какие там допустимые границы значений, где в этом темном подземелье раскиданы грабли, и надеяться на лучшее (привет, memcpy!), лучше следовать принципу debug once, compile everywhere. Производительность для большинства задач проблема даже не первого десятка, а реальные оптимизации все равно всегда были hand-crafted.

Кто что думает?

Перемещено JB из talks

★★

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

Довольно давно в clang и gcc появился Undefined Behavior Sanitizer. Так что кому надо может найти места с UB в своем коде и подумать головой, что с ними делать. Поэтому компилятор, который страдает определенным поведением в неопределенных местах ненужен, ибо, наверняка, он не сможет использовать многие оптимизации, которые возможны при наличии UB. Кроме того, компиляторы пишут люди и они стараются делать так, чтобы UB было наиболее определенным и предсказуемым, кроме тех мест, где совсем ничего другого сделать не получится.

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

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

Сколько уже можно? Дайте уже сишке завоевать мир!

Сишка уже давно завоевала мир, просто ты этого не замечаешь.

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

Проблематично убрать UB оставив при этом операции с указательными и ручным высвобождением памяти.

Смотря что считать «ручным управлением». Вещи типа unique_ptr, как по мне, всё-таки ручное управление и уж точно не GC о которым изначально речь шла. При этом вероятность ошибки снижается.

Можно пойти дальше - ввести дополнительные ограничения типа как в расте и обеспечить ещё большие гарантии. Естественно, ценой этих самых ограничений.

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

Как тут избавиться от UB? На шаге 5 при обращении получится мусор вместо данных.

Использовать вместо «простых указателей» что-то типа shared_ptr из С++. Мы ведь о гипотетической ситуации в произвольном языке говорим? Потому что С с рядом ограничений, как тут предлагается, тоже не совсем С.

DarkEld3r ★★★★★
()

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

Если серьёзно, то заведомо UB - в сущности ошибка, компиляция на этом должна прекращаться.

Deleted
()

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

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

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

Нет никаких способов проактивно узнать, есть в сишкином коде UB или нет (не считая кропотливого аудита с формальными доказательствами касательно участков кода, что никто не в силах оплатить). Только запуск и тестирование: во всех режимах, на всех границах. Это все уже делается, DJB лишь предлагает сделать такое расширение, которое не будет *внезапно* добавлять новых кейсов. Хочет поменять false-negative на false-positive, что имхо вполне разумно.

arturpub ★★
() автор топика

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

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

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

Хм. Собирать с "-O0" ?

Manhunt ★★★★★
()

выберет к-л конкретное поведение для всех сортов UB

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

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

Речь не о том, чтобы запретить веселую сишку, а о том, чтобы наконец уже сделать скучную — ее ведь нет.

arturpub ★★
() автор топика

Оппа, не ожидал откровенного ламерства от Бернштейна.

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

Итак, мы говором о новом языке, всего лишь чуть более строгом чем C. Ну а тут ответ очевиден - он не нужен. Проблемы, проистекающие из неопределённого поведения - далеко не все и даже не основные проблемы C, а новый язык решает только их. При этом требуя нового компилятора (ладно если, гипотетически, его напишут как -std=bernstein-lamo для gcc/clang, но если это будет отдельная поделка где заново будут писат поддержку оптимизаций, векторных инструкций, arm и т.д. то вообще занавес).

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

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

Мы ведь о гипотетической ситуации в произвольном языке говорим?

Нет, мы вроде говорили о языке, который максимально похож на Си, лучше всего просто об особом компиляторе Си, и обязательно с сохранением совместимости по ABI. Это главная жалоба Бернштейна на все проекты типа «Safe C»: они изменяют ABI.

Да и потом, если ты вручную освободишь место, на которое ссылается shared_ptr, огребёшь точно так же неопределённое поведение.

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

А можно примеры таких программ? Хочу держаться от них как можно дальше.

#include <stdio.h>
#include <limits.h>
 
int main(void) {
	printf("%d", INT_MAX);
	return 0;
}
anonymous
()
Ответ на: комментарий от andreyu

А где тут UB?

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

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

А где тут UB?

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

Если программа зависит от рандома или пользовательского ввода, это не говорит о наличии в ней UB.

andreyu ★★★★★
()

Мужик дело говорит про тот ужас, что сейчас в си. Но, имхо, надо не просто новый компилятор, а #pragma strict в стандарте, с частичной потерей совместимости. И со строгой типизацией ;)

having variables automatically initialized to 0

Забавно, то же самое предлагает Майерс в C++17. До сишников явно что-то начинает доходить :D

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

Если тебе нужна безопасность и не оч важна производительность,

Нужно и то и то. Потоковая дешифровка большого объема трафика, например.

JANB
()

Ммм, костыли-костылики. Нет, чтобы нормальный язык использовать.

quantum-troll ★★★★★
()
Ответ на: комментарий от DarkEld3r

unique_ptr это не ручное управление, а RAII.

Можно конечно попробовать побороться с UB вписав в стандарт: если free() получает то, что предварительно не было получено от malloc() или уже обрабатывалось free() и при этом не-NULL, то free() возвращает ошибку. Но это усложнит реализацию.

Но с возможностью манипулировать указателями всё гораздо сложнее. Указатель по определению может указывать куда угодно. И каждый раз, когда он указывает куда не надо, получается потенциальное UB. При этом во время промежуточных операций это нормальное явление. Проще отказаться от указателей в том виде, в каком они присутствую в C, вообще, чем научить программу проверять их корректность. А нужность C без его указателей сомнительна.

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

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

Aswed ★★★★★
()

который навсегда выберет к-л конкретное поведение для всех сортов UB

UB на то и UB, что компилятор волен делать что хочет.

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

Я вообще не уверен, что ядро можно собрать чем-то кроме gcc, а даже если получится, то оно не упадёт при первом же запуске.

ICC, Clang. С разморозкой.

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

Во-первых, этот пример не жизненный

он на то и пример. вот тебе другой

int f(int a, int b)
{
  return a << b;
}

int main(int ac, char *av[])
{
  int r = atoi(av[1]);
  return f(42, r);
}
./a.out -1

так что не понятно, в чём именно твоя проблема

в том, что не всегда в компайлтайм известно, что будет ub.

В-третьих, как спасёт от этого т.н. boring c?

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

Что, если на платформе char имеет 12 бит?

это вообще не в тему.

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

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

В описании говорится, что unique_ptr

Manages the storage of a pointer, providing a limited garbage-collection facility, with little to no overhead over built-in pointers (depending on the deleter used).

Кстати говоря, по своей природе unique_ptr не защищает от UB. В нём тоже можно при желании скормить хрен пойми что free().

Как я уже выше писал, чтобы защитить ручную работу выделением/высвобождением памяти, можно переделать malloc()/free(). Только есть подозрение, что это не так уж просто

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

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

Так рандом или пользовательский ввод вместо MAX_INT - это UB или нет?
Если нет, то в каком месте MAX_INT вдруг стал UB?

ты ничего не путаешь?

Нет, ничего.

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

Кстати говоря, по своей природе unique_ptr не защищает от UB.

Ну да, 100% гарантий нет, но получить UB всё-таки «чуть-чуть сложнее».

Не уверен что unique_ptr корректно рассматривать как способ управления памятью, не важно какой.

Почему?

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

Почему?

Потому что обёртка над имеющимися механизмами. Но это смотря с какой стороны посмотреть.

omnomnomnus
()

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

Iron_Bug ★★★★★
()

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

да? зачем тогда вообще на С писать?

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

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

Так там не будет разыменования, т.к. это просто выражение внутри typeof

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

Неправильная арифметика указателей может привести к UB. Двойной free() или освобождение памяти не выделенной с помощью malloc() это тоже UB. Проблематично убрать UB оставив при этом операции с указательными и ручным высвобождением памяти.

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

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

Есть, называется java.

Java не имеет ни малейшего отношения ни к С++, ни тем более - к С. Её корни - в Паскале и Обероне Никлауса Вирта.

LongLiveUbuntu ★★★★★
()

к-л конкретное поведение для всех сортов UB

удачи </thread>

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

Тем не менее синтаксически очень похожа.

Чтобы плюсовики при переходе не так пугались.

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

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

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

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

можно ограничиться x86-64 и ARM - остальное ненужно

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

на платформе char имеет 12 бит?

в жопу платформы - только x64 и ARM

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