Как писать на C и не стрелять себе в ногу. Создатель curl устал отбиваться и запретил strncpy
NewsMakerПочему разработчики переписали копирование строк и что это меняет для безопасности.
Есть функции, которые в языке C выглядят как удобные мелочи, но на практике годами собирают вокруг себя ошибки. В проекте curl одну из таких уже «вынесли» из кода, а теперь решили добить и вторую. Разработчик curl Даниэль Стенберг рассказал , почему команда полностью отказалась от strcpy и чем заменяет привычное копирование строк.
Раньше curl уже прошел похожую чистку. В проекте избавились от всех вызовов strncpy. У этой функции, по словам Стенберга, слишком коварный характер: она может не поставить завершающий ноль в конце строки и при этом заполняет буфер нулями до конца, что часто приводит к неожиданным последствиям. В большинстве кодовых баз, считает он, каждый вызов strncpy потенциально является ошибкой. При переписывании команда придерживалась простого правила: либо копируем строку целиком и корректно, либо возвращаем ошибку. Частичное копирование редко бывает правильным выбором, а если вдруг нужно именно оно, это проще и честнее сделать через memcpy и явно поставить нулевой байт в нужном месте.
С strcpy ситуация тоньше. У нее, как ни странно, более понятный интерфейс, и у функции есть легитимные сценарии применения. Проблема в другом: strcpy не принимает размер буфера назначения и не знает длину исходной строки. В идеальном мире это не страшно, потому что в C ее используют только там, где разработчик полностью контролирует и источник, и приемник. Но «в идеальном мире» и «всегда» не одно и то же. Ошибаются все, а код в таких проектах живет десятилетиями, постоянно меняется и обрастает правками разных людей.
И вот здесь появляется главная угроза. Использование strcpy почти всегда означает, что где-то раньше по коду уже были проверки размеров, которые гарантируют безопасность копирования. Если все сделано аккуратно, между проверкой и самой копией ничего не успевает измениться. Но в реальном проекте со временем эти части кода могут «разъехаться»: проверки перенесут, условия поменяют, добавят новую ветку, и в какой-то момент вызов strcpy окажется слишком далеко от того места, где изначально подтверждалось, что места хватает. Чем больше дистанция между проверкой и копированием, тем выше шанс, что по дороге кто-то невольно сломает гарантию.
Есть функции, которые в языке C выглядят как удобные мелочи, но на практике годами собирают вокруг себя ошибки. В проекте curl одну из таких уже «вынесли» из кода, а теперь решили добить и вторую. Разработчик curl Даниэль Стенберг рассказал , почему команда полностью отказалась от strcpy и чем заменяет привычное копирование строк.
Раньше curl уже прошел похожую чистку. В проекте избавились от всех вызовов strncpy. У этой функции, по словам Стенберга, слишком коварный характер: она может не поставить завершающий ноль в конце строки и при этом заполняет буфер нулями до конца, что часто приводит к неожиданным последствиям. В большинстве кодовых баз, считает он, каждый вызов strncpy потенциально является ошибкой. При переписывании команда придерживалась простого правила: либо копируем строку целиком и корректно, либо возвращаем ошибку. Частичное копирование редко бывает правильным выбором, а если вдруг нужно именно оно, это проще и честнее сделать через memcpy и явно поставить нулевой байт в нужном месте.
С strcpy ситуация тоньше. У нее, как ни странно, более понятный интерфейс, и у функции есть легитимные сценарии применения. Проблема в другом: strcpy не принимает размер буфера назначения и не знает длину исходной строки. В идеальном мире это не страшно, потому что в C ее используют только там, где разработчик полностью контролирует и источник, и приемник. Но «в идеальном мире» и «всегда» не одно и то же. Ошибаются все, а код в таких проектах живет десятилетиями, постоянно меняется и обрастает правками разных людей.
И вот здесь появляется главная угроза. Использование strcpy почти всегда означает, что где-то раньше по коду уже были проверки размеров, которые гарантируют безопасность копирования. Если все сделано аккуратно, между проверкой и самой копией ничего не успевает измениться. Но в реальном проекте со временем эти части кода могут «разъехаться»: проверки перенесут, условия поменяют, добавят новую ветку, и в какой-то момент вызов strcpy окажется слишком далеко от того места, где изначально подтверждалось, что места хватает. Чем больше дистанция между проверкой и копированием, тем выше шанс, что по дороге кто-то невольно сломает гарантию.