mprotect не всегда сворачивает соседние строки в /proc/pid/maps
У меня есть процесс, когда через некоторое время mprotect()
не удается с ENOMEM
, Ошибка вызвана тем, что "внутренние структуры ядра не могут быть размещены": в этот момент файл /proc/<pid>/maps
содержит 65531 строк, что, конечно, подозрительно близко к 2^16.
Процесс начинается с получения фрагмента памяти с помощью mmap (1280 МБ, MAP_PRIVATE | MAP_ANONYMOUS) и вызова mprotect()
на отдельных страницах (или небольшом количестве страниц) для включения и отключения доступа к ним, для отладки. Первоначально отображаемая область размером 1280 МБ отображается в виде одной строки в /proc/<pid>/maps
, но каждый звонок mprotect()
потенциально может "разделить" эту область на три части: память до, измененная страница и память после. После нескольких изменений, когда две смежные (но независимо измененные) области памяти заканчиваются одинаковыми флагами доступа, они обычно снова объединяются, поэтому общее количество строк остается разумным.
Но только "обычно". В случае неудачи /proc/<pid>/maps
заканчивается большим количеством смежных областей памяти с одинаковой защитой, и я не понимаю, почему они не объединены. В одностраничных примерах они объединены правильно. Когда это работает по-другому и почему?
Для справки, сбойная программа является многопоточной, хотя это не должно иметь эффекта (для каждого потока /proc/<tid>/maps
файл идентичен). Видно в ядрах Linux "2.6.35-30-generiC#56-Ubuntu SMP" и "3.2.0-37-generiC#58-Ubuntu SMP".
РЕДАКТИРОВАТЬ: как воспроизвести:
hg clone https://bitbucket.org/pypy/stmgc
cd stmgc/c4
hg up d4e3aac8c458 # branch copy-over-original2
make debug-demo2
gdb ./debug-demo2 # lots and lots of colored output
Это должно потерпеть неудачу в err = mprotect(..); assert(err == 0);