Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
失败malloc()的单元测试_C_Unit Testing_Memory Management_Libc - Fatal编程技术网

失败malloc()的单元测试

失败malloc()的单元测试,c,unit-testing,memory-management,libc,C,Unit Testing,Memory Management,Libc,对涉及失败的malloc()的代码路径进行单元测试的最佳方法是什么?在大多数情况下,这可能并不重要,因为你正在做类似的事情 thingy *my_thingy = malloc(sizeof(thingy)); if (my_thingy == NULL) { fprintf(stderr, "We're so screwed!\n"); exit(EXIT_FAILURE); } 但在某些情况下,除了死亡,你还有其他选择,因为你已经分配了一些额外的东西用于缓存或其他什么,你可以回收

对涉及失败的
malloc()
的代码路径进行单元测试的最佳方法是什么?在大多数情况下,这可能并不重要,因为你正在做类似的事情

thingy *my_thingy = malloc(sizeof(thingy));
if (my_thingy == NULL) {
  fprintf(stderr, "We're so screwed!\n");
  exit(EXIT_FAILURE);
} 
但在某些情况下,除了死亡,你还有其他选择,因为你已经分配了一些额外的东西用于缓存或其他什么,你可以回收这些内存


然而,在那些您可以尝试从失败的
malloc()
中恢复的实例中,您在一个非常不寻常的代码路径中执行一些棘手且容易出错的操作,这使得测试特别重要。你到底是怎么做的

在FreeBSD中,我曾经简单地重载了C库malloc.o模块(符号很弱),并用一个具有控制失败概率的实现替换了malloc()实现。 所以我静态链接并开始执行测试。srandom()使用受控伪随机序列完成图片


另外,根据我的意见,还需要一套好的工具。至少它们会重载malloc()/free()来跟踪泄漏,因此它似乎是添加任何您想要的内容的可用点。

这有点恶心,但如果您确实想要单元测试,您可以使用#ifdef:

不幸的是,您必须使用此解决方案重新编译很多内容


如果你使用Linux,你也可以考虑通过使用内存压力来运行代码,但是要小心。

< P>我看到了S. Paavolainen提出的这个问题的一个很酷的解决方案。其思想是通过一个定制的分配器覆盖标准的
malloc()
,您只需在链接器中就可以做到这一点

  • 读取调用malloc()的线程的当前执行堆栈
  • 检查存储在硬盘上的数据库中是否存在堆栈
  • 如果堆栈不存在,则将堆栈添加到数据库并返回
    NULL
  • 如果堆栈已经存在,则正常分配内存并返回

  • 然后您只需多次运行单元测试:此系统通过不同的控制路径自动枚举到
    malloc()
    失败,并且比随机测试更有效、更可靠。

    我建议为您的特殊malloc代码创建一个特定的函数,您希望它可能会失败,并且您可以优雅地处理它。例如:

    void* special_malloc(size_t bytes) {
      void* ptr = malloc(bytes);
      if(ptr == NULL) {
        /* Do something crafty */
      } else {
        return ptr;
      }
    }
    

    然后,您可以在这里通过为字节传递一些坏值来单元测试这个狡猾的业务。您可以将其放在一个单独的库中,并创建一个模拟库,该模拟库的行为对于您测试调用此函数的函数来说非常特殊。

    编写您自己的库,通过随机失败或调用真正的malloc(静态链接或显式dlopened)来实现malloc


    然后LD_预加载它

    您可以通过使用一些定义和全局参数来控制它来劫持malloc。。。这有点老套,但似乎管用

    #include <stdio.h>
    #include <stdlib.h>
    
    #define malloc(x) fake_malloc(x)
    
    struct {
      size_t last_request;
      int should_fail;
      void *(*real_malloc)(size_t);
    } fake_malloc_params;
    
    void *fake_malloc(size_t size) {
      fake_malloc_params.last_request = size;
      if (fake_malloc_params.should_fail) {
        return NULL;
      }
      return (fake_malloc_params.real_malloc)(size);;
    }
    
    int main(void) {
      fake_malloc_params.real_malloc = malloc;
      void *ptr = NULL;
      ptr = malloc(1);
      printf("last: %d\n", (int) fake_malloc_params.last_request);
      printf("ptr: 0x%p\n", ptr);
      return 0;
    }
    
    #包括
    #包括
    #定义malloc(x)fake_malloc(x)
    结构{
    上次请求的大小;
    int应该失败;
    空*(*真实的马洛克)(尺寸);
    }假参数;
    void*fake\u malloc(尺寸){
    假_malloc_params.last_request=大小;
    如果(如果失败,则为假参数){
    返回NULL;
    }
    返回值(假参数、真参数、大小);;
    }
    内部主(空){
    伪_malloc_params.real_malloc=malloc;
    void*ptr=NULL;
    ptr=malloc(1);
    printf(“最后一个:%d\n”,(int)假参数(最后一个请求);
    printf(“ptr:0x%p\n”,ptr);
    返回0;
    }
    
    您可以劫持
    malloc()
    并使其有时返回0。许多库函数,如
    printf
    ,在进程内存不足时可能会失败。@如果
    fprintf()
    处理正确,请说明一切正常。;-)回答得好。不依赖偶然发现问题,让您系统地测试分配失败的后果。+1表示完全覆盖随机测试。SQLite做了类似的事情。malloc()失败是使用计数器触发的,而不是检查堆栈的唯一性。这方面的理论是可靠的,我想实现这一点。您的回答没有具体的实施细节,搜索S.Paavolainen malloc也没有发现任何问题。可以提供一些实现细节吗?我制作了一个共享库来实现这种行为。只要调试符号可用,就可以使用它,而无需通过LD_预加载修改可执行文件。我最终选择了这种方法。我的测试框架需要使用一些额外的编译标志,但它非常灵活。另外,在我的共享对象库中,我没有让malloc随机失败,而是声明了一个全局值,当我指定时,它将使malloc失败。在我的测试代码中,该变量必须声明为
    extern
    #include <stdio.h>
    #include <stdlib.h>
    
    #define malloc(x) fake_malloc(x)
    
    struct {
      size_t last_request;
      int should_fail;
      void *(*real_malloc)(size_t);
    } fake_malloc_params;
    
    void *fake_malloc(size_t size) {
      fake_malloc_params.last_request = size;
      if (fake_malloc_params.should_fail) {
        return NULL;
      }
      return (fake_malloc_params.real_malloc)(size);;
    }
    
    int main(void) {
      fake_malloc_params.real_malloc = malloc;
      void *ptr = NULL;
      ptr = malloc(1);
      printf("last: %d\n", (int) fake_malloc_params.last_request);
      printf("ptr: 0x%p\n", ptr);
      return 0;
    }