简体   繁体   English

Musl mmap ENOMEM

[英]Musl mmap ENOMEM

I compiled some cross compilers against musl(x86_64, i686, arm).我针对 musl(x86_64、i686、arm)编译了一些交叉编译器。 I need to compile code, that allocate like 2048 Mb +- 200Mb.我需要编译代码,分配大约 2048 Mb +- 200Mb。 However I noticed some errors with i686 musl compiler:但是我注意到 i686 musl 编译器有一些错误:

#include <stdio.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <errno.h>
int main(){
  void*ptr = mmap(0, 2147483647,PROT_READ|PROT_WRITE, 
            MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);       // malloc(2147483647)
  if(ptr == MAP_FAILED){
    printf("ERROR MMAP - "); 
    if(errno == ENOMEM){
      struct rlimit ra, rd; 
      if( getrlimit(RLIMIT_AS, &ra) < 0)
        printf("RLIMIT AS ERR\n");  
      if( getrlimit(RLIMIT_DATA, &rd) < 0)
        printf("RLIMIT AS ERR\n");   
      printf("ENOMEM, RLIMIT_AS: (%lu:%lu); RLIMIT_DATA: (%lu:%lu)\n", ra.rlim_cur, ra.rlim_max, rd.rlim_cur, rd.rlim_max); 
    }
  }
  else 
    printf("SUCCESS\n"); 
}

I know that there is no mistake with building i686-linux-musl.我知道构建 i686-linux-musl 没有错误。 To prove it I, for example, downloaded i686-linux-musl from https://musl.cc/例如,为了证明这一点,我从https://musl.cc/下载了 i686-linux-musl 在此处输入图像描述

I dont know why ldd tell me, that c is static, but file tell me it's dynamically linked.我不知道为什么 ldd 告诉我,c 是 static,但文件告诉我它是动态链接的。

However if I compile it with i686-linux-gnu (i586)但是,如果我用 i686-linux-gnu (i586) 编译它在此处输入图像描述

What's the problem with musl? musl有什么问题? EDITED.编辑。 I used strace and got.我用strace得到了。 i686-linux-musl: i686-linux-musl:

execve("./c", ["./c"], 0x7ffe6a24f548 /* 61 vars */) = 0
strace: [ Process PID=1723318 runs in 32 bit mode. ]
set_thread_area({entry_number=-1, base_addr=0xf7ff75ac, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
set_tid_address(0xf7ff7654)             = 1723318
prlimit64(0, RLIMIT_AS, NULL, {rlim_cur=RLIM64_INFINITY, rlim_max=RLIM64_INFINITY}) = 0
prlimit64(0, RLIMIT_DATA, NULL, {rlim_cur=RLIM64_INFINITY, rlim_max=RLIM64_INFINITY}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=40, ws_col=235, ws_xpixel=0, ws_ypixel=0}) = 0
writev(1, [{iov_base="ERROR MMAP - ENOMEM, RLIMIT_AS: "..., iov_len=92}, {iov_base=")\n", iov_len=2}], 2ERROR MMAP - ENOMEM, RLIMIT_AS: (4294967295:4294967295); RLIMIT_DATA: (4294967295:4294967295)
) = 94
exit_group(0)

Whereis mmap?? mmap在哪里?? And with i586-linux-gnu:以及 i586-linux-gnu:

execve("./c2", ["./c2"], 0x7fff3e161878 /* 61 vars */) = 0
strace: [ Process PID=1723806 runs in 32 bit mode. ]
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
mmap(NULL, 2147483647, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77f34000
write(1, "SUCCESS\n", 8SUCCESS
)                = 8
exit(8)                                 = ?
+++ exited with 8 +++

By looking at the source code of musl's mmap we see that it forces the size to be less than PTRDIFF_MAX , which is probably 2147483647, and returns the ENOMEM error if it's not.通过查看musl 的mmap的源代码,我们看到它强制大小小于PTRDIFF_MAX ,这可能是 2147483647,如果不是,则返回ENOMEM错误。

Ask for 1 byte less, and it will actually try to mmap.要求少 1 个字节,它实际上会尝试 mmap。

However, the memory fragmentation concern still applies.但是,memory 碎片问题仍然存在。 On a 32-bit architecture, allocating 2GB of memory may succeed, but it won't always succeed and you have to be prepared for the possibility that it may not.在 32 位架构上,分配 2GB 的 memory可能会成功,但它不会总是成功,您必须为它可能不会成功的可能性做好准备。 Many 32-bit operating systems limit you to a maximum of 2GB of address space - not 4GB - including the memory you allocate and your program itself.许多 32 位操作系统将您的地址空间限制为最多 2GB - 而不是 4GB - 包括您分配的 memory 和您的程序本身。 On those operating systems, you won't ever be able to allocate 2GB.在这些操作系统上,您将永远无法分配 2GB。 I think 32-bit Windows and 32-bit Linux work this way.我认为 32 位 Windows 和 32 位 Linux 是这样工作的。

What's happening there is that the address space is fragmented.那里发生的事情是地址空间是碎片化的。 While you may still have enough free memory and enough free address space for the process, there is simply not a 2GB long contiguous range of unused addresses.虽然您可能仍然有足够的空闲 memory 和足够的进程可用地址空间,但根本没有 2GB 长的连续未使用地址范围。 Therefore, the mmap call fails, as it should.因此,mmap 调用失败,这是应该的。 The different libraries of course have different allocation patterns and will get loaded at different addresses (or even random addresses with ASLR), so the size of the largest free block of address space will vary (it can even be random on purpose with ASLR).不同的库当然有不同的分配模式,并且会加载到不同的地址(或者甚至是 ASLR 的随机地址),因此地址空间的最大空闲块的大小会有所不同(它甚至可以是故意随机的 ASLR)。

You have to allocate the memory in smaller non-contiguous chunks, whether you like it or not.您必须将 memory 分配为较小的非连续块,无论您是否喜欢。 Alternatively, if you compile for 64 bit, you get a much larger address space where it's no problem at all to fit in a 2GB allocation.或者,如果您针对 64 位进行编译,您将获得更大的地址空间,完全可以容纳 2GB 的分配空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM