Комментарии 26
Безопасный код должен начинаться с указания void вместо списка аргументов для функций, которые не принимают аргументов, а в ваших примерах этого не наблюдается.
В одном случае функция может не принимать аргументов, а во втором не может принимать аргументов. Это же разные вещи.
Вообще, если не указать void, значит функция может принимать сколько угодно параметров.
Этот пример компилируется:
#include <stdio.h>
static void print_hello() {
puts("Hello World");
}
int main(void) {
print_hello();
print_hello("lol", "kek");
}
clang выводит предупреждение:
test.c:9:29: warning: too many arguments in call to 'print_hello'
print_hello("lol", "kek");
~~~~~~~~~~~ ^
1 warning generated.
До gcc пока не добрался, но, по-моему, он не выводит предупреждение в таких случаях.
Если же добавить void, пример не скомпилируется:
test.c:9:17: error: too many arguments to function call, expected 0, have 2
print_hello("lol", "kek");
~~~~~~~~~~~ ^~~~~~~~~~~~
test.c:3:13: note: 'print_hello' declared here
static void print_hello(void) {
^
1 error generated.
Я добрался до gcc, он и правда не выводит предупреждение, если не указать void вместо списка аргументов, причём даже с флагами -Wall и -Wextra. У меня, если что, gcc версии 13.2.1
/* объявление функции без аргументов */
int no_args();
/* тоже объявление функции без аргументов */
int no_args(void);
Первый вариант означает, что тип и кол-во аргументов не определены (можно писать no_args(1,2,3)), второй вариант означает, что аргументов у функции нет. Первый вариант можно отнести к быдлокоду, он ещё жив, полагаю, для совместимости...
https://habr.com/ru/companies/badoo/articles/503140/comments/#comment_21653930
Или можно компилировать с `-std=c2x` :)
Старший бит отвечает за знак, остальные за само число.
И тут студент получает контрольный вопрос в голову: почему 1 0000000₂ — это (-128), а не (-0).
Можно ещё вот тут про флаги компилятора почитать https://interrupt.memfault.com/blog/best-and-worst-gcc-clang-compiler-flags
Ошибка:
0 - это старший байт и он отвечает за знак.
Не байт, а бит.
Undefined Santizer - Санитайзер, который...
Слово Behavior "выпало":
UndefinedBehaviorSanitizer, a fast undefined behavior detector
Кстати, в первый раз увидел в тексте документации GCC ссылку на llvm.org.
Безопасное программирование на Си
Самый безопасный способ заниматься безопасным программированием на Си - не писать на Си. Отсутвие честных типов делает задачу фактически невыполнимой. Если не следовать какому-нибудь MISRA-гайдлайну и не торчать постоянно в статическом анализаторе - безопасный код на Си будет являться тавтологией.
Не писать на си иногда не вариант, я вот понял, что всякую низкоуровневую фигню ни на плюсах, ни на расте я писать не желаю. Можно, кстати, упороться и писать доказуемо корректные программы на си. А тавтология - это использование одного и того же слова в предложении, разве нет?
попробуйте zig или odin. у первого говорят даже интероперабельность с си максимально приятная.
Доказуемо корректные программы тоже не совсем про безопасность - вполне можно написать доказуемо корректный эксплойт.
Да, с тавтологией это я глупость сморозил. Там какое-то другое слово должно было быть.
Zig показался прикольным, с перспективами, как мне кажется. Есть ещё c2lang - похож на Си, но с методами и некоторыми дополнительными приятными фишками (типа моделей, публичные/приватные функции), недавно компилятор для c2lang даже переписали на сам c2lang, у него полная совместимость с Си и портировать либы можно очень быстро (вроде его даже можно компилировать в Си).
А про тавтологию, может "оксюморон" имели ввиду?
попробуйте zig или odin
Пока zig не выйдет в релиз, смотреть на него особо не хочется. В последний раз я столкнулся с тем, что мне приходилось вместо документации читать исходники, потому что в документации нужной мне информации не было. А вот на odin надо будет посмотреть
Спасибо за статью, привет с МГТУ СМ, а будет ли в будущем статья на тему форматирования вывода scanf и printf , а также указатели?
Здравствуйте.
В будущем планировалась статья, посвященная расширению подхода к выявлению ошибок в том числе при работе с памятью, а именно: вывод компилятора -> (описано в данной статье) -> стат.анализ средствами clang -> динамический анализ средствами ASan, MSan \ Valgrind -> сбор покрытия.
Также планирую рассмотреть типовые ошибки при работе с массивами и памятью.
Возможно будет переход к фаззинг тестированию
Про форматированной ввод/вывод планов не было, этому посвящен отдельный абзац статьи. А что именно Вам интересно?
P.s. Статья писалась для студентов МИФИ, рад, что студентов МГТУ она тоже заинтересовала)
scanf вообще лучше не использовать. А какие могут быит проблемы с printf, если сейчас компиляторы выводят предупреждения о несоответствии заявленного формата вывода и переданных аргументов?
Чем Вас не устраивает scanf для ввода целых чисел? Тем более в лабораторных работах первого курса?
В лабораторных работах можно, но в реальных проектах лучше его не использовать. Там куча не очевидных вещей, можно подробнее здесь прочитать
Мне понравилась шутка, про безопасное программирование на си:)
Безопасное программирование на Си. Часть 1