LINUX.ORG.RU

История изменений

Исправление no-dashi, (текущая версия) :

Но, все же интересен механизм.

Этот «механизм» называется MMAP.

До сих пор я думал, что библиотеки загружаются в память и остаются там неизменными до тех пор, пока их использует хотя бы одно приложение.

Не совсем. Бибилиотеки не «загружаются в память», а MMAP'ятся.

А в этом примере происходит какая-то замена уже загруженной в память либы.

Очень грубо говоря, MMAP фактически это подключение страниц кэша в адресное пространство процесса. Как следствие, эти страницы при необходимости (нехватка памяти, ага) можно сплюнуть и когда потребуются, поднять заново. Когда ты переписываешь файл (не удаляешь, а именно обновляешь содержимое), операция записи зацепляет кэш, вследствие чего данные страниц, отображенных в память уже запущенного процесса, меняются. Вдобавок ко всему, при перезаписи файла через cp файл усекается в момент открытия (man fopen), что приводит к удалению MMAP'нутых страниц (размер файла стал 0, страницы освобождены), после чего попытка работающего процесса что-то там сделать автоматом приводит к segfault.

Если бы ты вместо cp использовал dd conv=notrunc при перезаписи файла библиотеки новой копией, вполне возможно что программа пережила бы это (conv=notrunc не приводит к усечению файла и соответственно к освобождению страниц кэша).

Фактически, в линуксе у тебя два swap-пространства: «канонический» swap, куда при необходимости сносятся страницы с данными, и все библиотеки и бинарники. Главное отличие между ними - это то, что во вторую группу запись не производится, и mmap'ятся страницы кэша в которых лежат библиотеки в режиме read-only.

Исходная версия no-dashi, :

Но, все же интересен механизм.

Этот «механизм» называется MMAP.

До сих пор я думал, что библиотеки загружаются в память и остаются там неизменными до тех пор, пока их использует хотя бы одно приложение.

Не совсем. Бибилиотеки не «загружаются в память», а MMAP'ятся.

А в этом примере происходит какая-то замена уже загруженной в память либы.

Очень грубо говоря, MMAP фактически это подключение страниц кэша в адресное пространство процесса. Как следствие, эти страницы пр инеобходимости можно сплюнуть и когда потребуются, поднять заново. Когда ты переписываешь файл (не удаляешь, а именно обновляешь содержимое), операция записи зацепляет кэш, вследствие чего данные страниц, отображенных в память уже запущенного процесса, меняются. Вдобавок ко всему, при перезаписи файла через cp файл усекается в момент открытия (man fopen), что приводит к удалению MMAP'нутых страниц (размер файла стал 0, страницы освобождены), после чего попытка работающего процесса что-то там сделать автоматом приводит к segfault.

Если бы ты вместо cp использовал dd conv=notrunc при перезаписи файла библиотеки новой копией, вполне возможно что программа пережила бы это (conv=notrunc не приводит к усечению файла и соответственно к освобождению страниц кэша).