c++ system() raises ENOMEM

后端 未结 2 758
礼貌的吻别
礼貌的吻别 2021-01-28 23:27

This question is a M(not)WE of this question. I wrote a code that reproduces the error:

#include 
#include 
#include 

        
2条回答
  •  误落风尘
    2021-01-28 23:38

    The system() function works by first creating a new copy of the process with fork() or similar (in Linux, this ends up in the clone() system call, as you show) and then, in the child process, calling exec to create a shell running the desired command.

    The fork() call can fail if there is insufficient virtual memory for the new process (even though you intend to immediately replace it with a much smaller footprint, the kernel can't know that). Some systems allow you to trade the ability to fork large processes for reduced guarantees that page faults may fail, with copy-on-write (vfork()) or memory overcommit (/proc/sys/vm/overcommit_memory and /proc/sys/vm/overcommit_ratio).

    Note that the above applies equally to any library function that may create new processes - e.g. popen(). Though not exec(), as that replaces the process and doesn't clone it.

    If the provided mechanisms are inadequate for your use case, then you may need to implement your own system() replacement. I recommend starting a child process early on (before you allocate lots of memory) whose sole job is to accept NUL-separated command lines on stdin and report exit status on stdout.

    An outline of the latter solution in pseudo-code looks something like:

    int request_fd[2];
    int reply_fd[2];
    
    pipe(request_fd);
    pipe(reply_fd);
    
    if (fork()) {
        /* in parent */
        close(request_fd[0]);
        close(reply_fd[1]);
    } else {
        /* in child */
        close(request_fd[1]);
        close(reply_fd[0]);
        while (read(request_fd[0], command)) {
            int result = system(command);
            write(reply_fd[1], result);
        }
        exit();
    }
    
    // Important: don't allocate until after the fork()
    std::vector a(7e8,1);  // allocate a big chunk of memory
    
    int my_system_replacement(const char* command) {
        write(request_fd[1], command);
        read(reply_fd[0], result);
        return result;
    }
    

    You'll want to add appropriate error checks throughout, by reference to the man pages. And you might want to make it more object-oriented, and perhaps use iostreams for your read and write operations, etc.

提交回复
热议问题