繁体   English   中英

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 );

因为指针arg1arg2指向的字符串在 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;
}

问题

  1. 不为null 字符分配空间。 关闭 1。

  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM