自定义strncat()函数触发Stack smashing detected错误的原因及修复
自定义_strncat函数栈溢出错误的原因与修复
我编写的代码旨在复刻strncat()函数的功能,代码能输出预期结果,但始终会出现“Stack smashing detected (Aborted Core Dump)”错误,需排查错误原因并找到修复方法。
代码文件
main.h
#ifndef MAIN_H #define MAIN_H #include <stdio.h> #include <string.h> int _putchar(char c); char *_strcat(char *dest, char *src); char *_strncat(char *dest, char *src, int n); #endif
1-main.c
#include "main.h" #include <stdio.h> /** * main - check the code * * Return: Always 0. */ int main(void) { char s1[98] = "Hello "; char s2[] = "World!\n"; char *ptr; printf("%s\n", s1); printf("%s", s2); ptr = _strncat(s1, s2, 1); printf("%s\n", s1); printf("%s", s2); printf("%s\n", ptr); ptr = _strncat(s1, s2, 1024); printf("%s", s1); printf("%s", s2); printf("%s", ptr); return (0); }
1-strncat.c(原错误实现)
#include "main.h" /** * _strncat - Concatenates strings * @dest: destination string * @src: source string * @n: Max bytes * Return: dest */ char *_strncat(char *dest, char *src, int n) { int srclen = 0; int destlen = 0; int i = 0; int j = 0; while (src[srclen] != '\0') { srclen++; } while (dest[destlen] != '\0') { destlen++; } for (i = destlen; (i < (destlen + n) && j < n); i++) { dest[i] = src[j]; j++; } dest[destlen + n] = '\0'; return (dest); }
错误原因分析
终止符写入越界:
代码最后一行dest[destlen + n] = '\0';是核心问题。无论src实际有多少字符,也不管dest剩余空间是否足够,直接在destlen + n位置写入终止符。比如main函数中第二次调用_strncat时传入n=1024,此时destlen加上1024远远超过s1数组的98字节容量,直接破坏栈内存,触发栈溢出检测。循环未处理
src提前结束的情况:
原循环条件只限制了拷贝次数不超过n,但没有判断src[j]是否已到字符串结束符'\0'。如果src长度小于n,代码仍会尝试拷贝n个字符,可能读取src数组外的未知内存,同时后续写入终止符的位置也会错误。冗余的长度计算:
提前计算srclen完全没必要,既浪费性能,也没用到这个值做有效判断。
修复方法及代码
针对上述问题,修改后的_strncat实现如下:
#include "main.h" /** * _strncat - Concatenates strings * @dest: destination string * @src: source string * @n: Max bytes to copy from src * Return: Pointer to dest */ char *_strncat(char *dest, char *src, int n) { int dest_len = 0; int copy_count = 0; // 定位dest的末尾 while (dest[dest_len] != '\0') { dest_len++; } // 最多拷贝n个字符,直到src结束 while (copy_count < n && src[copy_count] != '\0') { dest[dest_len + copy_count] = src[copy_count]; copy_count++; } // 在实际拷贝的字符末尾添加终止符 dest[dest_len + copy_count] = '\0'; return dest; }
修复要点说明
- 移除冗余的
srclen计算,改为在循环中实时判断src是否到达结束符,避免无效计算和内存越界读取。 - 终止符写入位置改为
dest_len + copy_count,即实际拷贝字符的下一位,确保不会超出dest的有效范围(只要调用者保证dest有足够空间,比如main中的s1[98])。 - 使用更简洁的
while循环替代for循环,逻辑更清晰,同时覆盖了src长度小于n的场景。
内容的提问来源于stack exchange,提问作者Akintola Oluwaseyi Alex
相关产品推荐
相关产品推荐

