LINUX.ORG.RU
ФорумTalks

С++ имеет синтаксис для некорректных функций

 


0

2

В С++ (даже 17) можно не писать return в функции, которая должна что-то возвращать. Это скомпилируется. Но в рантайме, при вызове этого метода прога упадет с кодом ошибки.

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

Вы там охренели? Это вообще нормально? Алло, не бросайте трубку.

★★★★☆
Ответ на: комментарий от tailgunner

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

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

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

Выигрыш только в одном — если ты не тестируешь функцию, а там баг, то ты не получишь SIGSEGV.

Неверно. SIGSEGV - это редкое счастье. Обычно память молча прописывается или из нее читается мусорное значение. А в Rust (safe Rust) это невозможно.

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

Эт в NULL-то пишется? Про мусорную память спору нет, Rust все упрощает. Только и тестов на мусорную память никто и не пишет. Разве что фаззеры, но они и другие баги ловят.

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

А теперь расскажи мне, почему пару ptr/NULL проверять нужно, а Option — нет, хотя логические ошибки могут быть в обоих случаях.

Потому, что Option проверяет компилятор и к None я обратится не могу.

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

Потому, что Option проверяет компилятор и к None я обратится не могу.

То есть ветвлений не существует, и в зависимости от None там или нет, не может быть выполнен разный код? Иначе проверить все-таки придется.

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

То есть ветвлений не существует, и в зависимости от None там или нет

То есть у указателя есть 2 способа быть неверно использованным - разыменование и проверка, а у Option - только один: проверка. // К.О.

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

Тебе картинку нарисовать? (с)

Если я в C пропущу проверку на валидность указателя - получу SEGFAULT/UB. В Rust я её пропустить физически не могу.

Именно поэтому std::options из C++ и убог, так как я могу обратится к std::nullopt и компилятору на это пофиг.

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

Если я в C пропущу проверку на валидность указателя - получу SEGFAULT/UB. В Rust я её пропустить физически не могу.

Ну давай на примерах, чего уж там:

fn jwt_is_valid(jwt: Option<Jwt>) -> bool {
. . .
}

Как думаешь, стоит такую функцию проверять?

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

Невалидный - это какой? К памяти это отношения не имеет. А мы обсуждаем именно её.

Имеет, и самое прямое. Не отвлекайся. Так как думаешь, будем к этой функции тест писать? :)

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

Жалуется на tailgunner'a, а из самого мысль тисками не вытащить.

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

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

Допустим. И?

Чтобы полностью покрыть все входные значения, что мы должны на вход подать? Nothing, Some<Jwt> (валидный) и Some<Jwt> (невалидный), так?

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

Предвещая будущий тупняк:

Если я в C пропущу проверку на валидность указателя - получу SEGFAULT/UB. В Rust я её пропустить физически не могу.

Поэтому в C проверять на NULL нужно обязательно, а в Rust - опционально.

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

Отлично, а теперь смотрим на C версию:

bool jwt_is_valid(struct jwt *jwt)

И тот же самый тест будет выглядеть абсолютно так же. Те же самые три значения. И, ещё раз: для QA разница в объемах тестирования крайне мизерная.

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

Поэтому в C проверять на NULL нужно обязательно, а в Rust - опционально.

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

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

И нет, тебе придется его проверять.

Нет. Потому, что в Rust я не могу забыть его проверить, а в С - могу.

Итого: получаем (в теории) логическую ошибку в Rust и UB в C. Что лучше? КО.

Мораль в том, что в Си я не могу гарантировать, что не NULL указатель ссылается на реальную память. В Rust - могу (учитывая возможные нюансы). Поэтому получаем два-три теста в Rust vs три теста в C + Heisenbug, которому плевать на тесты.

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

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

Проблема в том, что heartbleed намекает на то, что тесты в контексте работы с памятью в C - бесполезны.

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

Мы получаем три теста везде. Safe Rust действительно дает гарантию того, что память всегда валидна, и с этим я не спорил.

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

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

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

Ваше мнение очень важно для нас.

Я уже приводил пример с динамически типизированным языком и статическим. Что там не понятно - я хз.

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

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

man теория вероятности

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

что мы должны на вход подать? Nothing, Some<Jwt> (валидный) и Some<Jwt>

Но если мы решим, что jwt_is_valid(Nothing) не имеет никакого смысла и избавимся от Option, передавая сразу Jwt, тогда проверка на Null не нужна

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

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

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

В других случаях и нет смысла проверять на NULL, раз мы подразумеваем, что указатель есть всегда. Что ты будешь делать, если его нет?

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

раз мы подразумеваем, что указатель есть всегда.

Что указатель есть всегда в сишке это еще нужно протестировать :)

Что ты будешь делать, если его нет?

Исправлять ошибку в коде.

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

Да, окей, у нас есть два чёрных ящика (функции). Формат входа и формат выхода которых одинаков. Естественно, что и тестировать мы должны их одинаково. Однако! У Rust кишки этого чёрного ящика будут написаны а) безопаснее и б) более выразительно. Что же нам это даёт?

1) Ошибок, которые покрывают эти одинаковые тесты, в Rust будет меньше. А значит, меньше времени на багфиксы.

2) Ошибок, которые одинаковые тесты не покрывают, в Rust будет меньше. Значит, приложение будет работать более стабильно.

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

Что указатель есть всегда в сишке это еще нужно протестировать :)

Нет, он есть всегда. Вопрос что там внутри.

Исправлять ошибку в коде.

Я не о том. Вот вставил ты проверку, она прошла успешно, нульпоинтер. А дальше-то что?

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

Не спорю. Времени на отладку мы потратим меньше. Но работы в QA сильно меньше не станет. Это просто типа разные задачи, чего некоторые не понимают.

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

Вот вставил ты проверку, она прошла успешно, нульпоинтер. А дальше-то что?

Я хочу не if в коде, а чтобы компилятор проверил, что null туда никак не придет, если мне не нужен Option, а нужно значение и всё.

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

Да. Если у меня есть функция, которой нужно конкретное значение, а не Option, то раст за меня проверит, что туда null не придет. В случае сишки нужно сделать тест, что если каким-то макаром туда придет null, чтобы программа не закрешилась.

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

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

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

Ну это крайний случай. Твои программы не должны так делать :)

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

Для этого тебе нужно нормальное тестирование, которое тебе нужно в любом случае. И резервирование, которое тоже нужно в любом случае.

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

Я так понял, вы имели опыт написания софта для мобильного банка? И каждую функцию обкладывали тестами по самое не балуй?

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

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