我有以下代码在fork中执行无效命令。 以下代码在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);
}
用valgrind返回执行上面的代码:
$ 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)
注意:如果我使用有效命令执行代码&#34; ls&#34;而不是&#34; tawtaw&#34;然后valgring将不会返回内存泄漏。
我缺少什么?
答案 0 :(得分:2)
这是预期的。当execve()
无法执行命令时,它会将控制权返回给您的代码,而不是退出并永远不会从strdup()
释放内存。
当execve
成功时,将替换整个文件图像,并且没有任何内容保留在strdup()
分配的内存中。
答案 1 :(得分:1)
你不应该关心这个“泄漏”,因为这只是你的过程异常终止。当您只需打印错误消息并退出时,不应该小心地释放资源。操作系统将释放所有未完成的资源。
如果您出于某种原因仍然对此感到担心,请尝试将exit(0)
替换为return -1;
。在实际程序中,您永远不会使用exit
,而只能使用释放已分配资源的正常返回路径。在C ++中,使用RAII并在需要异常退出时抛出异常。这是你的程序转换为RAII风格:
#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;
}
}