0

I'm confronted to a strange problem, my program has a segfault when i try to access a structure member but my structure's address is not NULL and I've never freed this structure.

The structure's address is something like "0x8000000000" or "0x2000000000".

Here is gdb's bt :

Program received signal SIGSEGV, Segmentation fault.
0x00000001000039cc in ft_sort_ascii (files=0x8000000000000) at srcs/sort/ascii.c:43
43      while (i < files->len)
(gdb) bt
#0  0x00000001000039cc in ft_sort_ascii (files=0x8000000000000) at srcs/sort/ascii.c:43
#1  0x0000000100003a3c in ft_sort_ascii (files=0x10080a400) at srcs/sort/ascii.c:50
#2  0x0000000100003a3c in ft_sort_ascii (files=0x1001080d0) at srcs/sort/ascii.c:50
#3  0x0000000100003a3c in ft_sort_ascii (files=0x100801800) at srcs/sort/ascii.c:50
#4  0x0000000100003a3c in ft_sort_ascii (files=0x100801200) at srcs/sort/ascii.c:50
#5  0x0000000100003a3c in ft_sort_ascii (files=0x100104c10) at srcs/sort/ascii.c:50
#6  0x0000000100002137 in main (ac=1, av=0x7fff5fbff758) at srcs/main.c:26

The valgrind report :

==29835==
==29835== HEAP SUMMARY:
==29835==     in use at exit: 415,075 bytes in 11,152 blocks
==29835==   total heap usage: 17,711 allocs, 6,559 frees, 3,960,490 bytes allocated
==29835==
==29835== 112 bytes in 1 blocks are definitely lost in loss record 106 of 178
==29835==    at 0x10000CCA1: calloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x1004ABC11: class_createInstance (in /usr/lib/libobjc.A.dylib)
==29835==    by 0x10010F920: _os_object_alloc_realized (in /usr/lib/system/libdispatch.dylib)
==29835==    by 0x1004650D5: _xpc_pipe_create (in /usr/lib/system/libxpc.dylib)
==29835==    by 0x100467655: xpc_pipe_create (in /usr/lib/system/libxpc.dylib)
==29835==    by 0x1002AE100: _od_xpc_pipe (in /usr/lib/system/libsystem_info.dylib)
==29835==    by 0x1002AE044: _od_running (in /usr/lib/system/libsystem_info.dylib)
==29835==    by 0x1002ADFD8: ds_user_byuid (in /usr/lib/system/libsystem_info.dylib)
==29835==    by 0x1002ADF46: search_item_bynumber (in /usr/lib/system/libsystem_info.dylib)
==29835==    by 0x1002ADE82: getpwuid (in /usr/lib/system/libsystem_info.dylib)
==29835==    by 0x1000029EB: ft_get_file_infos (in ./ft_ls)
==29835==    by 0x1000027B4: ft_set_infos_foreach (in ./ft_ls)
==29835==
==29835== 121 bytes in 1 blocks are definitely lost in loss record 107 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002F6B: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100002120: main (in ./ft_ls)
==29835==
==29835== 405 bytes in 5 blocks are definitely lost in loss record 130 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002F6B: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100002120: main (in ./ft_ls)
==29835==
==29835== 516 bytes in 20 blocks are definitely lost in loss record 133 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002F6B: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==
==29835== 2,523 bytes in 27 blocks are definitely lost in loss record 157 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002F6B: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100002120: main (in ./ft_ls)
==29835==
==29835== 6,124 bytes in 140 blocks are definitely lost in loss record 165 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002F6B: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100002120: main (in ./ft_ls)
==29835==
==29835== 6,493 bytes in 205 blocks are definitely lost in loss record 166 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002F6B: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100003061: ft_open_directories (in ./ft_ls)
==29835==    by 0x10000276E: ft_set_files (in ./ft_ls)
==29835==    by 0x100002120: main (in ./ft_ls)
==29835==
==29835== 341,832 (104 direct, 341,728 indirect) bytes in 1 blocks are definitely lost in loss record 178 of 178
==29835==    at 0x10000C59B: malloc (in /usr/local/Cellar/valgrind/HEAD/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==29835==    by 0x100002474: ft_set_files (in ./ft_ls)
==29835==    by 0x100002120: main (in ./ft_ls)
==29835==
==29835== LEAK SUMMARY:
==29835==    definitely lost: 16,398 bytes in 400 blocks
==29835==    indirectly lost: 341,728 bytes in 10,269 blocks
==29835==      possibly lost: 0 bytes in 0 blocks
==29835==    still reachable: 22,201 bytes in 62 blocks
==29835==         suppressed: 34,748 bytes in 421 blocks
==29835== Reachable blocks (those to which a pointer was found) are not shown.
==29835== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==29835==
==29835== For counts of detected and suppressed errors, rerun with: -v
==29835== ERROR SUMMARY: 1243 errors from 14 contexts (suppressed: 21 from 21)

Seems i have many errors/leaks, i do not free my memory that i used once (all my t_files) because they will be freed at the end of program.

And here is my code :

static void     ft_swap_files(t_files *files, size_t *i)
{
    size_t  j;
    t_files tmp;

    j = *i + 1;
    while (j < files->len)
    {
        if (files[j].error < 0)
        {
            if (ft_strcmp(files[*i].name, files[j].name) > 0)
            {
                tmp = files[*i];
                files[*i] = files[j];
                files[j] = tmp;
                *i = -1;
                return ;
            }
        }
        j++;
    }
}

void            ft_sort_ascii(t_files *files)
{
    size_t  i;

    i = 0;
    while (i < files->len)
    {
        if (files[i].error < 0)
        {
            ft_swap_files(files, &i);
            if (files[i].files != NULL)
            {
                ft_sort_ascii(files[i].files);
            }
        }
        i++;
    }
}

My t_files structure :

typedef struct      s_files
{
    size_t          len;
    t_bool          hidden;
    int             error;
    char            *path;
    char            *name;
    char            *sym_name;
    char            *rights;
    char            *uid;
    char            *gid;
    char            *time;
    int             nlink_max;
    int             size_max;

    /*
    ** from stat
    */
    int             type;
    int             nlink;
    int             size;

    t_bool          rd;
    struct s_files  *files;
}                   t_files;

This error occurs after multiple recursive calls. "files[i].files" is initialized to NULL in another file and is malloc if necessary.

Recursive calls may cause issues ?

Thank's ;)

Ziad
  • 419
  • 3
  • 7
  • 15
  • 3
    This smells like memory corruption (long?) before the crash. Try running your program using a memory checker like Valgrind (http://valgrind.org). – alk Mar 09 '15 at 17:41
  • 1
    Memory address doesn't have to be NULL to trigger the memory violation when accessed. It's enough that it is just out of the accessible range (if there is a memory protection), or if overwriting some essential data/code. Recursion can cause a stack overflow s well, so try to narrow down your problem. – Eugene Sh. Mar 09 '15 at 17:42
  • 3
    And why do you title "*Accessing a NULL pointer*" when you explicitly do not access a NULL pointer ("*address is not NULL*)"? – alk Mar 09 '15 at 17:42
  • Your `t_files` structure contains a pointer to an array of `t_files` structures? Can you explain your data structure? – Michael Burr Mar 09 '15 at 17:44
  • This call `ft_swap_files(files, &i);` is likely doing the wrong thing. If it replaces a specified file with an error (i) with the last element of the list and then shortens the list, then you aren't protecting against the last element being chopped off the list and then you operating on it anyway. – jschultz410 Mar 09 '15 at 17:46
  • I don't understand how this even compiles. You are accessing "files" as a pointer to a structure (`files->len`) and as an array (`files[i]`). Can you show us the declaration of `t_files`? – Lee Daniel Crocker Mar 09 '15 at 18:00
  • @alk you've right, my title is wrong, i will change it (if i can). I will also try with valgrind (i've never use it, but that is a great first time for !). jschultz410 my ft_swap_files is protected (i think) because i swap t_files structure only if my index is under my file's length. Micheal Burr and Lee Daniel Crocker my i've edited my post to show you my t_files structure – Ziad Mar 09 '15 at 18:10
  • 1
    Use [valgrind](http://valgrind.org/) if possible – Basile Starynkevitch Mar 09 '15 at 18:13
  • @Zlad: more than the `t_files` structure definition, how is the data structure used? What would it look like when populated? – Michael Burr Mar 09 '15 at 18:38
  • @MichaelBurr my code is a little bit complicated i think, i've used cross recursivety to populate my t_files. My code is available in my github -> [link](https://github.com/ziadsarour/ft_ls) in srcs/parser/files.c and srcs/directories/open.c – Ziad Mar 09 '15 at 18:50

1 Answers1

1

You have a potential array underflow access in ft_sort_ascii(). In ft_swap_files() you have the code:

      *i = -1;
      return ;
 }

which returns to the following code in ft_sort_ascii():

 ft_swap_files(files, &i);

 if (files[i].files != NULL)    // Underflow here if i == -1
 {
     ft_sort_ascii(files[i].files);  // and here if it gets this far
 }

which underflows the files[] array. You'll need to check if i is a valid index before performing any array access with it.

uesp
  • 6,194
  • 20
  • 15
  • i is a valid index because on ft_swap_files return, i is incremented to finally be set to 0 -> if (files[i].error < 0) { ft_swap_files(files, &i); if (files[i].files != NULL) { ft_sort_ascii(files[i].files); } } i++; – Ziad Mar 09 '15 at 20:01
  • @Zlad: but the `if` statement immediately after the `ft_swap_files()` call accesses `files[i]` before `i` is incremented. – Michael Burr Mar 09 '15 at 20:42
  • Btw, is that good/correct to access a structure's member like "files->len" whereas "files" is a structures array ? I know that len is set identically in every index of my array (files[0], files[1], etc.). Thanks again guys ! – Ziad Mar 09 '15 at 22:55
  • Another (and last) question, should I free my array of structures, even if my program normally leaves ? – Ziad Mar 09 '15 at 23:16
  • Doing `files->len` is the same as `files[0]->len` and, while not technically wrong, is a little unconventional. It would be better to pass an array length of `files` into your functions explicitly. – uesp Mar 10 '15 at 14:02
  • Regarding freeing memory before exiting your program, technically you don't need to but it is a bad habit to get into. It may work for this program but next week/month when you reuse the same code in another program you may (will) end up leaking memory. – uesp Mar 10 '15 at 14:03
  • Thank you all, i now use valgrind so no more memory leaks ;) – Ziad Mar 12 '15 at 16:13