我正在尝试用Linux编写一个程序,其中要执行的命令是作为命令行参数传递的。我写了一段代码,但它有时运行文件,有时不工作,我不知道问题是什么。
下面是我的代码:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
void main(int argc, char* argv[]){
char com[60];
int i;
for(i = 1 ; i < argc ; i++){
strcat(com, argv[i]);
strcat(com, " ");
}
system(com);
}发布于 2018-10-21 19:12:13
您的程序具有未定义的行为。
如果用户不传递任何参数,则永远不会进入循环,而您将进入
char com[60];
// ...
system(com);此时com的内容未初始化,因此对system的调用具有未定义的行为。
如果用户传递参数,则执行此操作
strcat(com, argv[i]);此时com的内容未初始化,因此对strcat的调用具有未定义的行为。
要解决此问题,请在循环之前将com设置为有效字符串:
char com[60];
com[0] = '\0';发布于 2018-10-21 19:36:52
这有时会使缓冲区溢出(非常糟糕),有时会出现引用错误,没有参数的情况下,缓冲区将无法初始化(=>未定义行为)。
当shell运行你的程序时,它会去掉字符串的引号并插入$-variables。要健壮地完成此转发,除了检查缓冲区溢出之外,还需要重新报价。对于一个短小的程序来说,这可能有点乏味。
更简单的方法是直接使用argv数组执行posix_spawn或fork/exec:
int status;
pid_t pid;
if (0>(pid=fork())) return -1;
if(0==pid){
execvp(argv[1],argv+1);
_exit(127);
}
while(0>(waitpid(pid,&status,0)))
if (EINTR==errno) continue; else abort(); /*shouldn't happen*/现在,真正的system()还会忽略父进程中的SIGINT/SIGQUIT,并在获取状态之前阻止父进程中的SIGCHLD。posix_spawnp也是首选。
要复制这一点,您可以从musl libc的system实现开始,然后修改它以创建一个
int my_system(char const *file, char *argv[i]);这将跳过shell (以及创建具有正确引号和缓冲区溢出检查的字符串的需要):
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <spawn.h>
#include <errno.h>
#include <pthread.h>
//extern char **__environ;
extern char **environ;
int my_system(char const *file, char *argv[])
{
pid_t pid;
sigset_t old, reset;
struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
int status = -1, ret;
posix_spawnattr_t attr;
//pthread_testcancel();
//if (!cmd) return 1;
sigaction(SIGINT, &sa, &oldint);
sigaction(SIGQUIT, &sa, &oldquit);
sigaddset(&sa.sa_mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sa.sa_mask, &old);
sigemptyset(&reset);
if (oldint.sa_handler != SIG_IGN) sigaddset(&reset, SIGINT);
if (oldquit.sa_handler != SIG_IGN) sigaddset(&reset, SIGQUIT);
posix_spawnattr_init(&attr);
posix_spawnattr_setsigmask(&attr, &old);
posix_spawnattr_setsigdefault(&attr, &reset);
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
#if 0
ret = posix_spawn(&pid, "/bin/sh", 0, &attr,
(char *[]){"sh", "-c", (char *)cmd, 0}, environ);
#else
ret = posix_spawnp(&pid, file, 0, &attr, argv, environ);
#endif
posix_spawnattr_destroy(&attr);
if (!ret) while (waitpid(pid, &status, 0)<0 && errno == EINTR);
sigaction(SIGINT, &oldint, NULL);
sigaction(SIGQUIT, &oldquit, NULL);
sigprocmask(SIG_SETMASK, &old, NULL);
if (ret) errno = ret;
return status;
}现在有了my_system,您就不需要报价了,只需用以下命令调用它
my_system(argv[1], argv+1);https://stackoverflow.com/questions/52914641
复制相似问题