条件跳转或移动取决于酉值

时间:2018-05-17 15:56:23

标签: c memory valgrind

所以,valgrind给了我那个错误,我用--track-origins = yes运行它并找到了错误所在的行,但我不明白错误是什么或如何解决它。

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

typedef struct Date{
    int year;
    int month;
    int day;
} Date;

typedef struct Data{
    Date date;
    float temp;
    float uncertainty;
    char country[100];
} Data;

int main(){
    FILE* f = fopen("tempcountries_short.csv", "r");
    char* line = NULL;
    int capacity = 0;
    int countries_capacity = 0;
    int line_ix = 0;
    char c;
    Data* country = NULL;
    while ((c = fgetc(f)) != '\n'){ 
        if (line_ix + 1 > capacity){
            if (capacity == 0)                    
                capacity = 10;
            else
                capacity = capacity * 2;
            line = realloc(line, capacity); 
        }
        line[line_ix] = c;
        line_ix++;
    }
    if (countries_capacity == 0)
        countries_capacity = 10;
    else
        countries_capacity = countries_capacity * 2;
    country = realloc(country, countries_capacity);
    printf("%i\n",sscanf(line, "%i - %i - %i, %f , %f , %s", 
           &country->date.year, &country->date.month,
           &country->date.day, &country->temp, &country->uncertainty,
           country->country));
}

这是Valgrind的输出,选项--leak-check = full和--track-originins = yes:https://pastebin.com/EyqDGBmQ正如你所看到的还有很多其他错误,我不明白是什么导致他们。

该程序正在从包含许多国家温度数据的文件中读取行,我只是将一部分代码用于复制错误,但country应该是许多数据结构的数组。这是我正在阅读的文件中的示例行:

1972-03-01,4.787,0.342,斯洛伐克

3 个答案:

答案 0 :(得分:3)

country = realloc(country, countries_capacity);

您似乎依赖realloc(0, new_size)来表现malloc(new_size)。没关系,但是你必须确保传递给realloc的指针变量确实为空。此点之前没有代码初始化country变量,并在其声明中......

Data* country;

...没有初始化程序。将其更改为

Data *country = 0;

问题的那部分应该消失。

通常,当您从valgrind收到一连串错误时,只有第一个错误有意义,所以看看是否能解决所有问题。

编辑:对于上面更正的程序版本,输入显示的输入样本行,我不会对realloc内的未初始化值有任何抱怨,但我仍然抱怨未初始化的值在sscanf内:

==28542== Conditional jump or move depends on uninitialised value(s)
==28542==    at 0x4C340E6: rawmemchr (vg_replace_strmem.c:1409)
==28542==    by 0x4EB6291: _IO_str_init_static_internal (strops.c:41)
==28542==    by 0x4EA476C: __isoc99_vsscanf (isoc99_vsscanf.c:41)
==28542==    by 0x4EA46D3: __isoc99_sscanf (isoc99_sscanf.c:31)
==28542==    by 0x108886: main (in /tmp/a.out)

以及关于无效写入的投诉:

==28542== Invalid write of size 4
==28542==    at 0x4E98FFB: _IO_vfscanf (vfscanf.c:1898)
==28542==    by 0x4EA4781: __isoc99_vsscanf (isoc99_vsscanf.c:43)
==28542==    by 0x4EA46D3: __isoc99_sscanf (isoc99_sscanf.c:31)
==28542==    by 0x108886: main (in /tmp/a.out)
==28542==  Address 0x51f41a8 is 8 bytes inside a block of size 10 alloc'd
==28542==    at 0x4C2CABF: malloc (vg_replace_malloc.c:298)
==28542==    by 0x4C2EE04: realloc (vg_replace_malloc.c:785)
==28542==    by 0x10883C: main (in /tmp/a.out)

这些都是由真正的错误引起的:第一个是因为line数组永远不会被制作成正确的C字符串(通过添加一个nul终止符),第二个是因为 size 传递给realloc是错误的。你需要

line[line_ix] = '\0';

while循环后立即

country = realloc(country, countries_capacity * sizeof(Data));

而不是现在的realloc电话。

随着这些变化,我得到了valgrind投诉。您仍然遇到sscanf使用always a bad idea的问题,但valgrind无法为您提供帮助。

答案 1 :(得分:1)

问题在于:

std::initializer_list

country = realloc(country, countries_capacity); 尚未初始化,它包含不确定的值。

在声明后,只需将country初始化为country

NULL

答案 2 :(得分:1)

行的最后一个字符必须设置为\ 0,才能成为一个正确的以空字符结尾的字符串。