问题
I have the following code which execute a non valid command within a fork. The following code return a memory leak in valgrind.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
int external_cmd(char **argv)
{
int pid;
if ((pid = fork()) == -1)
return -1;
if (pid == 0) {
/* child */
execvp(argv[0], argv);
exit(0);
} else if (pid < 0)
return -1;
int status;
while (wait(&status) != pid);
return 0;
}
int main ()
{
char *argv[8] = {0};
argv[0] = "tawtaw"; //<--------- invalid command
argv[1] = "-a";
char *mem = strdup("anychar");
/* fork call */
external_cmd(argv);
free(mem);
return(0);
}
executing the above code with valgrind return:
$ valgrind --leak-check=full --show-leak-kinds=all ./test
==11573== Memcheck, a memory error detector
==11573== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==11573== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==11573== Command: ./test
==11573==
==11574==
==11574== HEAP SUMMARY:
==11574== in use at exit: 8 bytes in 1 blocks
==11574== total heap usage: 1 allocs, 0 frees, 8 bytes allocated
==11574==
==11574== 8 bytes in 1 blocks are still reachable in loss record 1 of 1
==11574== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11574== by 0x4EBF729: strdup (strdup.c:42)
==11574== by 0x400747: main (in /home/mohamed/Desktop/tech/test/test)
==11574==
==11574== LEAK SUMMARY:
==11574== definitely lost: 0 bytes in 0 blocks
==11574== indirectly lost: 0 bytes in 0 blocks
==11574== possibly lost: 0 bytes in 0 blocks
==11574== still reachable: 8 bytes in 1 blocks
==11574== suppressed: 0 bytes in 0 blocks
==11574==
==11574== For counts of detected and suppressed errors, rerun with: -v
==11574== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==11573==
==11573== HEAP SUMMARY:
==11573== in use at exit: 0 bytes in 0 blocks
==11573== total heap usage: 1 allocs, 1 frees, 8 bytes allocated
==11573==
==11573== All heap blocks were freed -- no leaks are possible
==11573==
==11573== For counts of detected and suppressed errors, rerun with: -v
==11573== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
NOTE: If I execute the code with a valid command "ls" in stead of "tawtaw" then valgring will not return memory leak.
What I m missing ?
回答1:
That is expected. When execve()
can't execute command, it returns control to your code, and than you exit and never free memory from strdup()
.
When execve
succeeds, the whole file image is replaced, and nothing remains of the memory allocated with strdup()
.
回答2:
You shouldn't care about this "leak", because it's just your process terminating abnormally. You are not expected to carefully free your resources when you need to just print an error message and exit. The OS will free all outstanding resources.
If you are still concerned about this for some reason, try replacing exit(0)
with return -1;
. In a real program you would never use exit
, but only normal return paths that free allocated resources. In C++, use RAII and throw an exception when you need to exit abnormally. Here is your program converted to RAII style:
#include <cstdlib>
#include <cstdarg>
#include <cerrno>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// This function should be standard in some kind of POSIX C++ library
void execvp(const std::string& program, const std::vector<std::string>& args)
{
std::vector<const char*> real_argv(args.size()+1);
for (const std::string& s : args)
real_argv.push_back(s.c_str());
real_argv.push_back(nullptr);
// have to use const_cast because of the broken const model of C
execvp(program.c_str(), const_cast<char**>(real_argv.data()));
throw std::runtime_error((std::string("Could not execvp ") + args[0]).c_str());
}
int external_cmd(const std::string& program, const std::vector<std::string>& args)
{
int pid;
if ((pid = fork()) == -1)
return -1;
if (pid == 0) {
/* child */
execvp(program, args);
} else if (pid < 0)
return -1;
int status;
while (wait(&status) != pid);
return 0;
}
int main ()
{
try {
std::vector<std::string> args;
args.push_back("tawtaw");
args.push_back("-a");
std::string s("12345678"); // RAII
/* fork call */
external_cmd(args[0], args);
return EXIT_SUCCESS;
} catch (std::exception& e) {
std::cerr << e.what() << ". Exiting.\n";
return EXIT_FAILURE;
} catch ( ... ) {
std::cerr << "Unexpected error. OS message is: " << strerror(errno) << ". Exiting.\n";
return EXIT_FAILURE;
}
}
来源:https://stackoverflow.com/questions/41126905/fork-with-invalid-command-cause-a-memory-leak-in-valgrind