You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

strcpy栈溢出疑问:已分配足够内存为何仍报错?

Stack Smashing错误排查:模拟mkdir代码的问题分析

我在运行一段模拟mkdir命令的代码时遇到了**stack smashing(栈溢出)**错误,代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_NAME 12
#define MAX_DIR 10

struct Node {
    char name[MAX_NAME];
    struct Node *subdirs[MAX_DIR];
};

int mkdir(struct Node* root, char* path) {
   char current_path[MAX_NAME+1];
   strcpy(current_path, path);

   char *next_path = strchr(current_path+1, '/');
   char *token;

   if (!next_path) {
       int i = 0;
       while(i < MAX_DIR && root->subdirs[i]) ++i;
       token = strtok(path, "/");
       root->subdirs[i] = malloc(sizeof(struct Node)); 
       strcpy(root->subdirs[i]->name, current_path+1);
       return 1;
   }

   token = strtok(path, "/");

   while( token != NULL) {

      for(int i = 0; i < MAX_DIR; i++) {
          if (root->subdirs[i] && !strcmp(root->subdirs[i]->name, token))
              return mkdir(root->subdirs[i], next_path);
      }

      token = strtok(NULL, "/");
   }

   printf("not found\n");

   return 0;
}

int main() {
    char input1[] = "/test";
    char input2[] = "/test/bar";
    char input3[] = "/lib/bar";
    char input4[] = "/foo";
    char input5[] = "/test/bar/foaa";

    struct Node *root = malloc(sizeof(struct Node));

    mkdir(root, input1);
    mkdir(root, input2);
    mkdir(root, input5);

    return 0;
}

这段代码用于模拟mkdir命令:比如输入"/test/bar/foaa"时,若/test/和/test/bar/已存在,会在/test/bar/下创建foaa目录。

错误触发在这行代码:

strcpy(root->subdirs[i]->name, current_path+1);

我发现把MAX_NAME增大到15就能解决问题,但"foaa"(包含终止符\0仅5个字符)理论上完全能放进MAX_NAME=12的数组里,想知道我的假设或代码哪里出了问题?


问题根源

  1. current_path数组越界,直接破坏栈结构
    代码中current_path的大小是MAX_NAME+1=13,但传入的路径比如input5是"/test/bar/foaa",长度(含\0)是14,strcpy会把超出的字符写入current_path的栈内存之外,直接触发栈溢出检测。这是最核心的问题——你关注的是最终复制的目录名长度,却忽略了整个路径字符串复制到current_path时已经越界。

  2. strtok修改原始输入字符串,引发连锁错误
    strtok会将原始字符串中的分隔符替换为\0,而main里的input数组是栈上的局部变量。第一次调用mkdir修改input1后,后续调用传入的input2、input5可能已经被意外修改(栈内存被破坏后,相邻变量的值会错乱),导致后续字符串操作进一步越界,最终错误在strcpy行暴露出来。

  3. 未初始化的结构体成员
    malloc分配Node结构体后,subdirs数组是未初始化的野指针,while(i < MAX_DIR && root->subdirs[i]) ++i;可能会访问非法内存,加重栈损坏的不可预见性。


修复方案

  • 安全复制路径到current_path:用strncpy替代strcpy,确保不越界,同时手动添加终止符:
    strncpy(current_path, path, MAX_NAME);
    current_path[MAX_NAME] = '\0';
    
  • 避免修改原始输入:不要直接对main中的输入数组使用strtok,可以先复制一份到临时缓冲区再处理,或者使用线程安全的strtok_r。
  • 初始化结构体:malloc后用memset初始化整个结构体,避免野指针:
    struct Node *new_node = malloc(sizeof(struct Node));
    memset(new_node, 0, sizeof(struct Node));
    root->subdirs[i] = new_node;
    

内容的提问来源于stack exchange,提问作者Franks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:47:06