条件跳转或移动取决于未初始化的值和无效的大小写

时间:2015-10-17 22:18:50

标签: c++ memory valgrind

我有一些与内存有关的奇怪问题。这是我的代码:

#include <iostream>
#include <string.h>
#include <cstdlib>
#include <stdio.h>

struct Pair{
char *key;
unsigned long long int value;
};


int main()
{
    Pair p;
    char string[256];
    char path[100];
    int i;
    int l;
    std::cout<<"ENTER THE DIRECTORY"<<std::endl;
    std::cin>>path;
    FILE *f = fopen(path,"wb");
    for (i = 0; i<5; i++) {
        std::cin>>string;
        p.key = new char[strlen(string)];
        l = strlen(p.key);
        std::cin>>p.value;
        strcpy(p.key,string);
        if (!fwrite(&l,sizeof(int),1,f))
            perror("ERROR: ");
        if (!fwrite(p.key, sizeof(char),l,f))
             perror("ERROR: ");
        if (!fwrite(&p.value, sizeof(unsigned long long int),1,f))
             perror("ERROR: ");
        std::cout<<p.key<<" "<<p.value<<std::endl;
        delete [] p.key;
    }
        fclose(f);
        f = fopen(path,"rb");
        for (i = 0; i<5; i++) {
        if (!fread(&l,sizeof(int),1,f))
            perror("ERROR: ");
        p.key = new char[l];
        if (!fread(p.key,sizeof(char),l,f))
            perror("ERROR: ");
        if (!fread(&p.value, sizeof(unsigned long long int),1,f))
            perror("ERROR: ");
        std::cout<<p.key<<" "<<p.value<<std::endl;
        delete [] p.key;
    }
    fclose(f);
    return 0;
}

但是valgrind说,条件跳跃或移动取决于l = strlen中未初始化的值(p.key);更重要的是,没有valgrind从文件中读取后它不会显示关键的唯一值。

==10157== Conditional jump or move depends on uninitialised value(s)
==10157==    at 0x402D3EB: strlen (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10157==    by 0x8048A84: main (main.cpp:25)
==10157== 
==10157== Invalid write of size 1
==10157==    at 0x402D506: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10157==    by 0x8048AB6: main (main.cpp:27)
==10157==  Address 0x434c1bc is 0 bytes after a block of size 4 alloc'd
==10157==    at 0x402ADFC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10157==    by 0x8048A74: main (main.cpp:24)

如果我将l = strlen(p.key)更改为l = strlen(字符串)valgrind说

==10030== Invalid write of size 1
==10030==    at 0x402D506: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10030==    by 0x8048AB9: main (main.cpp:27)
==10030==  Address 0x434c1bb is 0 bytes after a block of size 3 alloc'd
==10030==    at 0x402ADFC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10030==    by 0x8048A74: main (main.cpp:24)
==10030== 
==10030== Invalid read of size 1
==10030==    at 0x402D3F3: strlen (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10030==    by 0x40D33E4: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.19)
==10030==    by 0x8048B85: main (main.cpp:34)
==10030==  Address 0x434c1bb is 0 bytes after a block of size 3 alloc'd
==10030==    at 0x402ADFC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==10030==    by 0x8048A74: main (main.cpp:24)

同样的事情是strcpy功能。 我还尝试使用&#39; \ 0&#39;初始化p.key。通过memset,但valgrind写道

==10562== Invalid write of size 4
==10562==    at 0x403087D: memset (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
...
valgrind: m_mallocfree.c:277 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
 end of a heap block and corrupting heap metadata.  If you fix any
 invalid writes reported by Memcheck, this assertion failure will
 probably go away.  Please try that before reporting this as a bug.

那么,为什么我在这个简单的代码中遇到这些问题以及他们决定的可能方法,请帮助我。

1 个答案:

答案 0 :(得分:2)

问题1

p.key = new char[strlen(string)];
l = strlen(p.key);

您正在使用未初始化的p.key。由于strlen依赖于空终止字符数组,因此调用strlen(p.key)会导致未定义的行为。

问题2

strcpy(p.key,string);

也是一个问题。您没有分配足够的内存来保存p.key中的终止空字符。你需要使用:

p.key = new char[strlen(string)+1];
                            // ^^ Need the additional character

问题3

以下行有助于恢复文件内容。但是,字符串不会以空值终止。

p.key = new char[l];
if (!fread(p.key,sizeof(char),l,f))

您需要使用:

p.key = new char[l+1];
               // ^^ Need the additional character
if (!fread(p.key,sizeof(char),l,f))
p.key[l] = '\0`;