Find the answer to your Linux question:
Results 1 to 5 of 5
vfork() leaks parent process memory over a time I need help to understand does vfork() leaks memory or not. I am using uclinux with kernel version 2.6.30. In my application ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Sep 2013
    Location
    India
    Posts
    5

    vfork() leaks parent process memory over a time


    vfork() leaks parent process memory over a time

    I need help to understand does vfork() leaks memory or not.
    I am using uclinux with kernel version 2.6.30. In my application I used vfork() and execvp() command.
    I used this code for making child process:
    PHP Code:
    int execute(char **argv,char *log_file,int type)
    {
        
    pid_t pid = -1;
        
    int status 0;
        
    int err_out_fd 1;
        if ((
    pid vfork()) < 0)         /* fork a child process */
        
    {
            
    perror("ERROR : vfork call failed");
            
    syslog(2"ERROR : vfork call failed: %s\n",strerror(errno));

            return -
    1;
        }
        else if (
    pid == 0)         /* for the child process: */
        
    {
            if(
    != type)
            {
                if(
    == type)
                {
                    if(-
    == (err_out_fd open(log_fileO_CREAT O_TRUNC O_RDWR0666)))
                    {
                        
    perror("log file > create failed");
                        return -
    1;
                    }
                    else
                    {
                    }
                }
                else if(
    == type)
                {
                    if(-
    == (err_out_fd open(log_fileO_CREAT O_APPEND O_RDWR0666)))
                    {
                        
    perror("log file >> create failed");
                        return -
    1;
                    }
                }

                
    close(1);
                
    close(2);
                
    dup2(err_out_fd,1);
                
    dup2(err_out_fd,2);
                
    close(err_out_fd);
            }
            if(
    debug)
                
    printf("child:before usleep >>>>>>>\n");fflush(stdout);

            
    usleep(10000);
            if(
    debug)
                
    printf("child:after usleep >>>>>>\n");

            
    fflush(stdout);
            if (
    execvp(*argvargv) == -1)    /* execute the command  */
            
    {
                
    printf("sh:can't execute '%s': %s\n",argv[0],strerror(errno));
                
    syslog(2,"sh:can't execute '%s': %s\n",argv[0],strerror(errno));

                
    _exit(1);
            }

            
    _exit(1);
        }
        else
        {
            
    int chld_pid 0;
            
    status = -1;

            
    fflush(stdout);

            if(
    debug)
                
    printf("before waitpid call <<<<<<<<<<<<<\n");

            
    fflush(stdout);
            if ((
    chld_pid waitpid(pid, &status0)) == pid)
            {
                if (
    WIFEXITED(status))
                {
                    
    //if(debug)
                        
    printf("Parent process from caller, child %d : status %d <<<<<<<<<<<<<\n"chld_pid,  WEXITSTATUS(status));
                }
                else if(
    WIFSIGNALED(status))
                {
                    
    //if(debug)
                        
    printf("Parent process from caller, child %d : signal %d <<<<<<<<<<<<<\n"chld_pid,  WTERMSIG(status));
                }
                else if (
    WIFSTOPPED(status))
                {
                    
    //if(debug)
                        
    printf("Parent process from caller, child %d : signal %d  <<<<<<<<<<<<<\n"chld_pidWSTOPSIG(status));
                }
                else if (
    WIFCONTINUED(status))
                {
                    
    //if(debug)
                        
    printf("Parent process from caller, child %d : continued its execution   <<<<<<<<<<<<<\n"chld_pid);
                }
                else
                {
                    
    //if(debug)
                        
    printf("Parent process from caller, child %d : status %d   <<<<<<<<<<<<<\n"chld_pidstatus);
                }
            }
            else
            {
                
    //if(debug)
                    
    perror("Parent process waitpid fail   <<<<<<<<<<<<<\n");
            }

            if(
    debug)
                
    printf("Parent process after waitpid call   <<<<<<<<<<<<<\n");

            
    fflush(stdout);
        }

        
    //usleep(10000);

        
    return status;

    Instead of vfok() i changed to fork() then It stops leaking memory but as I know that fork() will create same resource copy of parent and in my application memory is not so big.
    Does anyone came across this fault before.
    Please help me.

    Parent process just calls "ARPING" using this function.
    Note: ARPING is busybox utility and it is call too frequently.After 15 days my memory full and then OOM killer kills process.
    I attached My code for your reference. Thanks in advance
    Attached Files Attached Files

  2. #2
    Linux Enthusiast
    Join Date
    Jan 2005
    Location
    Saint Paul, MN
    Posts
    620
    The "vfork" in Linux is only to be used to fork a child where it will only do an "execve" (execute an other program). This reduces the overhead of "creating a new process" that is a clone of the current process before switch to another process. The man page for "vfork" says:
    Code:
    vfork() is a special case of clone(2).  It is used to create  new processes
    without  copying the page tables of the parent process.  It may
    be useful in performance-sensitive applications where a child  is
    created which then immediately issues an execve(2).

  3. #3
    Just Joined!
    Join Date
    Sep 2013
    Location
    India
    Posts
    5
    To alf55,
    The "vfork" in Linux is only to be used to fork a child where it will only do an "execve" (execute an other program). This reduces the overhead of "creating a new process" that is a clone of the current process before switch to another process. The man page for "vfork" says:
    Code:

    vfork() is a special case of clone(2). It is used to create new processes
    without copying the page tables of the parent process. It may
    be useful in performance-sensitive applications where a child is
    created which then immediately issues an execve(2).
    you mean to say that i should not use execvp with vfork() this might create memory leak???

    Can any one explain me why i should not use execvp() with vfork() and it is acceptable to use execve() with vfork()??

    I found something might related to this post ..
    Here is the link :: https://bugzilla.redhat.com/show_bug.cgi?id=221187
    In that they told something with execvp problem but i didn't understand that much?

    Description of problem:
    When execvp() does pathname expansion on the first argument (the executable), it
    doesn't clean up and when called in a vfork() context (where memory is shared
    initially) causes a leak in the parent.

    Actual results:
    each vfork leaves an unreferenced copy of the first arg to execvp() after
    pathname expansion in the parent's memory space.

  4. #4
    Linux Enthusiast
    Join Date
    Jan 2005
    Location
    Saint Paul, MN
    Posts
    620
    Read the man page for vfork. It states:
    Code:
    VFORK(2)                   Linux Programmer's Manual                  VFORK(2)
    
    NAME
           vfork - create a child process and block parent
    
    SYNOPSIS
           #include <sys/types.h>
           #include <unistd.h>
    
           pid_t vfork(void);
    
       Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
    
           vfork():
               Since glibc 2.12:
                   _BSD_SOURCE ||
                       (_XOPEN_SOURCE >= 500 ||
                           _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) &&
                       !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
               Before glibc 2.12:
                   _BSD_SOURCE || _XOPEN_SOURCE >= 500 ||
                   _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
    
    DESCRIPTION
       Standard description
           (From POSIX.1) The vfork() function has the  same  effect  as  fork(2),
           except that the behavior is undefined if the process created by vfork()
           either modifies any data other than a variable of type  pid_t  used  to
           store  the  return  value from vfork(), or returns from the function in
           which vfork() was called, or calls any other function  before  success‐
           fully calling _exit(2) or one of the exec(3) family of functions.
    
       Linux description
           vfork(),  just  like  fork(2),  creates  a child process of the calling
           process.  For details and return value and errors, see fork(2).
    
           vfork() is a special case of clone(2).  It is used to create  new  pro‐
           cesses  without  copying the page tables of the parent process.  It may
           be useful in performance-sensitive applications where a child  is  cre‐
           ated which then immediately issues an execve(2).
    
           vfork()  differs  from  fork(2) in that the calling thread is suspended
           until the child terminates (either normally, by  calling  _exit(2),  or
           abnormally,  after  delivery  of a fatal signal), or it makes a call to
           execve(2).  Until that point, the child shares all memory with its par‐
           ent,  including  the stack.  The child must not return from the current
           function or call exit(3), but may call _exit(2).
    
           As with fork(2), the child process created by vfork()  inherits  copies
           of  various of the caller's process attributes (e.g., file descriptors,
           signal dispositions, and current working directory); the  vfork()  call
           differs  only  in  the  treatment  of  the  virtual  address  space, as
           described above.
    
           Signals sent to the parent arrive after the child releases the parent's
           memory (i.e., after the child terminates or calls execve(2)).
    
       Historic description
           Under  Linux,  fork(2) is implemented using copy-on-write pages, so the
           only penalty incurred by fork(2) is the time  and  memory  required  to
           duplicate  the parent's page tables, and to create a unique task struc‐
           ture for the child.  However, in the  bad  old  days  a  fork(2)  would
           require  making a complete copy of the caller's data space, often need‐
           lessly, since usually immediately afterward an exec(3) is done.   Thus,
           for  greater  efficiency, BSD introduced the vfork() system call, which
           did not fully copy the address space of the parent  process,  but  bor‐
           rowed  the  parent's  memory  and  thread  of  control  until a call to
           execve(2) or an exit occurred.  The parent process was suspended  while
           the  child was using its resources.  The use of vfork() was tricky: for
           example, not modifying data in the parent process depended  on  knowing
           which variables were held in a register.
    
    CONFORMING TO
           4.3BSD;  POSIX.1-2001  (but marked OBSOLETE).  POSIX.1-2008 removes the
           specification of vfork().
    
           The requirements put on vfork() by the standards are weaker than  those
           put  on  fork(2),  so an implementation where the two are synonymous is
           compliant.  In particular, the programmer cannot  rely  on  the  parent
           remaining blocked until the child either terminates or calls execve(2),
           and cannot rely on any specific behavior with respect to shared memory.
    
    NOTES
           Some consider the semantics of vfork() to be an architectural  blemish,
           and  the  4.2BSD  man page stated: "This system call will be eliminated
           when proper system sharing mechanisms are  implemented.   Users  should
           not  depend  on  the memory sharing semantics of vfork() as it will, in
           that case, be made synonymous to fork(2)."  However, even though modern
           memory  management  hardware  has  decreased the performance difference
           between fork(2) and vfork(), there are various reasons  why  Linux  and
           other systems have retained vfork():
    
           *  Some performance-critical applications require the small performance
              advantage conferred by vfork().
    
           *  vfork() can be implemented on systems that lack a  memory-management
              unit  (MMU),  but  fork(2)  can't  be  implemented  on such systems.
              (POSIX.1-2008 removed vfork() from the standard; the POSIX rationale
              for the posix_spawn(3) function notes that that function, which pro‐
              vides functionality equivalent to fork(2)+exec(3), is designed to be
              implementable on systems that lack an MMU.)
    
       Linux notes
           Fork handlers established using pthread_atfork(3) are not called when a
           multithreaded  program  employing  the  NPTL  threading  library  calls
           vfork().   Fork handlers are called in this case in a program using the
           LinuxThreads threading library.  (See pthreads(7) for a description  of
           Linux threading libraries.)
    
           A  call  to vfork() is equivalent to calling clone(2) with flags speci‐
           fied as:
    
                CLONE_VM | CLONE_VFORK | SIGCHLD
    
       History
           The vfork() system call appeared in 3.0BSD.  In 4.4BSD it was made syn‐
           onymous    to   fork(2)   but   NetBSD   introduced   it   again,   cf.
           ⟨http://www.netbsd.org/Documentation/kernel/vfork.html⟩.  In Linux,  it
           has   been  equivalent  to  fork(2)  until  2.2.0-pre6  or  so.   Since
           2.2.0-pre9 (on i386, somewhat later on other architectures)  it  is  an
           independent system call.  Support was added in glibc 2.0.112.
    
    BUGS
           Details  of the signal handling are obscure and differ between systems.
           The BSD man page states: "To avoid a possible deadlock situation,  pro‐
           cesses  that  are  children  in  the middle of a vfork() are never sent
           SIGTTOU or SIGTTIN signals; rather, output or ioctls  are  allowed  and
           input attempts result in an end-of-file indication."
    
    SEE ALSO
           clone(2), execve(2), fork(2), unshare(2), wait(2)
    
    COLOPHON
           This  page  is  part of release 3.51 of the Linux man-pages project.  A
           description of the project, and information about reporting  bugs,  can
           be found at http://www.kernel.org/doc/man-pages/.
    
    Linux                             2012-08-05                          VFORK(2)

  5. #5
    Just Joined!
    Join Date
    Sep 2013
    Location
    India
    Posts
    5

    Found alternate way to use execvp with vfork

    • Till now, I am passing only "arping -I bond0 172.16.0.40 -c 1 -w 1 -q -f" command to execvp().
    • Upon execution of this command, execvp() searches for arping binary with reference of environment variables of PSCM Linux system and updates its argument path.
    • Instead of passing only binary name as arping to the execvp(), I passed absolute path of arping binary as "/usr/bin/arping -I bond0 172.16.0.40 -c 1 -w 1 -q -f". With this change, I am not seeing any memory leak behavior parent process.


    I reviewed code of execvp() of glibc-2.5 and found this difference in code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •