字符串终止或悬挂指针?
String termination or dangling pointer?
从输出 foo �
你是否同意我的字符串终止问题?我写了一个自定义 shell 但是当我 运行 命令 echo foo
然后我得到一些看起来像悬空指针或未终止的字符串的垃圾 char
:
/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug/openshell
'PATH' is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin.
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $ ls
{ls}
19660: executing ls
CMakeCache.txt cmake_install.cmake openshell
CMakeFiles Makefile openshell.cbp
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $ echo foo
{echo} {foo}
19669: executing echo
foo �
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $
它在调试器或 Clion 分析中没有说明任何内容,但从输出中可以清楚地看出我没有终止字符串。你同意?我如何在 Clion 中调试它?如果我 运行 它在 gdb
中,那么不会出现任何有趣的东西。我想学习使用调试器,以便我可以在 运行 时间实际检查值。
更新
当我小心的时候,它确实在调试器中说了些什么。事实证明 a 没有终止一个论点:{"echo", "foo", 0x....}
应该是 {"echo", "foo", 0}
并且当我修复它时程序 运行 没有垃圾 char
就很好(那是0x2525252525...
)。
所以我稍微修改了一下代码:
static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command shellcommand[4];
char **argv;
int argc = 1;
bool pipe = false;
char *command[40];
char *cmd2[20] = {"cmd2", 0};
int numberofpipelines = 0;
unsigned long i3 = 0;
unsigned long i2 = 0;
unsigned long i1 = 0;
unsigned long n = 0;
char *string;
char *string1;
int maxgrep = 1;
cmd2[0] = NULL;
cmd2[1] = NULL;
cmd2[2] = NULL;
command[0] = NULL;
command[1] = NULL;
command[3] = NULL;
char *string2 = NULL;
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)){
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
makeArgs(cmd, &argc, (const char ***) &argv, pipe);
char a[20] = {0};
if (sscanf(cmd, "%*[^']'%[^']'", a) == 1) {
printf("<undefined>");
}
for (int i = 0; i < argc; i++) {
if (argv[i] != NULL && strstr(argv[i], "|")) {
numberofpipelines++;
char subbuff[40];
i1 = 0;
i2 = 0;
i3 = 0;
subbuff[0]='[=11=]';
string = strstr(argv[i], "|");
if (string != NULL) {
i3 = string - argv[i];
}
string1 = strstr(&argv[i][i3 + 2], "|");
if (string1 != NULL) {
i2 = string1 - argv[i3 + 1];
printf("i2: %lu", i2);
} else {
char *found3 = strstr(&argv[i][i3 + 1], " ");
if (found3 != NULL) {}
string2 = strstr(argv[1], "|");
if (string2 != NULL) {
i1 = string2 - argv[1];
}
n = strlen(argv[1]) - i1;
if (argc > 2) {
memcpy(subbuff, &argv[i][i3 + 1], n - 1);
subbuff[n - 1] = '[=11=]';
cmd2[0] = subbuff;
cmd2[1] = argv[argc - 1];
} else {
memcpy(subbuff, &argv[i][i3 + 1], n);
subbuff[n] = '[=11=]';
cmd2[0] = subbuff;
cmd2[1] = argv[argc - 1];
}
argc++;
argv[i + 1] = subbuff;
command[i] = "<undefined>";
argv[i + 2] = NULL;
maxgrep = i;
}
}
if (argv[i] != NULL) {
if (i < maxgrep) {
command[i] = argv[i];
command[i+1] = 0;
maxgrep++;
} else {
command[maxgrep] = argv[maxgrep];
}
}
if (argv[i] != NULL) {
char *p = strchr(argv[i], '|');
if (!p) {
/* deal with error: / not present" */;
} else {
*p = 0;
}
}
}
dump_argv((const char *) "d", argc, argv);
/* makeArgs(cmd, &argc, &argv, pipe);*/
/* command[2]= 0;*/
shellcommand[0].argv = command;
shellcommand[1].argv = cmd2;
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the program.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(numberofpipelines, shellcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
return WEXITSTATUS(status);
}
现在输出看起来更好了。
/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug/openshell
'PATH' is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin.
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $ echo foo
i rcommand {echo} {foo}
926: executing echo
foo
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $
检查输出前的字符串值。如果您使用 printf 并且只是一个 POD 字符数组,请确保最后一个字符是 '\0',并且它在它应该出现的位置(字符串被正确终止并且末尾没有垃圾)。如果您在 C++ 中使用 std::string,请确保它是使用正确的值构造的(与以前的规则相同)并让 C++ stdlib 处理输出和格式化。看来你最后有一些无法打印的数据。
从输出 foo �
你是否同意我的字符串终止问题?我写了一个自定义 shell 但是当我 运行 命令 echo foo
然后我得到一些看起来像悬空指针或未终止的字符串的垃圾 char
:
/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug/openshell
'PATH' is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin.
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $ ls
{ls}
19660: executing ls
CMakeCache.txt cmake_install.cmake openshell
CMakeFiles Makefile openshell.cbp
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $ echo foo
{echo} {foo}
19669: executing echo
foo �
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $
它在调试器或 Clion 分析中没有说明任何内容,但从输出中可以清楚地看出我没有终止字符串。你同意?我如何在 Clion 中调试它?如果我 运行 它在 gdb
中,那么不会出现任何有趣的东西。我想学习使用调试器,以便我可以在 运行 时间实际检查值。
更新
当我小心的时候,它确实在调试器中说了些什么。事实证明 a 没有终止一个论点:{"echo", "foo", 0x....}
应该是 {"echo", "foo", 0}
并且当我修复它时程序 运行 没有垃圾 char
就很好(那是0x2525252525...
)。
所以我稍微修改了一下代码:
static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command shellcommand[4];
char **argv;
int argc = 1;
bool pipe = false;
char *command[40];
char *cmd2[20] = {"cmd2", 0};
int numberofpipelines = 0;
unsigned long i3 = 0;
unsigned long i2 = 0;
unsigned long i1 = 0;
unsigned long n = 0;
char *string;
char *string1;
int maxgrep = 1;
cmd2[0] = NULL;
cmd2[1] = NULL;
cmd2[2] = NULL;
command[0] = NULL;
command[1] = NULL;
command[3] = NULL;
char *string2 = NULL;
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)){
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
makeArgs(cmd, &argc, (const char ***) &argv, pipe);
char a[20] = {0};
if (sscanf(cmd, "%*[^']'%[^']'", a) == 1) {
printf("<undefined>");
}
for (int i = 0; i < argc; i++) {
if (argv[i] != NULL && strstr(argv[i], "|")) {
numberofpipelines++;
char subbuff[40];
i1 = 0;
i2 = 0;
i3 = 0;
subbuff[0]='[=11=]';
string = strstr(argv[i], "|");
if (string != NULL) {
i3 = string - argv[i];
}
string1 = strstr(&argv[i][i3 + 2], "|");
if (string1 != NULL) {
i2 = string1 - argv[i3 + 1];
printf("i2: %lu", i2);
} else {
char *found3 = strstr(&argv[i][i3 + 1], " ");
if (found3 != NULL) {}
string2 = strstr(argv[1], "|");
if (string2 != NULL) {
i1 = string2 - argv[1];
}
n = strlen(argv[1]) - i1;
if (argc > 2) {
memcpy(subbuff, &argv[i][i3 + 1], n - 1);
subbuff[n - 1] = '[=11=]';
cmd2[0] = subbuff;
cmd2[1] = argv[argc - 1];
} else {
memcpy(subbuff, &argv[i][i3 + 1], n);
subbuff[n] = '[=11=]';
cmd2[0] = subbuff;
cmd2[1] = argv[argc - 1];
}
argc++;
argv[i + 1] = subbuff;
command[i] = "<undefined>";
argv[i + 2] = NULL;
maxgrep = i;
}
}
if (argv[i] != NULL) {
if (i < maxgrep) {
command[i] = argv[i];
command[i+1] = 0;
maxgrep++;
} else {
command[maxgrep] = argv[maxgrep];
}
}
if (argv[i] != NULL) {
char *p = strchr(argv[i], '|');
if (!p) {
/* deal with error: / not present" */;
} else {
*p = 0;
}
}
}
dump_argv((const char *) "d", argc, argv);
/* makeArgs(cmd, &argc, &argv, pipe);*/
/* command[2]= 0;*/
shellcommand[0].argv = command;
shellcommand[1].argv = cmd2;
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the program.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(numberofpipelines, shellcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
return WEXITSTATUS(status);
}
现在输出看起来更好了。
/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug/openshell
'PATH' is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin.
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $ echo foo
i rcommand {echo} {foo}
926: executing echo
foo
dac:/home/dac/.CLion2016.1/system/cmake/generated/openshell-69ebaaf9/69ebaaf9/Debug $
检查输出前的字符串值。如果您使用 printf 并且只是一个 POD 字符数组,请确保最后一个字符是 '\0',并且它在它应该出现的位置(字符串被正确终止并且末尾没有垃圾)。如果您在 C++ 中使用 std::string,请确保它是使用正确的值构造的(与以前的规则相同)并让 C++ stdlib 处理输出和格式化。看来你最后有一些无法打印的数据。