【问题标题】:Do I risk a buffer overrun here and how would I avoid it?我是否冒着缓冲区溢出的风险,我将如何避免它?
【发布时间】:2018-12-08 10:39:36
【问题描述】:

我实现了一个简单的列表结构,其中单个列表元素由以下结构定义:

struct list_elem {
    struct list_elem *next;  // ptr to the next element
    char             *data;  // ptr to data
};

现在,我想做以下事情:

struct list_elem *elem;
int main() {
    elem->data = "some_string";
    strcat(elem->data, "another_string");
}

我担心会溢出,因为 strcat 的手册页指出:

char *strcat(char *dest, const char *src) 函数将src 字符串附加到dest 字符串,覆盖dest 末尾的终止空字节('\0'),然后添加终止空字节。字符串不能重叠,dest 字符串必须有足够的空间用于结果。 如果dest 不够大,程序行为不可预测;缓冲区溢出是攻击安全程序的常用途径。

基本上我不知道为我的列表元素分配了多少内存。

【问题讨论】:

  • 有办法知道分配了多少字节,前提是datamalloc的结果:stackoverflow.com/a/1281720/6451573
  • 对于您的列表元素:未分配内存。 elemNULL。对于您的字符串:分配了 12 个字节 ('s', 'o', 'm', 'e', '_', 's', 't', 'r', 'i', 'n', 'g', '\0')。

标签: c string c-strings string-literals


【解决方案1】:

此声明:

elem->data = "some_string";

使data 指针指向字符串文字"some_string"
在这里:

strcat(elem->data, "another_string");

您正在尝试将字符串文字 "another_string" 复制到指向另一个字符串文字的指针。根据标准,尝试修改字符串文字会导致未定义的行为,因为它可能存储在只读存储中。

你应该给data分配内存,像这样:

elem->data = calloc(50, 1); // sizeof (char) is 1

然后将"some_string"复制到其中;

strcpy (elem->data, "some_string");

然后将"another_string" 连接到它:

strcat (elem->data, "another_string");

或者,您也可以使用snprintf()

snprintf (elem->data, 49, "%s%s", "some_string", "another_string");

编辑:

感谢@alk 指出这一点。

elem 指针未指向有效内存。 你应该先给struct list_elem指针elem分配内存,像这样:

elem = malloc (sizeof (struct list_elem));
if (elem == NULL)
    exit(EXIT_FAILURE);

【讨论】:

  • 请注意,根据 OP 的代码 elem 未指向有效内存。
【解决方案2】:

您可以搜索 astrxxx 函数(不是标准的 C 函数)。它们在操作时动态分配内存。 Github example implementations

  • astrcat 上面实现了。
  • asprintf 是 sprintf 的动态版本。
  • 一些 GNU 编译器提供了更多功能

注意:你应该释放动态分配的内存!!

另外,你应该这样使用它:

struct list_elem elem;    //removed *, as it can cause seg fault if not initialized. you have to initialize by using struct list_elem * elem=malloc(sizeof(struct list_elem)); or something.
int main() {
    elem.data = strdup("some_string");//you must free data later
    astrcat(&elem.data, "another_string");
    //use it
    free(elem.data);
}

首先,struct list_elem* elem 被初始化为NULL,所以它必须在-> 语句之前使用有效地址进行初始化。 可以将数据段的指针赋值给data,不能正常修改。

【讨论】:

  • 他不需要在结构中使用字符数组。空间可以在连接本身上分配
  • @mangusta: "空间可以在连接本身上分配" 请问你到底想表达什么?
  • 请注意astrcat()aprintf()不是标准C,strdup()也不是。
  • "struct list_elem* elem 未初始化" 它是一个全局变量,它被初始化为 NULL,实际上并没有多大帮助。
猜你喜欢
  • 2021-09-19
  • 2021-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
  • 1970-01-01
相关资源
最近更新 更多