是什么使以下代码在某些Linux/GCC环境上失败?我声明一个结构,然后创建此结构的"实例"。问题在于一个数组,该数组应该容纳单独的字符串并可以重新算起。详细信息:
typedef struct {
char (*pointer)[256];
int used;
int size;
} Array;
Array *createArray(int start_size) {
Array *array = malloc(sizeof( *array));
array->used = 0;
array->size = start_size;
array->pointer = malloc(start_size * sizeof *array->pointer); // <--- here
return array;
}
使用非初始化值的线标记在下面的<--
(strcpy
(。 parse
功能append
s使用append
功能。
void append(Array *array, char* elem) {
if (array->used >= array->size) {
// expand table
array->pointer = realloc(array->pointer, array->size * 2 * sizeof *array->pointer);
array->size *= 2;
}
// append new arg
strcpy(array->pointer[array->used] , elem); // <-- here
array->used++;
}
Array *parse(char* command) {
// split command by space and store each arg in array
char *args_str;
Array *args_list = createArray(DEFAULT_SIZE); // expandable array holding arguments
args_str = strtok(command, " ");
append(args_list, args_str);
args_str = strtok(NULL, " ");
}
valgrind表明,由于使用非专业化值,上面标记为<--- here
的行上有一个错误,但是该代码在Valgrind内部效果很好,也可以:
CentOS Linux release 7.4.1708 (Core) 3.10.0-693.11.6.el7.x86_64, gcc version 4.8.5 20150623 (Red Hat 4.8.5-16)
Ubuntu 16.04.3 LTS 4.4.0-112-generic, gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.6)
但失败:
Linux kali 4.13.0-kali1-amd64, gcc version 7.2.0 (Debian 7.2.0-14)
首先输入程序后立即投掷SEGFAULT 11
,这是在编译过程后,它在每个环境上都可以编译确定。
根据Pablo评论,需要修复parse
逻辑并改进realloc
!如前所述,当malloc
或realloc
返回时检查NULL
。
这是您进一步改进的MCVE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_SIZE 256
typedef struct {
char (*pointer)[256];
int used;
int size;
} Array;
Array *createArray(int start_size) {
Array *array = malloc(sizeof(*array));
array->used = 0;
array->size = start_size;
array->pointer = malloc(start_size * sizeof * array->pointer); //
return array;
}
void append(Array *array, char* elem) {
if (array->used >= array->size) {
// expand table
array->pointer = realloc(array->pointer, array->size * 2 * sizeof * array->pointer);
array->size *= 2;
}
// append new arg
strcpy(array->pointer[array->used] , elem); // <-- here
array->used++;
}
Array *parse(char* command) {
// split command by space and store each arg in array
char *args_str;
Array *args_list = createArray(DEFAULT_SIZE); // expandable array holding arguments
args_str = strtok(command, " ");
append(args_list, args_str);
args_str = strtok(NULL, " ");
append(args_list, args_str);
return(args_list);
}
int main(void)
{
char str[] = { '1', '2', '3', ' ', '5', '6', '7', ' ', 0 };
Array *p = parse(str);
printf("%sn",p->pointer[0]);
printf("%sn",p->pointer[1]);
return 0;
}
输出:
123
567
我将从评论中引用自己:
在附录中,您应该声明char
(*tmp)[256];
并以这样的方式调用realloc:tmp = realloc(array->pointer, ...);
。然后,您检查
tmp == NULL
是否并处理错误情况,以及它不是NULL
,array->pointer = tmp;
。 如果源字符串ELEM超过255个字符长,则可能会溢出指针 这将导致不确定的行为。使用strncpy(array->pointer[array->used] , elem, sizeof *array->pointer[array->used]); array->pointer[array->used][sizeof(array->pointer[array->used]) - 1] = 0;
而不是。
您的append
功能有一个小问题,它不会返回任何事物。我将其修改为:
Array *parse(char* command) {
// split command by space and store each arg in array
char *args_str;
Array *args_list = createArray(DEFAULT_SIZE); // expandable array holding arguments
args_str = strtok(command, " ");
do {
append(args_list, args_str);
} while(args_str = strtok(NULL, " "));
return args_list;
}
我拿走了您的代码并修复了parse
功能,并从我的main
调用它功能。
int main(void)
{
Array *array;
char cmd[] = "ls -alh --color /tmp";
array = parse(cmd);
if(array == NULL)
return 0;
printf("Array->used: %d, array->size: %dn", array->used, array->size);
for(int i = 0; i < array->used; ++i)
puts(array->pointer[i]);
free(array->pointer);
free(array);
}
我得到的输出是:
==11553== Memcheck, a memory error detector
==11553== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11553== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11553== Command: ./a
==11553==
Array->used: 4, array->size: 10
ls
-alh
--color
/tmp
==11553==
==11553== HEAP SUMMARY:
==11553== in use at exit: 0 bytes in 0 blocks
==11553== total heap usage: 3 allocs, 3 frees, 3,600 bytes allocated
==11553==
==11553== All heap blocks were freed -- no leaks are possible
==11553==
==11553== For counts of detected and suppressed errors, rerun with: -v
==11553== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
代码正常工作,问题可能会发生,因为不确定parse
呼叫之前的行为。我将测试代码放在这里:https://ideone.com/9vyyyh
您可以在IDEONE上看到,代码也会产生正确的结果。