【发布时间】:2015-12-08 20:21:37
【问题描述】:
考虑以下程序:
#include <sys/mman.h>
#include <stdlib.h>
#include <errno.h>
int
main()
{
errno = 0;
mlockall(MCL_FUTURE);
char *a = malloc(1);
if (!a)
exit(errno);
munlockall();
exit(0);
}
当以普通用户身份运行时,我得到:
~ ./a.out
~ echo $?
11
来自/usr/include/asm-generic/errno-base.h:
#define EAGAIN 11 /* Try again */
以 root 身份运行或传递 MCL_FUTURE | MCL_CURRENT 时,它会成功运行。我假设权限不足或标志错误,但 EPERM 和 EINVAL 均未返回。
该错误未在函数的手册页中指定,在 mlockall 的 POSIX 规范中也未指定。在 mlockall 之后放置一个 printf 表明是 malloc 正在设置 errno。
更奇怪的是,malloc 似乎没有设置 EAGAIN(或者我找错地方了):
/usr/src/glibc/glibc-2.19/malloc grep -r . -e EAGAIN
那么交易是什么?
~ uname -r 18:15:04
3.16-2-486
~ gcc --version 18:15:05
gcc (Debian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
~ ldd --version 18:15:11
ldd (Debian GLIBC 2.19-18+deb8u1) 2.19
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
~ 18:15:15
【问题讨论】:
-
您将
errno设置为0,调用两个 函数,然后检查errno的值。您无法判断它是由mlockall还是由malloc设置的。您提到添加printf调用,但它不在您发布的代码中。您应该在每次调用前将errno设置为0,并在每次调用后立即检查。 -
来自手册页 如果指定了 MCL_FUTURE,那么以后的系统调用(例如 mmap(2)、sbrk(2)、malloc(3))可能会失败,如果它会导致锁定字节数超过允许的最大值(见下文)。在同样的情况下,堆栈增长同样可能失败:内核将拒绝堆栈扩展并向进程传递 SIGSEGV 信号。
-
malloc() 通常不是系统调用。它只是调用 C 运行时子分配器。
-
@AndrewHenle:我很抱歉说得不准确。我现在写了一个答案,更详细地解释了这种情况。
-
@AndrewHenle:关于 POSIX,我看到
ENOMEM是malloc(3)的 POSIX 描述中列出的唯一errno值。但是here 我们看到“实现......可能会产生额外的错误,除非明确禁止特定功能。”所以我不认为这是违反 POSIX 的。