5

每个人!

我有这样的程序(usemalloc)的图像:

#include <stdio.h>
#include <stdlib.h>

#define USER_BYTES_SIZE 100

int main(void){
    char* userbytes = (char*)malloc(USER_BYTES_SIZE*sizeof(char));
    if(!userbytes)
        return 1;

    for(int i = 0; i <= USER_BYTES_SIZE; i++){ // "i <= USER_BYTES_SIZE" leads to an off-by-one memory overrun.
        userbytes[i] = 0;
    }
    return 0;
}

如您所见,存在一个导致内存溢出的错误。我想在运行时检测此类错误。LD_PRELOADed 库适合我的工作。我制作了一个名为 libhijack.so 的库来劫持对真正 malloc 的调用,并将其替换为对我自己的自定义 malloc 的调用,该调用调用真正的 malloc 并在由真正的 malloc 分配的内存条的末端添加红色区域。libhijack.so 的代码如下:

void* (*real_malloc) (size_t size);
void* malloc(size_t size){
    real_malloc = ((void*)(*)(size_t))dlsym(RTLD_NEXT, "malloc");
    void* allocbytes = (void*)real_malloc(size + 4); //put 2 bytes at each end, call them red zones
    return (allocbytes + 2);
}

我使用以下命令运行带有库的主程序:

LD_PRELOAD=./libhijack.so ./usemalloc

然后如果有红色区域的内存访问,我会检测它们并将它们视为内存溢出错误。

当主进程包含对 malloc 的调用时,此 LD_PRELOAD 解决方案运行良好,但在分叉子进程执行此操作时失败。

例如,我们将“usemalloc”改成如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // +

#define USER_BYTES_SIZE 100

int main(void){
    pid_t child = fork();
    if(child < 0)
        exit(1);

    if(child == 0){ //child process
        char* userbytes = (char*)malloc(USER_BYTES_SIZE*sizeof(char));
        if(!userbytes)
            return 1;

        for(int i = 0; i <= USER_BYTES_SIZE; i++){ // "i <= USER_BYTES_SIZE" leads to an off-by-one memory overrun.
            userbytes[i] = 0;
        }
    }
    else { //the current process
        wait(NULL);
    }
    return 0;
}

LD_PRELOADed 库不会检测到子进程中发生的溢出错误。

所以我的问题是:如何使用 LD_PRELOADed 库检测子进程中的溢出错误?那(使用 LD_PRELOADed 库)可能吗?如果没有,还有其他选择吗?任何建议表示赞赏!

4

3 回答 3

0

使用 valgrind 检测内存泄漏和其他内存问题。它工作得很好,你不必实现任何东西。

于 2013-01-02T09:56:02.437 回答
0

我希望通过指出 libhijack 代码实际上并没有分配任何内存,我不会挑剔?pthread_mutex_lock 需要一个 pthread_mutex_t * 参数,并返回一个整数,表示互斥锁是否成功?

此外,您正在 fork() 一个子进程,这与创建线程有点不同,因此 pthread 函数可能不是您真正想要的......?

另一个技巧是,虽然已经演示了导致问题的代码,但您如何检查“红色区域”?也许检测怪癖在于检测代码?

于 2013-01-01T14:44:09.623 回答
0

我认为您的问题与fork()vs.没有任何关系LD_PRELOAD。我认为这可能是您代码中其他地方的错误。我尝试使用以下测试用例重现您的问题:

// preloadlib.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <unistd.h>
void* malloc(size_t size)
{
        write(1, "malloc\n", 7);
        void *(*real_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
        return real_malloc(size);
}

.

// example.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
        if (fork()) {
                write(1, "A\n", 2);
                malloc(1337);
                write(1, "B\n", 2);
        } else {
                write(1, "C\n", 2);
                malloc(1337);
                write(1, "D\n", 2);
        }
        return 0;
}

.

# run.sh
gcc -Wall -Wextra -o example example.c
gcc -Wall -Wextra -fPIC -o preloadlib.so -shared preloadlib.c -ldl
LD_PRELOAD=$PWD/preloadlib.so ./example

这是我得到的输出:

$ bash run.sh 
A
malloc
C
B
malloc
D

这是在 64 位 Kubuntu 12.04(libc 版本 2.15-0ubuntu10.4)上。

于 2013-05-30T22:14:48.363 回答