LINUX.ORG.RU

Изменение поведения memcpy в glibc привело к странным ошибкам

 ,


0

2

Изменение поведения функции memcpy() в реализации glibc для x86_64 (для ia-32 ничего не изменилось) привело к странным ошибкам во многих программах. Например, искажению звука при проигрывании.

Проблема в том, что memcpy для перекрывающихся участков памяти теперь работает некорректно (как в общем-то и должно быть согласно документации). Но, как выяснилось, авторы многих проектов документацию не читали.

Несмотря на появление в обсуждении Линуса Торвальдса, у которого также появились проблемы со звуком в некоторых программах на его компьютере, ошибка была закрыта по причине «not a bug». В сообщении #38 Линус предлагает способ обхода этой проблемы.

>>> Подробности

★★★★★

Проверено: anonymous_incognito ()
Последнее исправление: Dendy (всего исправлений: 5)

Ответ на: комментарий от AVL2

>основание?

куцая документация, необходимость сделать что-то выходящее за рамки стандартного.

это фигня, а не основания

//лирика: у меня однажды был такой тимлид, ой как хреново было работать

>4.2 злостное, да хоть свою запили

Тогда уж и ядро заодно запилить и готова своя ось.

зато подробнейшая документация и можно всё время делать что-то выходящее за рамки - профит же, или не очень?

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

>это фигня, а не основания

кому как.

и, самое главное, потом не надо говорить что Вам разработчики библиотеки виноваты

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

Любопытно. Линус ещё и подкалывает: «Вы действительно собираетесь выпустить Fedora-14, зная, что не работает Adobe flash?»

я кстати помню историю в рассылке линукс-кернел. завели речь о том что в одной файловой системе теряются данные.

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

и вот тогда Линус Торвальдс устроил всем разнос на тему «раз никто не проверяет код возврата close: де-факто, то и нефиг возвращать ошибку в этом вызове!»

а теперь вон вишь как оно повернулось. наоборот стало быть

rsync ★★
()

> ошибка была закрыта по причине «not a bug»

Правильно, разработчики, использующие memcpy для перекривающихся областей памяти, сами себе злые буратины. Тем более что результат такого использования зависит ТОЛЬКО от реализации этого самого memcpy.

Deleted
()

Это ж надо, так изящно нагнуть флэш.

anonymous
()

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

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

>> раз никто не проверяет код возврата close

а какой смысл его проверять? Разве что ругнуться. Если close обломался можно спокойно делать exit(1)

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

а какой смысл его проверять? Разве что ругнуться. Если close обломался можно спокойно делать exit(1)

можно пользователя известить что запись обломалась по такой-то причине

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

> Ну если тебе бенчмарки Линуса не подошли, то чем мои бенчмарки помогут?

Линукс специально подобрал бенчмарк, чтобы потроллить упертого бюрократа с зашкаливающим ЧСВ, очевидно же. Я бы сделал то же самое - вариаций с кешами / instruction set / недоделками gcc (a glibc, если я правильно понял, теперь использует примитив из gcc для memcpy) достаточно, чтобы получить нужный тебе результат. Тем более, что memcpy очень неинтуитивная функция, любой кто реализовывал на C / асме и бенчмаркил, знает. Я уверен, что сами процессоры оптимизируют под ее разного рода наивные реализации.

Но в Adobe по любому полные идиоты - на любом курсе, где я преподавал C, даже для самых тупых непрофильных студентов, про memcpy первым делом говорилось, что регионы не должны пересекаться.

faustus
()
Ответ на: комментарий от fractaler

> Вот и тут затроллил разрабов glibc, причем предложил вполне рабочий способ сделать из _правильно_ работающей функции, неправильно работающую, но зато так, как он привык.

Каким именно образом его функция неправильно работает? С цитатой из одного из стандартов, пожалуйста.

Вообще, ITT большинство так называемых программистов (про всяких админов я даже и не говорю), не понимают сути аргументации Линуса. Он не говорит, что memcpy должен работать, как memove, в ущерб производительности. Он говорит про то, что memcpy испокон веков реализовывался через копирование адресов слева направо (ну или сверху вниз, олдфаги могут вспомнить эпичное эссе «В какую сторону растутъ адреса» и всплакнуть), и никакого преимущества у реализации memcpy наоборот ни на одном известном человечеству процессоре нет и быть не может (если, конечно, не считать преимуществом показывание Adobe где раки зимуют). В завершение же своей аргументации он троллит нью-др.пеппера самым обычным rep movsb, так как, очевидно, знает, с кем имеет дело.

faustus
()
Ответ на: комментарий от AVL2

Ничто ведь не мешало добавить в эту версию memcpy проверку аргументов с руганью в логи.

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

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

К сожалению, читать варнинги кретинам тоже не свойственно. Чукча не читатель, знаете ли.

anonymous
()
Ответ на: комментарий от linuxfan

>на новых 64-битных системах можно без проблем запустить старый 32-битный нативный Neverwinter.

Не совсем без проблем. Хаки для мувиков, сохранений в ~/.nwn и перекодировки названий файлов с модулями не очень хорошо работают.

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

> а какой смысл его проверять? Разве что ругнуться. Если close обломался можно спокойно делать exit(1)

чтобы ценный файл не перезаписывать недописанным недофайлом

уж лучше оставить старый файл неизменным, чем перезаписать его файлом нулевой длины

// К.О.

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

Это все конечно правильно.

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

Но при чем тут close() ??? Какие еще можно сделать действия если он обломался?

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

Если не ошибаюсь, в вышеописанном случае речь шла о какой-то хитрой журналируемой файловой системе, которая фейлила на close(), уже после того, как write() типа удался. Поскольку результат close() многие программы не проверяют, то они портили файлы, даже если делали все «атомарно» (write/close/rename). Линус там тоже всех затроллел, только вроде со знаком минус к текущей теме.

Вот, нашел - речь, похоже, о NFS: http://lkml.indiana.edu/hypermail/linux/kernel/0207.2/0516.html

faustus
()
Ответ на: комментарий от Lego_12239

>> Такую «мелочь», как перекрывающиеся области запросто можно и не вспомнить через 5 лет после того, как ты прочёл man, если ты не наступал на такие грабли.

Хера се мелочь. Ну Вы жжоте.

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

В процессе разработки количество вариантов разных аргументов может увеличиться. А про то что там внутри это может привести к перекрытию областей memcpy уже никто и не помнит. Это мелочи реализации.

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

> —Алло?

—Здравствуйте, это такой-то, из отдела совместимости Microsoft Windows. Мы нашли в вашей программе баг, из-за которого она не работала. Мы были вынуждены добавить в Windows 95 код для обхода этого бага, чтобы ваша программа продолжала работать.
—Замечательно, большое вам спасибо! До свидания. (Короткие гудки.)

(Набираем номер снова.)

—Алло?
—Алло, ээ… Вы даже не хотите узнать, какой был баг?
—Какая разница? Вы же всё исправили. Спасибо! Что бы мы без вас делали!
—Но, ээ, код в обход бага будет работать только с текущей версией вашей программы. Когда вы выпустите следующую версию, она не заработает.
—Вот оно как?.. Ну, подождите, я свяжу вас с нашими программистами.

Разработчики совершенно не обращают на вас внимания, пока вы не упомянете, что их программа перестанет работать.

Когда читал обратил внимание, что по разговору это говорит менеджер. А в воследнем предложении внизу назван разработчик. Думаю здесь надо жестко детализировать. Обычно как раз разработчикам не пофиг. Пофиг менеджерам.

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

> Но при чем тут close() ??? Какие еще можно сделать действия если он обломался?

в гуевом приложении, например, сказать юзеру, что записать че-то не удалось, пусть расчистит место на диске или проверит возможность туда писать (если через сеть), и затем повторить всю попытку записи файла от самого начала

// К.О.

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

> более того, он использует adobe flash ! ) местные Ъ не переживут.

И гуглхром! О_о

anonymous
()
Ответ на: комментарий от AptGet

> Похоже, зависит от версии gcc, флагов и фазы луны. Или исходники пропатчили.

gcc заменяет memcpy на встроенную реализацию по -O2 только в случае, если size был константой, и то, зависит от размера константы.

Но это - недокументированная фича, не стоит на нее полагаться.

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

anonymous
()
Ответ на: комментарий от faustus

>Каким именно образом его функция неправильно работает? С цитатой из одного из стандартов, пожалуйста.
См здесь: http://www.cplusplus.com/reference/clibrary/cstring/memcpy/
To avoid overflows, the size of the arrays pointed by both the destination and source parameters, shall be at least num bytes, and should not overlap (for overlapping memory blocks, memmove is a safer approach).
Сойдёт?
С тем, что аргументация Линуса сильна, нельзя не согласится. Однако она однобока и провоцирует костылестроение. В чем мы все, к сожалению, убеждаемся на примере ядра Линукс.

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

>на любом курсе, где я преподавал C, даже для самых тупых непрофильных студентов, про memcpy первым делом говорилось, что регионы не должны пересекаться.
Очевидно, Линус тоже не посещал Ваши курсы, потому что наступил на грабли с пересекающимися регионами.

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

> С тем, что аргументация Линуса сильна, нельзя не согласится. Однако она однобока и провоцирует костылестроение. В чем мы все, к сожалению, убеждаемся на примере ядра Линукс.

Имхо, он просто тонко троллит.

anonymous
()
Ответ на: комментарий от fractaler

>> Очевидно, Линус тоже не посещал Ваши курсы, потому что наступил на грабли с пересекающимися регионами.

Я думаю он просто решил посмотреть флеш-видео на ютубе

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

> Сойдёт?

Нет, не сойдет, так как это значит, что поведение функции для пересекающихся блоков неопределено (undefined). Корректное поведение для всех / части пересекающихся блоков прекрасно согласуется со стандартом POSIX (и всеми остальными, их много).

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

Что ж, допустим. Но ведь и закрытие темы как «не баг», тоже правильно, тем более, что в документации четко написано «should not overlap», так значит нечего memcpy там использовать.

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

> Очевидно, Линус тоже не посещал Ваши курсы, потому что наступил на грабли с пересекающимися регионами.

Линус не наступал ни на какие грабли. Линус написал ядро, Линус затроллел Танненбаума, Линус не поленился и затроллел бюрократа из GNU-проекта. Пример, кстати, очень показательный. Помню, как-то внезапно я заметил, что очередная версия Emacs'а при компиляции файла .el в байткод внезапно сначала трет файл .elc, а потом создает новый, вместо того, чтобы, как все нормальные люди, делать truncate. Соответственно, все существующие атрибуты файла .elc идут лесом. Я заслал куда надо баг, и, о чудо, до ответа снизошел сам дядька RMS, написавший что я ничего не понимаю, все так и должно быть, потому что это весьма удобно разработчикам emacs'а, которые делают hard-link'и из скомпилированных сорсов себе в домашнюю директорию, и тем самым экономят место на диске. А мои интересы, как пользователя, им до одного места. Выступил, так сказать, в роли K.O. от GNU.

faustus
()
Ответ на: комментарий от fractaler

Естественно, правильно. Только на вопрос Линуса, зачем копировать справа налево, если можно продолжать копировать слева направо, не теряя абсолютно ничего, и не ломая кучу известного и тонну неизвестного софта, это самый, как его, др. Швебс, так и не удосужился ответить.

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

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

fractaler ★★★★★
()

дело в том, что память это не совсем ПАМЯТЬ в современных условиях .. правильно, что сделали изменение

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