ft_substr函数传入负整数start参数引发段错误的求助
ft_substr传入负数start参数导致段错误的修复方案
问题代码
char *ft_substr(char const *s, unsigned int start, size_t len) { char *substr; if (!s) return (NULL); if (start > ft_strlen(s)) len = 0; if (start <= ft_strlen(s) && s[start] != '\0') { if (ft_strlen(s + start) < len) len = ft_strlen(s + start); } substr = (char *)malloc(sizeof(*s) * (len + 1)); if (!substr) return (NULL); if (len == 0) return (substr); ft_strlcpy(substr, s + start, len + 1); return (substr); }
注:ft_strlen等为自定义实现的对应标准库函数。
问题分析
传入-1作为start参数时,会被隐式转换为32位无符号整数4294967295。虽然代码里有start > ft_strlen(s)的判断会把len设为0,但第二个if的条件start <= ft_strlen(s) && s[start] != '\0'可能被编译器优化,导致s[start]被提前访问——即使start <= ft_strlen(s)不成立,也会触发非法内存访问,从而在Ubuntu 22.04上引发段错误(Mac上编译器优化策略不同,未触发该问题)。
另外,原代码未处理start等于字符串长度的情况,此时s[start]是'\0',子串应为空,但原代码可能保留原len值,存在潜在风险。
修复后的代码
char *ft_substr(char const *s, unsigned int start, size_t len) { char *substr; size_t s_len; if (!s) return (NULL); s_len = ft_strlen(s); // 覆盖start等于或超过字符串长度的所有情况(包括超大无符号数) if (start >= s_len) len = 0; else if (s[start] != '\0') { if (ft_strlen(s + start) < len) len = ft_strlen(s + start); } substr = (char *)malloc(sizeof(*s) * (len + 1)); if (!substr) return (NULL); if (len == 0) { *substr = '\0'; // 显式初始化空字符串,避免返回未初始化内存 return (substr); } ft_strlcpy(substr, s + start, len + 1); return (substr); }
修复要点
- 提前计算并缓存字符串长度
s_len,避免重复调用ft_strlen,同时确保判断逻辑的一致性。 - 将
start > s_len改为start >= s_len,覆盖start刚好等于字符串长度的场景,统一将len设为0。 - 用
else if替代原有的独立if,确保只有当start < s_len时才会访问s[start],彻底避免非法内存访问。 - 当
len为0时,显式将返回的指针指向的内存初始化为'\0',保证返回的是空字符串而非未初始化内存,符合预期行为。
这样修改后,无论传入多大的无符号start值,都不会触发非法内存访问,在Ubuntu和Mac上均可稳定运行。
内容的提问来源于stack exchange,提问作者user21073092
相关产品推荐
相关产品推荐

