Русский
Русский
English
Статистика
Реклама

Ревью кода

Перевод 8 лучших практик предотвращения SQL-инъекций

26.05.2021 14:12:47 | Автор: admin

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

К старту курса "Этичный хакер" мы решили поделиться именно этой статьёй, потому что она не только предлагает памятку по инъекциям, но и знакомит с платформой snyk.io сканером на уязвимости, который для проектов с открытым исходным кодом можно использовать совершенно бесплатно, а значит, он будет полезен для пет-проектов многих разработчиков и читателей Хабра. По этой причине публикация попала и в хаб Программирование.


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

Например, SQL-инъекции могут быть такими:

  • добавление к фразе where булева оператора, который делает это условие всегда выполняющимся ' OR 1=1;

  • удаление части запроса путём ввода строчных комментариев --;

  • завершение исходного запроса и запуск нового запроса '; DROP TABLE USERS;

  • соединение данных из нескольких таблиц с помощью оператора UNION.

В этой памятке я подробно рассмотрю 8 оптимальных методов, которые можно применять в любом приложении в целях предотвращения атак через SQL-инъекции. Итак, давайте начнём и сделаем ваше приложение действительно защищённым от SQL-инъекций.

Загрузить памятку

  1. Не полагайтесь на проверку вводимых данных на стороне клиента.

  2. Ограничивайте полномочия пользователя базы данных.

  3. Используйте предварительно подготовленные опраторы и параметризацию запросов.

  4. Сканируйте код, чтобы обнаружить уязвимость к SQL-инъекциям

  5. Используйте слой ORM.

  6. Не полагайтесь на чёрные списки.

  7. Выполняйте проверку вводимых пользователем данных.

  8. С осторожностью используйте хранимые процедуры.

1. Не полагайтесь на проверку вводимых данных на стороне клиента

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

Но применительно к SQL-инъекциям это не тот метод защиты, на который действительно можно положиться. Проверку вводимых данных на стороне клиента легко можно отключить, изменив некоторый код javascript, загруженный в ваш браузер. Кроме того, в архитектуре клиент-сервер очень легко выполнить простейший HTTP-вызов серверного приложения, используя в нём параметр, вызывающий SQL-инъекцию. Также это можно сделать, используя различные инструментальные средства, такие как postman, или старые добрые команды curl.

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

2. Ограничивайте полномочия пользователя базы данных

Как уже было упомянуто, существует несколько типов атак с использованием SQL-инъекций. Некоторые из них более опасны, чем другие. Представьте, к примеру, что мой SQL-запрос имеет вид "SELECT * FROM USER WHERE USERID = '" + userid +"'". Инъекция " foo' OR '1'='1 " предоставит доступ ко всем пользователям, и это само по себе очень опасно. Однако инъекция " '; UPDATE message SET password = 'EVIL приведет к ещё большим проблемам, поскольку злоумышленник в этом случае изменит все записи.

Создавая пользователя в базе данных для вашего приложения, вы должны подумать о его полномочиях. Действительно ли приложению необходима возможность считывать, записывать и обновлять все базы данных? Должны ли быть у него полномочия для выполнения команд truncate и drop в отношении таблиц? Если вы сами ограничите полномочия своего приложения при работе с базой данных, то таким образом можно снизить и потенциальный вред от SQL-инъекций. Наверное, правильным будет создание для приложения нескольких пользователей базы данных и назначение им определённых ролей. Проблемы с безопасностью, как правило, вызывают эффект цепной реакции, поэтому необходимо контролировать все звенья вашей цепи, чтобы предотвратить тяжёлые последствия.

3. Используйте предварительно подготовленные операторы и параметризацию запросов

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

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

Пример на Java:

String query = "SELECT * FROM USERS WHERE username LIKE ?";PreparedStatement statement = connection.prepareStatement(query);statement.setString(1, parameter);ResultSet result = statement.executeQuery();

Пример на Python с коннектором MySQL:

cursor = conn.cursor(prepared=True)params = ("foo",)cursor.execute("SELECT * FROM USERS WHERE username = %s", params)

Пример на JavaScript с mysql2:

connection.query("SELECT * FROM USERS WHERE username = ?",[     req.body.username    ],function(error, results){}); //emulates a prepared statement//ORconnection.execute("SELECT * FROM USERS WHERE username = ?",[     req.body.username    ],function(error, results){});//prepared statement

Тем не менее существует несколько способов сделать это в JavaScript при использовании, например, базы данных MySQL. Учитывайте, что при использовании функции .query() подготовленный оператор не выполняется. В этом случае подстановка параметров осуществляется на стороне клиента, то есть происходит эмуляция подготовленного оператора. Чтобы сделать настоящий подготовленный запрос к базе данных, следует использовать функцию .execute().

4. Сканируйте код, чтобы обнаружить уязвимость к SQL-инъекциям

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

Используя такой инструмент SAST (технология статического тестирование безопасности приложений), как Snyk Code, вы можете автоматически проверять свой код и обнаруживать в нём угрозы безопасности, включая SQL-инъекции. Этот процесс можно легко автоматизировать в SDLC, например, подключив к Snyk ваш Git-репозиторий.

5. Используйте слой ORM

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

Одним из ярких примеров использования библиотек ORM является применение решений Hibernate для Java и Entity Framework для C#. Эти языки строго типизированы, а значит, в них есть возможность устанавливать соответствие между объектами и таблицами в базах данных. Таким образом, у вас есть возможность полностью отказаться от самостоятельного формирования каких-либо SQL-запросов.

Тем не менее проблема всё равно возникнет, если потребуется написать свои собственные запросы. В библиотеке Hibernate для Java предусмотрен даже собственный язык написания запросов HQL (Hibernate Query Language). При создании запросов на HQL опять же нужно помнить о возможных инъекциях и использовать функцию createQuery(), которая работает аналогично подготовленным операторам.

Для языка JavaScript также существуют хорошо известные библиотеки ORM, такие как sequelize. С помощью sequelize вы сможете определить, как значения будут отображаться в определённые типы в базе данных. Но давайте смотреть правде в глаза, в конечном счёте любой библиотеке ORM требуется преобразование её внутренних логических команд в операторы SQL. Мы верим, что в библиотеках экранирование параметров реализовано правильно.

Чтобы быть уверенным, что в вашей библиотеке ORM нет проблем с SQL-инъекциями, необходимо выполнить её сканирование с целью выявления известных уязвимостей. Работа с некорректной, устаревшей версией библиотек sequelize или hibernate может стать причиной больших проблем. Используя Snyk Open Source для проверки своего проекта, вы сможете защититься от скрытых SQL-инъекций в применяемых библиотеках, а также от многих других потенциальных угроз.

Использование Snyk совершенно бесплатно

Вы можете сразу приступать к работе со Snyk Open Source. Всё, что для этого нужно, пройти регистрацию на получение бесплатного аккаунта.

6. Не полагайтесь на чёрные списки

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

Например, мы можем блокировать все запросы, где содержится слово OR. Возможно, в этом даже есть какой-то смысл, но на практике оказывается, что Or это очень часто встречающееся в Израиле имя. И это означает, что множество моих коллег будут блокироваться при попытке ввода своих имён. То же самое справедливо для одиночных кавычек '. Этот символ содержится в огромном количестве имён. Подумайте о пользователях с фамилиями ONeill и ODonnell. А ведь есть ещё и имена, такие как Donta.

7. Выполняйте проверку вводимых данных

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

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

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

8. С осторожностью используйте хранимые процедуры

Многие верят, что работа с хранимыми процедурами это хороший способ защититься от SQL-инъекций. Но это не всегда так. Подобно SQL-запросам, созданным в вашем приложении, хранимые процедуры также подвержены инъекциям со стороны злоумышленников.

И, так же как и в случае с SQL-запросами, вам следует использовать в хранимой процедуре параметризованные запросы вместо добавления параметров. SQL-инъекции в хранимой процедуре достаточно легко предотвратить. Но не пытайтесь сделать это в MySQL:

DELIMITER //CREATE PROCEDURE `FindUsers`(    IN Username VARCHAR(50))BEGIN    SET @Statement = CONCAT('SELECT * FROM User WHERE username = ', Username, ' );    PREPARE stm FROM @Statement;    EXECUTE stm;END //DELIMITER ;

Вместо этого лучше используйте в своих хранимых процедурах параметризованные запросы:

DELIMITER //CREATE PROCEDURE `First`(    IN Username VARCHAR(50))BEGIN    PREPARE stm FROM 'SELECT * FROM User WHERE username = ?';    EXECUTE stm USING Username;END //DELIMITER ;

Как показано выше, к хранимым процедурам применяются те же правила, что и к коду приложения. Способы применения хранимых процедур различаются в зависимости от используемой базы данных. Убедитесь, что вы хорошо представляете себе, как хранимые процедуры реализуются в используемой вами базе, и также будьте бдительны в отношении возможных инъекций. Хоть я и уверен, что лучше всего убрать всю логику внутрь вашего приложения, но хранимые процедуры также могут быть разумным решением, если используемый вами язык программирования не поддерживает работу с предварительно подготовленными операторами.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Код ревью как быть хорошим автором

02.03.2021 16:05:07 | Автор: admin

Привет! Меня зовут Сергей Загурский, я работаю в Joom в команде инфраструктуры. В своей практике ревьюера кода я регулярно сталкиваюсь с тем, что автор не понимает, что ревьюер не является волшебным чёрным ящиком, в который можно закинуть любые изменения и получить по ним обратную связь. Ревьюер, как и автор, будучи человеком, обладает рядом слабостей. И автор должен (если, конечно, он заинтересован в качественном ревью), помочь ревьюеру настолько, насколько это возможно.

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

Зачем мы делаем ревью кода

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

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

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

На примитивном уровне ревью кода также является моделью того, как с написанным кодом будет идти взаимодействие в дальнейшем. Если у ревьюера не возникает никаких проблем с пониманием, значит и при чтении или отладке кода в будущем также сложностей не будет. И наоборот, если ревьюер не может ничего понять, то это write only код. Его развитие и отладка будут стоить дороже.

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

Дальше мы сосредоточимся на самой фундаментальной составляющей процесса ревью на понимании кода.

Как ревьюер делает ревью

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

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

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

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

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

Также нужно помнить, что ревьюер, будучи человеком, склонен откладывать начало ревью на потом, если видит ревью повышенной сложности. Вежливый ревьюер может постесняться потребовать разбить большой Pull Request на несколько и будет платить за это своим временем и качеством ревью.

Как помочь ревьюеру провести качественное ревью

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

Перед тем, как превратить свои изменения в Pull Request, следует разбить их на логические куски, если в этом есть необходимость. Комфортный объём ревью заканчивается примерно на 500 строках кода изменений. Допустимый примерно на 1000 строках. Всё, что за пределами 1000 строк, должно быть разбито на более мелкие Pull Requestы.

Если вы, как и я, не разбиваете свои изменения на куски комфортного размера заранее, то это придётся проделать перед отправкой ваших изменений на ревью. Отмазка, что на это нужно потратить время, не катит. Принимая решение об отправке на ревью 1000+ строк кода, вы, фактически, оцениваете своё время дороже времени ревьюера. По нашим правилам у ревьюера всегда есть право потребовать разбить изменения на более мелкие куски. Мы всегда просим коллег относиться с пониманием, если он этим воспользуется. С опытом становится проще строить свою работу так, чтобы у вас не появлялись гигантские Pull Requestы, в которых ничего нельзя отделить.

Отдельно стоит упомянуть изменения, внесённые в код с помощью авторефакторинга или sedа. Объём таких изменений может быть очень большим. Наличие автоматических изменений вместе с осмысленными изменениями усложняет ревью. Всегда отделяйте авторефакторинги в отдельные Pull Requestы, если их объём сопоставим с объёмом нового кода, написанного вами.

Следующая часть подготовки состоит в информировании ревьюера о сути изменений. Как я уже писал выше, ревьюеру нужно знать: что сделано, зачем сделано, как сделано, и почему именно так сделано. Часть информации у ревьюера уже может быть. Часть есть в коде. Всё, что не очевидно из кода, должно быть прописано в описании изменений.

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

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

Итак, автор подготовил изменения к ревью. Пора отправлять ревьюеру? Нет! Тут наступает ещё один важный этап, саморевью. Под саморевью я понимаю именно ревью, осуществлённое самим автором. Не просто беглый визуальный контроль. Нужно постараться провести полноценное ревью. Ответственно проведённое саморевью сэкономит уйму времени ревьюеру. Наверняка в коде есть какие-то остатки отладочных конструкций, закомментированного кода, TODO-комментариев, бессмысленных изменений форматирования, не пригодившегося кода и прочего подобного. Взгляд глазами ревьюера также поможет оценить сложность ревью и даст возможность добавить дополнительной информации к ревью, которая была упущена при подготовке. Пренебрежение автором саморевью я считаю проявлением крайнего неуважения к ревьюеру.

В целом, я считаю допустимым потратить порядка 10% от времени, затраченного на написание кода, на подготовку к ревью. Это время автора, которое мы обменяем на экономию времени ревьюера, и на улучшение качества ревью. Следует помнить, что ревьюеру на качественное ревью легко может потребоваться и 20%, и 50% от времени, затраченного автором на написание кода.

Вот только теперь автор может с чистой совестью отправить изменения ревьюеру.

Дальше начинается жизненный цикл Pull Requestа. Ревьюер должен либо одобрить его, либо попросить внести изменения. Чтобы упростить работу ревьюера, автору стоит добавить комментарий к каждому запрошенному изменению. Это вполне может быть краткое OK или Исправил, если ничего другого не требуется. Убедитесь, что вы понимаете, что просит ревьюер и что вам понятна его аргументация. Не стоит безоговорочно принимать любые запросы на внесение изменений, возводя тем самым ревьюера в околобожественный ранг. Ревью это обоюдный процесс. Если ревьюеру что-то не понятно, то он спрашивает об этом автора, и наоборот. В случае, если автор не очень опытен, ревьюеру следует приложить особенные усилия к описанию запросов на изменения, чтобы воспользоваться возможностью поделиться с автором своим опытом. Бывают и спорные моменты, когда аргументация недостаточно сильная, чтобы склонить обе стороны к единой точке зрения. С учётом того, что автор находится в более уязвимой позиции, считаю, что при прочих равных преимущество должно оставаться за автором.

Не вносите изменений в свой Pull Request, не относящихся к тому, что попросил вас ревьюер. Это крайне сбивает с толку. Также следует воздержаться от rebase и подобных действий.

Получили одобрение от ревьюера? Отлично, ещё одно качественно написанное и оформленное изменение было добавлено в проект!

Подробнее..

Пример полезного комментария

22.03.2021 16:16:43 | Автор: admin

Пример полезного комментария


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


Код, который мы рассмотрим далее, был выписан в процессе работы над статьёй "Обработка дат притягивает ошибки или 77 дефектов в Qt 6".


Анализатор PVS-Studio обратил внимание на этот фрагмент кода, выдав предупреждение: V575 [CWE-628] The 'memcpy' function doesn't copy the whole string. Use 'strcpy / strcpy_s' function to preserve terminal null. qplaintestlogger.cpp 253. Собственно, вот он:


const char *msgFiller = msg[0] ? " " : "";QTestCharBuffer testIdentifier;QTestPrivate::generateTestIdentifier(&testIdentifier);QTest::qt_asprintf(&messagePrefix, "%s: %s%s%s%s\n",                   type, testIdentifier.data(), msgFiller, msg,                   failureLocation.data());// In colored mode, printf above stripped our nonprintable control characters.// Put them back.memcpy(messagePrefix.data(), type, strlen(type));outputMessage(messagePrefix.data());

Обратите внимание на вызов функции memcpy. Сам по себе этот код вызывает сразу два вопроса:


  1. Зачем что-то записывается в буфер, содержимое которого было только что сформировано с помощью printf-подобной функции?
  2. Точно не ошибка, что не копируется терминальный ноль? Это как раз и не нравится анализатору.

К счастью, комментарий сразу всё проясняет. Нужно восстановить некие непечатаемые символы.


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


Для сравнения рассмотрим другой фрагмент кода из этого же файла:


char buf[1024];if (result.setByMacro) {  qsnprintf(buf, sizeof(buf), "%s%s%s%s%s%s\n", buf1, bufTag, fill,            buf2, buf2_, buf3);} else {  qsnprintf(buf, sizeof(buf), "%s%s%s%s\n", buf1, bufTag, fill, buf2);}memcpy(buf, bmtag, strlen(bmtag));outputMessage(buf);

Здесь забыли сделать аналогичный комментарий. И картина радикально меняется. Этот код способен ввести в замешательство нового члена команды, который будет его сопровождать или модифицировать. Совершенно не понятно, зачем нужен этот memcpy. Более того, непонятно, почему в начало строки печаталось содержимое некоего буфера buf1, а затем в начало строки помещается содержимое буфера bmtag. Как много вопросов, как мало ответов. Не стоит писать такой код.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. One Useful Comment.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru