![](/img/trans.png)
[英]Warning : call to __builtin___strncat_chk might overflow destination buffer [enabled by default] In function ‘strncat’
[英]strncat causes buffer overflow
如何将strncat
与堆对象一起使用?
我正在尝试编写一个简单的 function 将 2 个字符串连接在一起返回结果,但是,如果不使返回缓冲区非常大(在其长度上增加大约 5000)以使其不会溢出,我将无法运行它。
我可能只是使用strncat
function 错误地使用堆对象而不是固定长度的字符 arrays 。 但我不知道我会怎么写它。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *concatStrings(char *arg1, char *arg2) {
char *ret = malloc(strlen(arg1) + strlen(arg2));
strncpy(ret, arg1, strlen(arg1));
strncat(ret, arg2, strlen(arg2));
ret[strlen(arg1)+strlen(arg2)] = '\0';
return ret;
}
int main(int argc, char *argv[]) {
if (argc == 3) {
char *print = concatStrings(argv[1], argv[2]);
printf("\n%s", print);
free(print);
}
return 0;
}
第一个问题是,您没有分配足够的 memory,因为在 C 中,字符串以0-byte
结尾,所以它应该是
char *ret = malloc((strlen(arg1) + strlen(arg2))+1);
当然,您应该检查 malloc 是否有效。
if (!ret)
// error
第二个问题是,您在此处使用带有硬编码长度的strncpy
。 只需使用strcpy
,因为您已经分配了足够的 memory。 出于同样的原因,您也可以使用strcat
。 strncat
没有提供任何额外的好处,实际上使代码变慢,因为您再次调用strlen
。
这个
ret[10 + strlen(arg2)] = '\0';
根本不需要。 事实上,如果 arg1 少于 10 个字符,它可能会很危险。
对于初学者, function 应声明为
char * concatStrings( const char* arg1, const char* arg2 );
因为指针arg1
和arg2
指向的字符串在 function 中没有改变。
在此 memory 分配
char *ret = malloc(strlen(arg1) + strlen(arg2));
您忘记为 null 终止字符'\0'
保留 memory 。 你必须写
char *ret = malloc( strlen(arg1) + strlen(arg2) + 1 );
在此调用中使用幻数 10
strncpy(ret,arg1,10);
没有意义。
相反,如果你会写例如
strncpy(ret,arg1,strlen(arg1));
然后下一个电话
strncat(ret,arg2,strlen(arg2));
将调用未定义的行为,因为调用strncpy
没有 append null 终止字符 '\0' 指向指针ret
指向的字符串。
至少写一下会好得多
strcpy( ret, arg1 );
无论如何,您的 function 实施效率低下。 例如有两次调用 function strlen
为参数 arg2
char *ret = malloc(strlen(arg1) + strlen(arg2));
//...
strncat(ret,arg2,strlen(arg2));
另外strncat
的调用效率也很低,因为 function 需要遍历整个目标字符串以找到其终止零。
function 可以通过以下方式定义
char * concatStrings( const char* arg1, const char* arg2 )
{
size_t n1 = strlen( arg1 );
char *ret = malloc( n1 + strlen( arg2 ) + 1 );
if ( ret != NULL )
{
strcpy( ret, arg1 );
strcpy( ret + n1, arg2 );
}
return ret;
}
这是一个演示程序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatStrings( const char* arg1, const char* arg2 )
{
size_t n1 = strlen( arg1 );
char *ret = malloc( n1 + strlen( arg2 ) + 1 );
if ( ret != NULL )
{
strcpy( ret, arg1 );
strcpy( ret + n1, arg2 );
}
return ret;
}
int main(void)
{
const char *argv1 = "Hello ";
const char *argv2 = "World!";
char *print = concatStrings( argv1, argv2 );
if ( print != NULL ) puts( print );
free( print );
return 0;
}
程序 output 是
Hello World!
在 function 中用第一次调用strcpy
代替memcpy
会更好。 也就是说 function 也可以看起来像
char * concatStrings( const char* arg1, const char* arg2 )
{
size_t n1 = strlen( arg1 );
char *ret = malloc( n1 + strlen( arg2 ) + 1 );
if ( ret != NULL )
{
memcpy( ret, arg1, n1 );
strcpy( ret + n1, arg2 );
}
return ret;
}
我忘记了snprintf
存在,并认为我必须使用strcpy
strcat
或其他字符串或 memory 管理 function 来执行此操作
char* concatStrings(char* arg1, char*arg2){
size_t n1 = strlen(arg1), n2 = strlen(arg2);
char *ret = malloc(n1 + n2 + 1);
snprintf(ret,n1 + n2 + 1, "%s%s", arg1, arg2);
return ret;
}
问题
不为null 字符分配空间。 关闭 1。
strncpy(ret, arg1, strlen(arg1))
不会null 字符终止ret
,因此下一个strncat(ret,...
是未定义的行为,因为ret
需要指向一个string 。
一些替代方案:
// Via sprintf
// Good compilers will emit efficient code
// and not perform the usual parsing overhead of *printf format at run time
char *concatStrings_alt1(const char *arg1, const char *arg2) {
char *ret = malloc(strlen(arg1) + strlen(arg2) + 1);
sprintf(ret, "%s%s", arg1, arg2);
return ret;
}
// Via memcpy
char *concatStrings_alt2(const char *arg1, const char *arg2) {
size_t len1 = strlen(arg1);
size_t size2 = strlen(arg2) + 1;
char *ret = malloc(len1 + size2);
memcpy(ret, arg1, len1);
memcpy(ret + len1, arg2, size2);
return ret;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.