0

When I try recursively traverse directories in fork.Fork causing memory leak.İf I do just fork everythink okey but when I called function in child process I see memory leak on valgrind.I think ,I close every directory.But valgrind says opendir_tail.I tried write clodir in parent but then I take 1 allocated but 2 free error.Where is the problem ?

Here my code.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <ctype.h>

int dfsdirectory (char *path){
DIR* dir;   
struct dirent *dirEntry;  
struct stat fileStat;     
char _PathN[1000];       

int totalSize=0;
  if (!(dir = opendir(path))){
    closedir(dir);
    return -1;
  }
  while ( ((dirEntry=readdir(dir)) != 0)  ) {
    int dirSize=0;

    if (strcmp(dirEntry->d_name, ".") == 0 
     || strcmp(dirEntry->d_name, "..") == 0)  
        continue;

    snprintf(_PathN, sizeof(_PathN), "%s/%s", path, dirEntry->d_name);
    lstat (_PathN, &fileStat);

    if (S_ISDIR(fileStat.st_mode)){
        int PID = fork();

        if(PID<0){
            closedir(dir);
            return -1;
        }

        if(PID == 0){
          dfsdirectory(_PathN);
            while ((closedir(dir) == -1) && (errno == EINTR));      
            exit(0);
        } 
        else{                
            wait(NULL);   
        }
    }
}
      closedir(dir);
      return totalSize; 
}

int main() {    
   dfsdirectory("A");   
}

And valgrind output

==4070== Memcheck, a memory error detector
==4070== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4070== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright 
info
==4070== Command: ./main
==4070== Parent PID: 953
==4070== 
==4072== 
==4072== HEAP SUMMARY:
==4072==     in use at exit: 32,816 bytes in 1 blocks
==4072==   total heap usage: 3 allocs, 2 frees, 98,448 bytes allocated
==4072== 
==4072== 32,816 bytes in 1 blocks are still reachable in loss record 1 of 1
==4072==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==4072==    by 0x4EEB813: __alloc_dir (opendir.c:247)
==4072==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4072==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4072==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4072== 
==4072== LEAK SUMMARY:
==4072==    definitely lost: 0 bytes in 0 blocks
==4072==    indirectly lost: 0 bytes in 0 blocks
==4072==      possibly lost: 0 bytes in 0 blocks
==4072==    still reachable: 32,816 bytes in 1 blocks
==4072==         suppressed: 0 bytes in 0 blocks
==4072== 
==4072== For counts of detected and suppressed errors, rerun with: -v
==4072== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==4071== 
==4071== HEAP SUMMARY:
==4071==     in use at exit: 0 bytes in 0 blocks
==4071==   total heap usage: 2 allocs, 2 frees, 65,632 bytes allocated
==4071== 
==4071== All heap blocks were freed -- no leaks are possible
==4071== 
==4071== For counts of detected and suppressed errors, rerun with: -v
==4071== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==4075== 
==4075== HEAP SUMMARY:
==4075==     in use at exit: 65,632 bytes in 2 blocks
==4075==   total heap usage: 4 allocs, 2 frees, 131,264 bytes allocated
==4075== 
==4075== 32,816 bytes in 1 blocks are still reachable in loss record 1 of 2
==4075==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==4075==    by 0x4EEB813: __alloc_dir (opendir.c:247)
==4075==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4075==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4075==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4075== 
==4075== 32,816 bytes in 1 blocks are still reachable in loss record 2 of 2
==4075==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==4075==    by 0x4EEB813: __alloc_dir (opendir.c:247)
==4075==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4075==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4075==    by 0x108A78: dfsdirectory (in /home/alex/Desktop/main)
==4075==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4075== 
==4075== LEAK SUMMARY:
==4075==    definitely lost: 0 bytes in 0 blocks
==4075==    indirectly lost: 0 bytes in 0 blocks
==4075==      possibly lost: 0 bytes in 0 blocks
==4075==    still reachable: 65,632 bytes in 2 blocks
==4075==         suppressed: 0 bytes in 0 blocks
==4075== 
==4075== For counts of detected and suppressed errors, rerun with: -v
==4075== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==4076== 
==4076== HEAP SUMMARY:
==4076==     in use at exit: 65,632 bytes in 2 blocks
==4076==   total heap usage: 4 allocs, 2 frees, 131,264 bytes allocated
==4076== 
==4076== 32,816 bytes in 1 blocks are still reachable in loss record 1 of 2
==4076==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==4076==    by 0x4EEB813: __alloc_dir (opendir.c:247)
==4076==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4076==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4076==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4076== 
==4076== 32,816 bytes in 1 blocks are still reachable in loss record 2 of 2
==4076==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==4076==    by 0x4EEB813: __alloc_dir (opendir.c:247)
==4076==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4076==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4076==    by 0x108A78: dfsdirectory (in /home/alex/Desktop/main)
==4076==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4076== 
==4076== LEAK SUMMARY:
==4076==    definitely lost: 0 bytes in 0 blocks
==4076==    indirectly lost: 0 bytes in 0 blocks
==4076==      possibly lost: 0 bytes in 0 blocks
==4076==    still reachable: 65,632 bytes in 2 blocks
==4076==         suppressed: 0 bytes in 0 blocks
==4076== 
==4076== For counts of detected and suppressed errors, rerun with: -v
==4076== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==4074== 
==4074== HEAP SUMMARY:
==4074==     in use at exit: 32,816 bytes in 1 blocks
==4074==   total heap usage: 3 allocs, 2 frees, 98,448 bytes allocated
==4074== 
==4074== 32,816 bytes in 1 blocks are still reachable in loss record 1 of 1
==4074==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==4074==    by 0x4EEB813: __alloc_dir (opendir.c:247)
==4074==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4074==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4074==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4074== 
==4074== LEAK SUMMARY:
==4074==    definitely lost: 0 bytes in 0 blocks
==4074==    indirectly lost: 0 bytes in 0 blocks
==4074==      possibly lost: 0 bytes in 0 blocks
==4074==    still reachable: 32,816 bytes in 1 blocks
==4074==         suppressed: 0 bytes in 0 blocks
==4074== 
==4074== For counts of detected and suppressed errors, rerun with: -v
==4074== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==4073== 
==4073== HEAP SUMMARY:
==4073==     in use at exit: 0 bytes in 0 blocks
==4073==   total heap usage: 2 allocs, 2 frees, 65,632 bytes allocated
==4073== 
==4073== All heap blocks were freed -- no leaks are possible
==4073== 
==4073== For counts of detected and suppressed errors, rerun with: -v
==4073== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==4070== 
==4070== HEAP SUMMARY:
==4070==     in use at exit: 0 bytes in 0 blocks
==4070==   total heap usage: 1 allocs, 1 frees, 32,816 bytes allocated
==4070== 
==4070== All heap blocks were freed -- no leaks are possible
==4070== 
==4070== For counts of detected and suppressed errors, rerun with: -v
==4070== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Croolman
  • 1,103
  • 13
  • 40
reddawn
  • 11
  • 6
  • Please build your program with debug information enabled (add the `-g` flag when building with GCC or Clang). Then Valgrind will be able to add line-numbers to its output for your program as well, telling you exactly where the allocation happened. – Some programmer dude Mar 22 '19 at 10:30
  • 2
    On an unrelated note, symbols beginning with an underscore and followed by an upper-case letter (like for example `_PathN`) are reserved in all scopes. You should not define such symbols yourself. – Some programmer dude Mar 22 '19 at 10:33
  • I tryid gcc -o main main.c -g but same result on valgrind ?@Someprogrammerdude – reddawn Mar 22 '19 at 10:36
  • I din't claim it would change anything, only that Valgrind would then be able to tell you the line number in your code where it detected the leak. possibly making it easier for you to understand what's going on and how to solve it. – Some programmer dude Mar 22 '19 at 10:43
  • Yes I understand you but still I can't see line number on valgrind @Someprogrammerdude – reddawn Mar 22 '19 at 10:47

2 Answers2

4

This memory leak is related to the recursion. You do not close the directory handles further up the stack:

==4075==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4075==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4075==    by 0x108AE6: main (in /home/alex/Desktop/main)
==4075==    by 0x4EEB902: opendir_tail (opendir.c:145)
==4075==    by 0x108977: dfsdirectory (in /home/alex/Desktop/main)
==4075==    by 0x108A78: dfsdirectory (in /home/alex/Desktop/main)
==4075==    by 0x108AE6: main (in /home/alex/Desktop/main)

It is a leak of the still reachable kind, and these can be harmless, either because you call exit early (which applies here), or because they refer to data structures that are rooted in global variables. There is considerable disagreement among C developers whether these leaks need to be addressed, or whether it is acceptable to leave them in a program.

Please also note that the EINTR check for closedir is wrong with glibc. It introduces a double-free vulnerability in case of an EINTR failure.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • But I close every directory both child and parent process..Why this leak happend?@Florian Weimer – reddawn Mar 22 '19 at 10:51
  • It's due to the recursion. There are more directory handles on the call stack (the `dir` variable exists separately in each recursive invocation). – Florian Weimer Mar 22 '19 at 11:36
-1

I found the solution.Close the directory before recursive call and there is not any memory leak

reddawn
  • 11
  • 6
  • That’s exactly what @Florian Weimar told you, why not just mark his answer correct? – Gwyn Evans Mar 30 '19 at 09:39
  • there is no answer his post.Just causing the recursion.Where is the solution ? @GwynEvans – reddawn Mar 30 '19 at 09:50
  • Second sentence - “You do not close the directory handles further up the stack” seems pretty clear to me. Were you expecting him to provide actual source code for you? – Gwyn Evans Mar 30 '19 at 09:57
  • It's due to the recursion. There are more directory handles on the call stack (the dir variable exists separately in each recursive invocation). He know solution ? @GwynEvans – reddawn Mar 30 '19 at 10:04
  • Yes, he did, and also pointed out that it was due to calling the exit where you did as if your recursion had terminated by unwinding, rather than just calling exit() while a number of levels down, the trailing closedirs would have run. – Gwyn Evans Mar 30 '19 at 10:12
  • I'm sorry I did not understand.I changed the answer.As a result my problem solved.I have another problem with fifo can you help me ? https://stackoverflow.com/questions/55420089/named-pipe-fifo-does-not-work-with-fork?noredirect=1#comment97563002_55420089 @GwynEvans – reddawn Mar 30 '19 at 10:19