Про memcpy, memmove и Open Source

Кто не читал книжку Кернигана и Ритчи — сразу может скроллить до следующего поста. Остальные насладятся замечательной историей, почерпнутой у [info]avva.

В общем, так исторически сложилось, что в языке программирования Си есть две функции, которые копируют произвольные области памяти. Одна называется memmove — memory move, другая — memcpy, memory copy. Они имеют одинаковый синтаксис, но работают немного по-разному. Первая правильно копирует данные, когда области перекрываются, вторая — нет, но работает «чуть-чуть» быстрее. Естественно, что программисты эти функцию путают, и один из авторов языка Си, Брайан Керниган в своей книге «Практика программирования» даже высказался на этот счет:

В стандарте ANSI C определены две функции: memcpy, которая работает быстрее, но может затереть память, если источник и приемник данных пересекаются, и memmove, которая может работать медленнее, но всегда корректна. Бремя выбора между скоростью и корректностью не должно взваливаться на программиста; должна быть только одна функция. Считайте, что это так и есть, и всегда используйте memmove.

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

В общем, разработчики одной из наиболее распространенных реализаций этих функций — библиотеки glibc, использующейся практически во всех Linux-образных операционках, решили, что хорошо бы немного доработать memcpy, чтобы та работала еще быстрее, при этом сделав так, что она совсем перестала работать с перекрывающимися областями в памяти. Эта версия библиотеки прошлым летом была включена в дистрибутив Fedora — и вскоре обнаружилось, что некоторые программы перестали работать. Баг искали несколько месяцев, пока не поняли, что дело в том, что авторы этих программ понадеялись на то, что memcpy всегда будет правильно работать в тех самых «неправильных» случаях.

После этого началась веселуха. Авторы glibc, и «по совместительству» — разработчики Fedora — заявили, что никакого бага нет, а во всем виноваты криворукие программисты. Линус Торвальдс (живой бог для всех линуксоидов) пишет примерно следующее:

You can call it «crap software» all you like, but the thing is, if memcpy doesn’t warn about overlaps, there’s no test coverage, and in that case even well-designed software will have bugs.

Then the question becomes one of «Why break it?»

и

Quite frankly, I find your attitude to be annoying and downright stupid.

How hard can it be to understand the following simple sentence:

THE USER DOESN’T CARE.

Если у пользователя после обновления ОС не работает кривой Flash-плагин — то пользователь не будет винить в этом криворуких разработчиков плагина, а будет винить разработчиков ОС. Разработчики glibc этого не понимают и их главарь, Ульрих Дреппнер, подводит вот такой итог под всей этой дискуссией:

The existence of code written by people who should never have been allowed to touch a keyboard cannot be allowed to prevent a correct implementation.

Как же это не похоже на ту идеологию, которую проповедует Raymond Chen из Microsoft. Но вся эта история объясняет, почему на большинстве пользовательских ПК все еще стоит Windows.

PS В итоге до сих пор в glibc остается новая версия memcpy. Обнаружилось, что в огромном количестве программ программисты полагались на недокументированное поведение этой функции, где-то исправили, а где-то — нет.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *