GVKun编程网logo

c – 如何使用未初始化的数据有意初始化变量,以便valgrind将变量视为未初始化?

20

本篇文章给大家谈谈c–如何使用未初始化的数据有意初始化变量,以便valgrind将变量视为未初始化?,同时本文还将给你拓展c–valgrind给出了未初始化的错误大小、c–使用Valgrind检查时,

本篇文章给大家谈谈c – 如何使用未初始化的数据有意初始化变量,以便valgrind将变量视为未初始化?,同时本文还将给你拓展c – valgrind给出了未初始化的错误大小、c – 使用Valgrind检查时,Libzip示例包含未初始化的值、c – 如何理解允许实现在某些情况下将非局部变量的动态初始化视为静态初始化?、C-根据订单元素添加链表valgrind未初始化错误等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

c – 如何使用未初始化的数据有意初始化变量,以便valgrind将变量视为未初始化?

c – 如何使用未初始化的数据有意初始化变量,以便valgrind将变量视为未初始化?

我的代码中有一个垃圾数据缓冲区,我将其传递给写入它的函数.我不需要这个垃圾缓冲区的数据.由于我需要在多个地方使用这样的垃圾数据缓冲区,但从不从它们读取,我到处使用相同的垃圾缓冲区.

当一些虚假代码从垃圾数据缓冲区中读取时,这将是致命的,或者,例如,当我使用垃圾数据缓冲区时,我应该使用适当的专用缓冲区.

理想情况下,我想让伪代码快速崩溃,因此我在调用写入函数后对数据进行加扰,因此没有人可以使用(并依赖)垃圾数据.

现在我有了一个想法,我可以将未初始化的数据复制到垃圾数据而不是加扰它,因此valgrind可以从垃圾缓冲区中找到所有读取.

我当前的解决方案是new []一些字节,并将未初始化的内容复制到垃圾缓冲区,然后删除[]未初始化的数据.由于未初始化的数据在大多数情况下是0(不幸的是),因此我将其与模式进行异或.对于这么简单的事情,这一切似乎都很复杂.

有没有人想出更好的解决方案?

解决方法

Valgrind(和memcheck)有一个 C API!

你可以这样做:

#include <memcheck.h>

// ....

VALGRIND_MAKE_MEM_UNDEFINED(trash_buffer,trash_length);

如果您希望valgrind将数据视为不可访问而不仅仅是单元化,您还可以使用VALGRIND_MAKE_MEM_NOACCESS.

在valgrind外部运行时,这将只有很少的运行时开销.即使不在valgrind中运行,你复制内容的方法也可能很昂贵.

c – valgrind给出了未初始化的错误大小

c – valgrind给出了未初始化的错误大小

我在博客中看到的sample2.c代码用valgrind来说明未初始化的值.这是代码:
sample2.c:

1  #include <stdio.h>
 2  
 3  int main()
 4  {
 5      int a[5];
 6      int i,s;
 7      a[0]=a[1]=a[3]=a[4]=0;
 8      
 9      printf("%d\n",a[2]);
10      for(i=0;i<5;i++)
11      s += a[i];
12      
13      if(s == 377)
14      printf("sum is %d\n",s);
15      return 0;
16  }

使用gcc -g -o sample2 sample2.c

valgrind –leak-check = full –track-originins = yes ./sample2

我在下面获得了valgrind检查信息.

我不明白为什么在我的机器中由于sizeof(int)== 4而使用大小为8的未初始化值?我在x64机器上运行程序,所以这是指针吗?

==31419== Use of uninitialised value of size 8
==31419==    at 0x4E7F1CB: _itoa_word (in /usr/lib64/libc-2.17.so)
==31419==    by 0x4E83450: vfprintf (in /usr/lib64/libc-2.17.so)
==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
==31419==    by 0x400561: main (sample2.c:9)
==31419==  Uninitialised value was created by a stack allocation
==31419==    at 0x40052D: main (sample2.c:4)

完整检查信息如下:

==31419== Memcheck,a memory error detector
    ==31419== copyright (C) 2002-2017,and GNU GPL'd,by Julian Seward et al.
    ==31419== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
    ==31419== Command: ./sample2
    ==31419== 
    ==31419== Conditional jump or move depends on uninitialised value(s)
    ==31419==    at 0x4E81AFE: vfprintf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x400561: main (sample2.c:9)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    ==31419== Use of uninitialised value of size 8
    ==31419==    at 0x4E7F1CB: _itoa_word (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E83450: vfprintf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x400561: main (sample2.c:9)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    ==31419== Conditional jump or move depends on uninitialised value(s)
    ==31419==    at 0x4E7F1D5: _itoa_word (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E83450: vfprintf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x400561: main (sample2.c:9)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    ==31419== Conditional jump or move depends on uninitialised value(s)
    ==31419==    at 0x4E8349F: vfprintf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x400561: main (sample2.c:9)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    ==31419== Conditional jump or move depends on uninitialised value(s)
    ==31419==    at 0x4E81BCB: vfprintf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x400561: main (sample2.c:9)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    ==31419== Conditional jump or move depends on uninitialised value(s)
    ==31419==    at 0x4E81C4E: vfprintf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x4E8A338: printf (in /usr/lib64/libc-2.17.so)
    ==31419==    by 0x400561: main (sample2.c:9)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    4195392
    ==31419== Conditional jump or move depends on uninitialised value(s)
    ==31419==    at 0x400588: main (sample2.c:13)
    ==31419==  Uninitialised value was created by a stack allocation
    ==31419==    at 0x40052D: main (sample2.c:4)
    ==31419== 
    ==31419== 
    ==31419== HEAP SUMMARY:
    ==31419==     in use at exit: 0 bytes in 0 blocks
    ==31419==   total heap usage: 0 allocs,0 frees,0 bytes allocated
    ==31419== 
    ==31419== All heap blocks were freed -- no leaks are possible
    ==31419== 
    ==31419== For counts of detected and suppressed errors,rerun with: -v

解决方法

你有一个64位处理器.即使值本身是32位,它也会在64位寄存器中传递给printf;这来自x86-64的System-V调用约定.

然而,它似乎没有触发错误,直到后来,valgrind似乎只知道该值被符号扩展为64位并且最初来自您的main函数(甚至行号在那里是错误的.

如果使用-m32编译它并以某种方式设法在valgrind下运行它(我需要在Ubuntu上安装其他32位软件包),你可以在这里看到4:

==4854== Use of uninitialised value of size 4
==4854==    at 0x48A3CAB: _itoa_word (_itoa.c:179)
==4854==    by 0x48A85C5: vfprintf (vfprintf.c:1642)
==4854==    by 0x48AF2F5: printf (printf.c:33)
==4854==    by 0x1085D0: main (sample2.c:9)
==4854== 
==4854== Conditional jump or move depends on uninitialised value(s)
==4854==    at 0x48A3CB3: _itoa_word (_itoa.c:179)
==4854==    by 0x48A85C5: vfprintf (vfprintf.c:1642)
==4854==    by 0x48AF2F5: printf (printf.c:33)
==4854==    by 0x1085D0: main (sample2.c:9)
==4854==

这里需要注意的一点是,int [2]中的值是不确定的,但是没有int类型的陷阱值,并且它的地址被取而代之,因此将它传递给函数时没有未定义的行为 – 但是在库函数中使用的确如此.

c – 使用Valgrind检查时,Libzip示例包含未初始化的值

c – 使用Valgrind检查时,Libzip示例包含未初始化的值

我一直在使用libzip来处理zip文件,并根据rodrigo对 this question的回答找到了我的代码.这是他的代码,供快速参考:
#include <zip.h>

int main()
{
    //Open the ZIP archive
    int err = 0;
    zip *z = zip_open("foo.zip",&err);

    //Search for the file of given name
    const char *name = "file.txt";
    struct zip_stat st;
    zip_stat_init(&st);
    zip_stat(z,name,&st);

    //Alloc memory for its uncompressed contents
    char *contents = new char[st.size];

    //Read the compressed file
    zip_file *f = zip_fopen(z,"file.txt",0);
    zip_fread(f,contents,st.size);
    zip_fclose(f);

    //And close the archive
    zip_close(z);
}

我追踪了我随后从Valgrind得到的错误回到了这段代码 – 当使用’zip_fopen()`打开压缩的“file.txt”时,它会抱怨未初始化的值.

==29256== Conditional jump or move depends on uninitialised value(s)
==29256==    at 0x5B4B290: inflateReset2 (in /usr/lib/libz.so.1.2.3.4)
==29256==    by 0x5B4B37F: inflateInit2_ (in /usr/lib/libz.so.1.2.3.4)
==29256==    by 0x4E2EB8C: zip_fopen_index (in /usr/lib/libzip.so.1.0.0)
==29256==    by 0x400C32: main (main.cpp:24)
==29256==  Uninitialised value was created by a heap allocation
==29256==    at 0x4C244E8: malloc (vg_replace_malloc.c:236)
==29256==    by 0x5B4B35B: inflateInit2_ (in /usr/lib/libz.so.1.2.3.4)
==29256==    by 0x4E2EB8C: zip_fopen_index (in /usr/lib/libzip.so.1.0.0)
==29256==    by 0x400C32: main (main.cpp:24)
==29256==
==29256==
==29256== HEAP SUMMARY:
==29256==     in use at exit: 71 bytes in 1 blocks
==29256==   total heap usage: 26 allocs,25 frees,85,851 bytes allocated
==29256==
==29256== 71 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29256==    at 0x4C24A72: operator new[](unsigned long) (vg_replace_malloc.c:305)
==29256==    by 0x400BEE: main (main.cpp:19)

我无法在此代码中看到未初始化值的来源.任何人都可以追踪这个,或者libzip本身的错误是什么?我应该切换到另一个zip库 – 例如,Minizip吗?

编辑:71字节是file.txt的内容,读取in-delete []内容;在最后标记将消除这一点.

(我已经对最初的答案留下了评论,以引起对这个问题的关注,但我没有必要的代表.)

解决方法

你让我看:)

是的,这是zlib中的一个错误(由libzip使用),因为内存的分配和使用都在同一个调用的inflateInit2_内.你的代码甚至没有机会进入那段记忆.

我可以使用zlib 1.2.3重复这个问题,但它在1.2.7中不再出现了.我没有1.2.3的代码可用,但是如果你正在查看它,我会检查状态的初始化以及它在inflateReset2中的使用方式.

编辑:追踪问题,我下载了Ubuntu的zlib源代码包(1.2.3.4)和违规行;

if (state->wbits != windowBits && state->window != Z_NULL) {

wbits在此之前未初始化,并将导致警告.奇怪的是原始的zlib 1.2.3或1.2.4都没有这个问题,它似乎对Ubuntu来说是独一无二的. 1.2.3甚至没有函数inflateReset2,而1.2.4也没有;

if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {

由于窗口先前已初始化为Z_NULL,因此不会发生未初始化的wbits读取.

c – 如何理解允许实现在某些情况下将非局部变量的动态初始化视为静态初始化?

c – 如何理解允许实现在某些情况下将非局部变量的动态初始化视为静态初始化?

事实上,问题来自标准草案N4582中的文字:

[basic.start.static/3] An implementation is permitted to perform the initialization of a variable with static or thread storage duration as a static initialization even if such initialization is not required to be done statically,provided that

— the dynamic version of the initialization does not change the value of any other object of static or thread storage duration prior to its initialization,and

— the static version of the initialization produces the same value in the initialized variable as would be produced by the dynamic initialization if all variables not required to be initialized statically were initialized dynamically.

这些词是否意味着如果满足这两个条件,则类型的非局部变量可以静态完全初始化(零初始化),以便不调用其构造函数(因为动态版本,通过调用构造函数初始化,可能被静态版本取代)?

解决方法

在编译/链接期间执行静态初始化.编译器/链接器为静态存储器中的变量分配一个位置,并用正确的字节填充它(字节不需要全为零).程序启动时,静态存储器的那些区域从程序的二进制文件加载,不需要进一步初始化.

例子:

namespace A {
    // statically zero-initialized
    int a;
    char buf1[10];

    // non-zero initialized
    int b = 1;
    char date_format[] = "YYYY-MM-DD";
}

与静态初始化不同,动态初始化需要在程序启动后运行一些代码,以将初始化变量设置为初始状态.需要运行的代码不需要是构造函数调用.

例子:

namespace B {
    int a = strlen(A::date_format);   (1)
    int b = ++a;                      (2)

    time_t t = time();                (3)

    struct C {
        int i;

        C() : i(123) {}
    };

    C c;                              (4)

    double s = std::sqrt(2);          (5)
}

现在,C标准允许编译器执行在动态初始化期间执行的计算,前提是这些计算没有副作用.此外,这些计算不得依赖于外部环境.在上面的例子中:

(1)可以静态执行,因为strlen()没有任何副作用.

(2)因为变异而必须保持动态.

(3)必须保持动态,因为它取决于外部环境/进行系统调用.

(4)可以静态执行.

(5)有点棘手,因为浮点计算取决于FPU的状态(即舍入模式).如果编译器被告知不要认真对待浮点运算,那么它可以静态执行.

C-根据订单元素添加链表valgrind未初始化错误

C-根据订单元素添加链表valgrind未初始化错误

问题是您有混合类型列表,但是ll_contains强制比较一种固定类型。

所以发生的是,当您按此顺序执行时

ll_add_end(test_ll,&double_val,DOUBLE);  /* This order causes no errors! */
ll_add_end(test_ll,&int_val,INT);
assert(ll_contains(test_ll,DOUBLE) == true);

double值在列表中排在第一位,因此它在与int比较之前返回。

当订单冲销时

ll_add_end(test_ll,INT);  /* This order causes the error! */
ll_add_end(test_ll,DOUBLE);
assert(ll_contains(test_ll,DOUBLE) == true);

您首先拥有int,然后拥有double。因此,您需要在intdouble

之间进行比较
if (*((double*)current->data) == *((double*)data))  /* ERROR HERE */

但是current->data实际上是指向int的指针。 malloced时,您可能取回的不仅仅是4个字节-iirc大约为24个字节。因此,当您执行此比较时,第四个字节之后的字节未初始化。

在比较功能中,您需要在投射和检查之前检查类型 数据。

while (current != NULL)
{
   if (current->type) == type)
   switch (type)
   {
   case INT:
      if (*((int*)current->data) == *((int*)data))
      {
         return true;
      }
      break;
      // etc.
   }
   current = current->next;
}

今天关于c – 如何使用未初始化的数据有意初始化变量,以便valgrind将变量视为未初始化?的讲解已经结束,谢谢您的阅读,如果想了解更多关于c – valgrind给出了未初始化的错误大小、c – 使用Valgrind检查时,Libzip示例包含未初始化的值、c – 如何理解允许实现在某些情况下将非局部变量的动态初始化视为静态初始化?、C-根据订单元素添加链表valgrind未初始化错误的相关知识,请在本站搜索。

本文标签: