NOTE: This post is a long one, documenting the steps I have taken to debug this code. As I got near to the end, I realised what the problem might be. Please scroll to the end of this post to see what I am now attempting. I have included the information about my debugging process, as it may still be useful to look at. I will post again when I have some results.
Alright, so I’ve just gone through GDB again. I ran through the loop. The first time, everything executes successfully. The second time, it aborts on the call to
free(file);. The memory address of file within the
Close_file() function is different, so a different pointer has been passed to the function. My original theory that it was not incrementing is incorrect. I tried setting file to NULL after freeing. Of course, since it is actually incrementing, this made no difference.
So this makes your other suggestion, that the memory has not in fact been allocated, sound more likely. However, when I run the program it is printing out each of these files. I changed the program after uploading it, so that on line 99, when each file is initialised, the
size variable, at the start, is set to
10 + i. This variable does not mean much, but it is a way of differentiating them. The program the prints out these values, and an incremented number is shown in this field. This suggests to me that seperate files are in fact being created. I realise that they could be using illegal memory, but that seems unlikely for 10 different structs, when I have run this repeatedly without seeing an issue there like a segfault.
It actually points to invalid reads on each line of the function, starting at line 69, where I check
if (file->owner != NULL). So the file object passed to it has no value. These checks run without a problem in GDB, but Valgrind is reporting errors. Perhaps the invalid reads are tolerated, but then attempting to free the entire pointer causes the abort signal.
The backtrace from GDB is this:
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7a4ba87 in __GI_abort () at abort.c:90
#2 0x00007ffff7a90a38 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7ba0f52 "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007ffff7a98478 in malloc_printerr (str=str@entry=0x7ffff7ba2ad8 "double free or corruption (out)") at malloc.c:5368
#4 0x00007ffff7a9a410 in _int_free (av=0x7ffff7dd2c20 <main_arena>, p=0x5555557579f0, have_lock=<optimized out>) at malloc.c:4285
#5 0x0000555555554a1b in Close_file (file=0x555555757a00) at attributes.c:75
#6 0x0000555555554977 in Close_dir (dir=0x555555757730) at attributes.c:58
#7 0x0000555555554cfa in main (argc=1, argv=0x7fffffffde48) at attributes.c:129
This also traces the problem to line 75, but no mention of an issue on the previous lines. Valgrind only complains of invalid reads on the other lines, but complains about an invalid free on line 75. I’m not sure why there is a difference, but clearly this call to
free() is more significant.
The amount of memory left not freed is 610 bytes in 10 blocks. This corresponds exactly to the value of
file_size allocated in the
Create_file() function called on line 39, which is what the valgrind output shows on line 124 of the pastebin. That value is created on line 110 of the program. I ran it with
--leak-check=full. However, since it does seem to have freed the first pointer passed to it, I would expect only 9 blocks to be showing instead of 10. I would also expect about 30 additional blocks to show up for the 3 string pointers in each struct, as the loop has not gone through freeing each of these due to the abort signal. So again it seems like the memory may not be allocated even though everything is printing without a problem.
When I look online, everything points to the fact that these invalid reads and frees are caused by either freeing something and then attempting to access it, or not allocating it in the first place. This makes perfect sense. So I’ve had a look at line 99 of the program, where I run the for loop to allocate the returned pointer to a struct for new_dir->files[i][/code], but I can’t see a problem here. That’s where I call
Create_file, which allocates memory for the file struct, then initialises each variable of the struct, including allocating memory for the
char * variables. Then it returns a pointer to file. The debuggers don’t report any issues here. I checked the code at line 99 under GDB, and the address being passed is updating, and the correct values show up in each part of the struct after the function has been run.
I just had a closer look at line 99, and saw that the address returned by
Create_file() is the same each time. The address of
new_dir->files[i] is different each time, but each time it is a pointer to the same object. Perhaps I should restructure this function to take the pointer as an argument, and to directly assign everything to that. I’m not sure why I didn’t do this when I started writing the program, but that seems to me like it might fix the issue. I will attempt that this afternoon and post again when I get some different results.