为什么升级到 Centos 5.5 后 MAP_GROWSDOWN 会导致 SIGBUS 错误?
我正在将我们的其中一个版本的操作系统从 Centos 5.3 32 位升级到 Centos 5.5 32 位。完成软件包更新后,我重新启动,检查了源代码的干净副本,构建并运行了单元测试。所有依赖 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
I was upgrading the OS on one of our build from Centos 5.3 32bit to Centos 5.5 32bit. After doing the package update I rebooted, checked out a clean copy of the source, built and ran the unit tests. All unit tests which rely on our MemMap base class began to fail.
The crash occurs when we attempt to set the value of the guard page after immediatly after mapping the memory. After poking around I was able to isolate the problem to our use of the MAP_GROWSDOWN flag, the tests run fine without it but crash when the flag is set. These tests worked fine when the build system was running 5.3, but immediatly started crashing when we upgraded to 5.5. They also work fine on my development machine which is also running 5.5 but is real hardware; the build system is a XEN VM. This is a stable bit of code which hasn't been modified in several releases and has unit test coverage north of 80%.
So I guess my question is why is this happening?
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看起来 MAP_GROWSDOWN 已从 glibc http://bugs.centos.org/view 中删除。 php?id=4767 并且不应使用。
It looks like MAP_GROWSDOWN has been removed from glibc http://bugs.centos.org/view.php?id=4767 and shouldn't be used.