لماذا يتسبب MAP_GROWSDOWN في أخطاء SIGBUS بعد الترقية إلى CentOS 5.5؟

StackOverflow https://stackoverflow.com/questions/4055669

سؤال

كنت أقوم بترقية نظام التشغيل على أحد بناءنا من Centos 5.3 32bit إلى Centos 5.5 32bit. بعد إجراء تحديث الحزمة ، قمت بإعادة التشغيل ، وفحصت نسخة نظيفة من المصدر ، وبناء وتشغيل اختبارات الوحدة. بدأت جميع اختبارات الوحدة التي تعتمد على فئة قاعدة MEMMAP الخاصة بنا في الفشل.

يحدث الحادث عندما نحاول ضبط قيمة صفحة الحراسة بعد مرور الفترة على الفور بعد تعيين الذاكرة. بعد أن أتجول حولها ، تمكنت من عزل المشكلة لاستخدامنا لعلم MAP_GROWSDOWN ، فإن الاختبارات تعمل بشكل جيد بدونها ولكن يتم تعيين العلم. نجحت هذه الاختبارات بشكل جيد عندما كان نظام البناء يعمل 5.3 ، لكنه بدأ على الفور في الانهيار عندما قمنا بالترقية إلى 5.5. كما أنها تعمل بشكل جيد على آلة التطوير الخاصة بي التي تعمل أيضًا 5.5 ولكنها أجهزة حقيقية ؛ نظام البناء هو Xen VM. هذا جزء مستقر من التعليمات البرمجية التي لم يتم تعديلها في العديد من الإصدارات ولديها تغطية اختبار الوحدة شمال 80 ٪.

لذلك أعتقد أن سؤالي هو لماذا يحدث هذا؟

int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_GROWSDOWN;
int prot = PROT_EXEC|PROT_READ|PROT_WRITE;
size_t length = 524288;

long rv = ::sysconf(_SC_PAGESIZE);
if (rv < 0)
    throw SystemException(errno);
size_t pagelength = size_t(rv);

//  Adjust length for guard page
length = pagelength * (((length + pagelength - 1) / pagelength) + 1);

m_addr = ::mmap(NULL, length, prot, flags, -1, 0);
if (m_addr == MAP_FAILED)
    throw SystemException(errno);

m_stackaddr = static_cast<void *>(static_cast<char *>(m_addr) + pagelength);
m_length = length - pagelength;

// Fill the guard page with an interesting pattern
unsigned int *g = static_cast<unsigned int *>(m_addr);
for (size_t i=0; i < pagelength; i += sizeof(unsigned int))
    *g++ = 0xBADC0FFEU;  <-- SIGBUS HAPPENS HERE ON FIRST ITERATION
هل كانت مفيدة؟

المحلول

يبدو أن map_growsdown قد تمت إزالة من glibc http://bugs.centos.org/view.php؟id=4767 ولا ينبغي استخدامه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top