So, valgrind gave me that error and I ran it with --track-origins=yes and found the line where the error is, but I don't understand what the error is or how to fix it.
#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));
}
This is the output from Valgrind, with options --leak-check=full and --track-origins=yes: https://pastebin.com/EyqDGBmQ As you can see there are many other errors, and I don't understand what causes them either.
The program is reading lines from a file with data about many countries temperatures, I just took the part of the code for a single country to replicate the error, but country is supposed to be an array of many Data structs. Here's an example line from the file I'm reading:
1972-03-01,4.787,0.342,Slovakia
country = realloc(country, countries_capacity);
You appear to be relying on realloc(0, new_size)
to behave as malloc(new_size)
. That's fine, but then you must make sure that the pointer variable passed to realloc
really is null. No code before this point initializes the country
variable, and in its declaration ...
Data* country;
... there's no initializer. Change this to
Data *country = 0;
and that part of the problem should go away.
Often, when you get a whole string of errors from valgrind
, only the first one is meaningful, so see if that fixes all of your problems.
EDIT: With the version of the program with the above corrected, fed the sample line of input shown, I do not get any complaints about uninitialized values inside realloc
, but I do still get a complaint about uninitialized values inside 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)
and a complaint about invalid writes:
==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)
These are both caused by real bugs: the first is because the line
array is never made into a proper C-string (by adding a nul terminator), the second is because the size passed to realloc
is wrong. You need
line[line_ix] = '\0';
immediately after the while
loop, and
country = realloc(country, countries_capacity * sizeof(Data));
instead of the realloc
call you have now.
With those changes, I get no valgrind complaints. You do still have the problem that you're using sscanf
, which is always a bad idea, but valgrind can't help you with that.