通过“LD_PRELOAD”替换“malloc”、“calloc”、“realloc”和“free”时出现分段错误

Amm*_*izi 2 c linux malloc x86-64 ld-preload

背景

我尝试更换malloc(3)/ calloc(3)/ realloc(3)/free(3)通过LD_PRELOAD环境变量。我尝试使用静态链接的自定义函数,它们工作得很好。

但是,当我将它作为共享库附加到 时LD_PRELOAD,它总是会导致段错误。


关于功能的简短技术说明

  • 我使用 Linux x86-64mmap(2)munmap(2)syscall for malloc(3)and free(3)
  • calloc(3)只是对malloc(3)乘法溢出检查的调用。
  • realloc(3)电话malloc(3),然后复制旧的数据到新分配的内存和取消映射旧内存。

问题

  • 我的方法有什么问题,以至于它总是导致段错误?
  • 我该如何调试它(gdb 和 valgrind 也有段错误)?
  • 我在这里错过了什么?

笔记

我完全意识到mmap每次malloc调用时总是使用是一个坏主意,尤其是对于性能而言。我只想知道为什么我的方法不起作用。


输出

ammarfaizi2@integral:~$ gcc -shared mem.c -O3 -o my_mem.so
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so ls
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so cat
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so w
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so gdb ls
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ LD_PRELOAD=$(pwd)/my_mem.so valgrind ls
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ 
Run Code Online (Sandbox Code Playgroud)

glibc 版本

ammarfaizi2@integral:~$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.33-0ubuntu2) release release version 2.33.
Copyright (C) 2021 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.
Compiled by GNU CC version 10.2.1 20210130.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
ammarfaizi2@integral:~$ 
Run Code Online (Sandbox Code Playgroud)

代码mem.c


#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <string.h>


static inline void *my_mmap(void *addr, size_t length, int prot, int flags,
                            int fd, off_t offset)
{
    void *ret;
    register int _flags asm("r10") = flags;
    register int _fd asm("r8") = fd;
    register off_t _offset asm("r9") = offset;

    asm volatile(
        "syscall"
        : "=a"(ret)
        : "a"(9), "D"(addr), "S"(length), "d"(prot),
          "r"(_flags), "r"(_fd), "r"(_offset)
        : "memory", "r11", "rcx"
    );
    return ret;
}


static inline int my_munmap(void *addr, size_t length)
{
    int ret;

    asm volatile(
        "syscall"
        : "=a"(ret)
        : "a"(11), "D"(addr), "S"(length)
        : "memory", "r11", "rcx"
    );
    return ret;
}

#define unlikely(EXPR) __builtin_expect(EXPR, 0)

void * __attribute__((noinline)) malloc(size_t len)
{
    void *start_map;
    uintptr_t user_ptr, cmperr;
    size_t add_req = 0;

    add_req += sizeof(size_t);
    add_req += sizeof(uint8_t);
    add_req += 0x1full;

    start_map = my_mmap(NULL, add_req + len, PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    cmperr = 0xffffffffffffff00ull;
    if (unlikely(((uintptr_t)start_map & cmperr) == cmperr)) {
        errno = ENOMEM;
        return NULL;
    }

    /* Align 32-byte and take space to save the length and diff */
    user_ptr = ((uintptr_t)start_map + add_req) & ~0x1full;
    *(size_t  *)(user_ptr - 8) = len;
    *(uint8_t *)(user_ptr - 9) = (uint8_t)(user_ptr - (uintptr_t)start_map);

    return (void *)user_ptr;
}


void free(void *__user_ptr)
{
    size_t len;
    uint8_t diff;
    uintptr_t user_ptr = (uintptr_t)__user_ptr;

    len  = *(size_t  *)(user_ptr - 8);
    diff = *(uint8_t *)(user_ptr - 9);
    my_munmap((void *)(user_ptr - diff), len);
}


void *realloc(void *__user_ptr, size_t new_len)
{
    void *new_mem;
    size_t len;
    uint8_t diff;
    uintptr_t user_ptr = (uintptr_t)__user_ptr;

    len  = *(size_t  *)(user_ptr - 8);
    diff = *(uint8_t *)(user_ptr - 9);

    new_mem = malloc(new_len);
    if (unlikely(new_mem == NULL))
        return NULL;

    memcpy(new_mem, __user_ptr, (new_len < len) ? new_len : len);
    my_munmap((void *)(user_ptr - diff), len);
    return new_mem;
}


void *calloc(size_t nmemb, size_t len)
{
    size_t x = nmemb * len;
    if (unlikely(nmemb != 0 && x / nmemb != len)) {
        errno = EOVERFLOW;
        return NULL;
    }
    return malloc(x);
}

// #include <stdio.h>
// int main(void)
// {
//  char *test = malloc(1);

//  for (size_t i = 2; i <= (1024 * 1024); i++) {
//      test = realloc(test, i);
//      memset(test, 'q', i);
//  }

//  free(test);
// }

Run Code Online (Sandbox Code Playgroud)

重新编译-Wall -Wextra -ggdb3strace输出

ammarfaizi2@integral:~$ 
ammarfaizi2@integral:~$ gcc -Wall -Wextra -ggdb3 -shared mem.c -O3 -o my_mem.so
ammarfaizi2@integral:~$ strace -tf /usr/bin/env LD_PRELOAD=$(pwd)/my_mem.so ls
12:59:15 execve("/usr/bin/env", ["/usr/bin/env", "LD_PRELOAD=/home/ammarfaizi2/my_"..., "ls"], 0x7ffd2d6ee188 /* 34 vars */) = 0
12:59:15 brk(NULL)                      = 0x565552193000
12:59:15 arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd13017120) = -1 EINVAL (Invalid argument)
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=74118, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 74118, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7facba2ba000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\206\2\0\0\0\0\0"..., 832) = 832
12:59:15 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
12:59:15 pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
12:59:15 pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\30\355\366\266\203\242\371v\214\300\356\234\306J\346\373"..., 68, 896) = 68
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1983576, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7facba2b8000
12:59:15 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
12:59:15 mmap(NULL, 2012056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7facba0cc000
12:59:15 mmap(0x7facba0f2000, 1486848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7facba0f2000
12:59:15 mmap(0x7facba25d000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x191000) = 0x7facba25d000
12:59:15 mmap(0x7facba2a9000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1dc000) = 0x7facba2a9000
12:59:15 mmap(0x7facba2af000, 33688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7facba2af000
12:59:15 close(3)                       = 0
12:59:15 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7facba0ca000
12:59:15 arch_prctl(ARCH_SET_FS, 0x7facba2b95c0) = 0
12:59:15 mprotect(0x7facba2a9000, 12288, PROT_READ) = 0
12:59:15 mprotect(0x565550cb5000, 4096, PROT_READ) = 0
12:59:15 mprotect(0x7facba2ff000, 8192, PROT_READ) = 0
12:59:15 munmap(0x7facba2ba000, 74118)  = 0
12:59:15 brk(NULL)                      = 0x565552193000
12:59:15 brk(0x5655521b4000)            = 0x5655521b4000
12:59:15 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=3041456, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 3041456, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7facb9de3000
12:59:15 close(3)                       = 0
12:59:15 execve("/home/ammarfaizi2/.local/bin/ls", ["ls"], 0x565552194550 /* 35 vars */) = -1 ENOENT (No such file or directory)
12:59:15 execve("/usr/local/sbin/ls", ["ls"], 0x565552194550 /* 35 vars */) = -1 ENOENT (No such file or directory)
12:59:15 execve("/usr/local/bin/ls", ["ls"], 0x565552194550 /* 35 vars */) = -1 ENOENT (No such file or directory)
12:59:15 execve("/usr/sbin/ls", ["ls"], 0x565552194550 /* 35 vars */) = -1 ENOENT (No such file or directory)
12:59:15 execve("/usr/bin/ls", ["ls"], 0x565552194550 /* 35 vars */) = 0
12:59:15 brk(NULL)                      = 0x557f8624b000
12:59:15 arch_prctl(0x3001 /* ARCH_??? */, 0x7fff39dc1a30) = -1 EINVAL (Invalid argument)
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/home/ammarfaizi2/my_mem.so", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\20\0\0\0\0\0\0"..., 832) = 832
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0700, st_size=58768, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7daa68000
12:59:15 mmap(NULL, 16448, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7daa63000
12:59:15 mmap(0x7fa7daa64000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7fa7daa64000
12:59:15 mmap(0x7fa7daa65000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fa7daa65000
12:59:15 mmap(0x7fa7daa66000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fa7daa66000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=74118, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 74118, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa7daa50000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 p\0\0\0\0\0\0"..., 832) = 832
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=167352, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 178664, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7daa24000
12:59:15 mmap(0x7fa7daa2a000, 106496, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7fa7daa2a000
12:59:15 mmap(0x7fa7daa44000, 32768, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x20000) = 0x7fa7daa44000
12:59:15 mmap(0x7fa7daa4c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x27000) = 0x7fa7daa4c000
12:59:15 mmap(0x7fa7daa4e000, 6632, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa7daa4e000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\206\2\0\0\0\0\0"..., 832) = 832
12:59:15 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
12:59:15 pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
12:59:15 pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\30\355\366\266\203\242\371v\214\300\356\234\306J\346\373"..., 68, 896) = 68
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=1983576, ...}, AT_EMPTY_PATH) = 0
12:59:15 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
12:59:15 mmap(NULL, 2012056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7da838000
12:59:15 mmap(0x7fa7da85e000, 1486848, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7fa7da85e000
12:59:15 mmap(0x7fa7da9c9000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x191000) = 0x7fa7da9c9000
12:59:15 mmap(0x7fa7daa15000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1dc000) = 0x7fa7daa15000
12:59:15 mmap(0x7fa7daa1b000, 33688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa7daa1b000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\"\0\0\0\0\0\0"..., 832) = 832
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=617160, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 619304, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7da7a0000
12:59:15 mmap(0x7fa7da7a2000, 438272, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fa7da7a2000
12:59:15 mmap(0x7fa7da80d000, 167936, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6d000) = 0x7fa7da80d000
12:59:15 mmap(0x7fa7da836000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x95000) = 0x7fa7da836000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \"\0\0\0\0\0\0"..., 832) = 832
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=22912, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 24848, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7da799000
12:59:15 mmap(0x7fa7da79b000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fa7da79b000
12:59:15 mmap(0x7fa7da79d000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4000) = 0x7fa7da79d000
12:59:15 mmap(0x7fa7da79e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4000) = 0x7fa7da79e000
12:59:15 close(3)                       = 0
12:59:15 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
12:59:15 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
12:59:15 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\200\0\0\0\0\0\0"..., 832) = 832
12:59:15 pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 792) = 48
12:59:15 pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0a7\363\352;k|\2228\244\6\253\346\2569\312"..., 68, 840) = 68
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=150456, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 136208, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa7da777000
12:59:15 mmap(0x7fa7da77e000, 65536, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7fa7da77e000
12:59:15 mmap(0x7fa7da78e000, 20480, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17000) = 0x7fa7da78e000
12:59:15 mmap(0x7fa7da793000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b000) = 0x7fa7da793000
12:59:15 mmap(0x7fa7da795000, 13328, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa7da795000
12:59:15 close(3)                       = 0
12:59:15 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7da775000
12:59:15 mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7da772000
12:59:15 arch_prctl(ARCH_SET_FS, 0x7fa7da772800) = 0
12:59:15 mprotect(0x7fa7daa15000, 12288, PROT_READ) = 0
12:59:15 mprotect(0x7fa7da793000, 4096, PROT_READ) = 0
12:59:15 mprotect(0x7fa7da79e000, 4096, PROT_READ) = 0
12:59:15 mprotect(0x7fa7da836000, 4096, PROT_READ) = 0
12:59:15 mprotect(0x7fa7daa4c000, 4096, PROT_READ) = 0
12:59:15 mprotect(0x7fa7daa66000, 4096, PROT_READ) = 0
12:59:15 mprotect(0x557f842f9000, 8192, PROT_READ) = 0
12:59:15 mprotect(0x7fa7daa9c000, 8192, PROT_READ) = 0
12:59:15 munmap(0x7fa7daa50000, 74118)  = 0
12:59:15 set_tid_address(0x7fa7da772ad0) = 1639769
12:59:15 set_robust_list(0x7fa7da772ae0, 24) = 0
12:59:15 rt_sigaction(SIGRTMIN, {sa_handler=0x7fa7da77eb70, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7fa7da78b160}, NULL, 8) = 0
12:59:15 rt_sigaction(SIGRT_1, {sa_handler=0x7fa7da77ec10, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7fa7da78b160}, NULL, 8) = 0
12:59:15 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
12:59:15 prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
12:59:15 statfs("/sys/fs/selinux", 0x7fff39dc1a00) = -1 ENOENT (No such file or directory)
12:59:15 statfs("/selinux", 0x7fff39dc1a00) = -1 ENOENT (No such file or directory)
12:59:15 mmap(NULL, 512, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7daa9b000
12:59:15 openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
12:59:15 mmap(NULL, 160, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7daa62000
12:59:15 newfstatat(3, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
12:59:15 mmap(NULL, 1064, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7daa61000
12:59:15 read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 410
12:59:15 read(3, "", 1024)              = 0
12:59:15 munmap(0x7fa7daa62000, 120)    = 0
12:59:15 close(3)                       = 0
12:59:15 munmap(0x7fa7daa61000, 1024)   = 0
12:59:15 munmap(0x7fa7daa9b000, 472)    = 0
12:59:15 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xfffffffffffffff7} ---
12:59:16 +++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ 
Run Code Online (Sandbox Code Playgroud)

使用 /usr/bin/env 后的 Valgrind 输出

ammarfaizi2@integral:~$ valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all /usr/bin/env LD_PRELOAD=$(pwd)/my_mem.so ls
==1640100== Memcheck, a memory error detector
==1640100== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1640100== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==1640100== Command: /usr/bin/env LD_PRELOAD=/home/ammarfaizi2/my_mem.so ls
==1640100== 
Segmentation fault (core dumped)
ammarfaizi2@integral:~$ 
Run Code Online (Sandbox Code Playgroud)

pre*_*uin 6

I have debugged the core file and fixed the crash, for the free function, you need to check if the argument is nullptr, for the realloc we need to hander __user_ptr is nullptr too.

void free(void *__user_ptr) {
  if (!__user_ptr) return;
  // ...
}

void *realloc(void *__user_ptr, size_t new_len) {
  void *new_mem;
  size_t len;
  uint8_t diff;
  uintptr_t user_ptr = (uintptr_t)__user_ptr;

  new_mem = malloc(new_len);
  if (!__user_ptr) return new_mem;
  // ....
}
Run Code Online (Sandbox Code Playgroud)

I have some experience in writing memory allocator libraries. During debugging, I find that some old c program uses realloc as malloc with a nullptr arguments, it's weird but is totally valid, please reference the man page

The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is larger than the old size, the added memory will not be initialized. If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.

By the way, I see that you try to wrap the syscall for mmap and munmap, I suggest that we replace them with https://github.com/linux-on-ibm-z/linux-syscall-support , which is a production-level wrapper library and widely used. I think we should write as little code as possible to reduce potential errors.

  • OP 的 mmap 包装器*更高效*,因此他们通过编写自己的包装器获得了一些效率(至少更小的代码大小)。链接库似乎对 x86-64 中的最后 3 个参数(在 R10、R8、R9 中)使用“movq %5,%%r10;”之类的内容,而不是使用 GNU C `register ... asm (“r10”)`变量。它还强制将所有参数进行零或符号扩展为 64 位,即使它们只是“int”,尽管在这种情况下代码正在传递常量,因此编译器可以免费执行此操作。 (2认同)
  • 与通常的系统调用包装库一样,它们在每个系统调用上使用“内存”破坏器。对于 mmap,我认为您不能安全地省略“内存”破坏器来让编译器避免无关对象的溢出/重新加载,但是对于像“write”(仅读取内存)这样的系统调用,您可以通过告诉编译器只针对该缓冲区了解这一事实([如何指示可以使用内联 ASM 参数指向的内存?](/sf/ask/3950258161/))。 (2认同)
  • 也许对于 munmap,您可以告诉编译器指向的内存是 asm 语句的输入,因此所有对其的存储都必须在 asm 语句之前完成,而不是延迟到之后(当它们出现故障时)。或者告诉编译器它是一个“+m”读/写操作数,以确保它不会尝试延迟加载,直到它被取消映射。不管怎样,我想这确实是一个改进头文件库的论据,而不是让每个人都推出自己的头文件库。对包装器的这些优化并非特定于该用例。 (2认同)