Reputation: 219
These 2 errors are coming up with a linked list/low level file read/strtok program.
==10982== Use of uninitialised value of size 4
==10982== at 0x40C3899: strtok (strtok.S:197)
==10982== by 0x8048719: main (main.c:9)
==10982== Uninitialised value was created by a stack allocation
==10982== at 0x80487D2: buildList (functions.c:13)
==10982==
==10982== Use of uninitialised value of size 4
==10982== at 0x40C38C1: strtok (strtok.S:223)
==10982== by 0x8048719: main (main.c:9)
==10982== Uninitialised value was created by a stack allocation
==10982== at 0x80487D2: buildList (functions.c:13)
==10982==
==10982== Conditional jump or move depends on uninitialised value(s)
==10982== at 0x40C38C4: strtok (strtok.S:224)
==10982== by 0x8048719: main (main.c:9)
==10982== Uninitialised value was created by a stack allocation
==10982== at 0x80487D2: buildList (functions.c:13)
Here is the function buildList
void buildList(int fdin, int lines)
{
char ara[4096];
int num;
double p;
read(fdin, ara, 4096);
char *nl = "\n";
char *ws = " ";
char *temp = strtok(ara, " ");
while(temp != NULL)
{
Stock *s = (Stock*)calloc(1, sizeof(Stock));
s->c.symbol = (char*)calloc(strlen(temp)+1, sizeof(char));
strcpy(s->c.symbol, temp);
temp = strtok(NULL, "\n");
s->c.name = (char*)calloc(strlen(temp)+1, sizeof(char));
strcpy(s->c.name, temp);
temp = strtok(NULL, "\n");
sscanf(temp, "%lf", &p);
temp = strtok(NULL, "\n");
s->price = p;
sscanf(temp, "%d", &num);
s->shares = num;
Node *n = (Node*)calloc(1, sizeof(Node));
n->data = s;
addOrdered(n);
temp = strtok(NULL, " ");
}
close(fdin);
}
I cannot figure out why this error occurs. From what I've read it is because I am assigning things to a char* from strtok without assigning any memory to them. However this is how I have done it in the past and I think it has been fine.
Upvotes: 6
Views: 8698
Reputation: 70492
As others have surmised, valgrind
is complaining that strtok
is making use of uninitialized memory. The question then turns to why, since it seems like it is being initialized by:
read(fdin, ara, 4096);
However, read()
does not \0
terminate the data, while strtok
expects a \0
terminated string. Make sure the input is terminated properly:
ssize_t result = read(fdin, ara, sizeof(ara)-1); /* leave room for '\0' */
ara[result > 0 ? result : 0] = '\0';
The memset(ara, 0, sizeof(ara));
suggestion by Lee Daniel Crocker amounts to the same kind of fix, but it only works if the file contains less than sizeof(ara)
bytes of input. You are still exposed to a similar problem if the file you read from has 4096 bytes of data or more. Then, strtok
will be forced to scan past the end of the buffer to look for the \0
, leading to undefined behavior.
Upvotes: 6
Reputation:
read(fdin, ara, 4096);
...which could return:
ara
wasn't filled in;ara
wasn't filled in;ara
are filled in.Always check the return value of read()
.
char *temp = strtok(ara, " ");
$ man strtok
...
The strtok() function is used to isolate sequential tokens in a null-ter-
minated string, str. ...
There is nothing whatsoever that guarantees that ara
has a null character ('\0'
) in it, so you cannot validly hand it to strtok()
. Make it char ara[4097]
and do ara[4096] = '\0';
after the read if you want to make sure that there's a '\0'
in it.
Or, even better, if read()
's return value is in a variable data_read
, and you've already checked to make sure it's not -1, do ara[data_read] = '\0';
, so that you set the byte after the last one read to '\0'
.
And what happens if the file has more than 4096 characters, and your read()
call reads in, for example, several lines and the beginning of another line? Given that, you might want to consider using fopen()
to open the file and use fgets()
to read lines.
Upvotes: 3
Reputation: 2428
Does the data read by read
have a null terminator at the end? If not, that's probably the issue.
Upvotes: 1