簡體   English   中英

為什么在執行memcpy時會檢測到堆棧粉碎?

[英]Why am I getting stack smashing detected when doing memcpy?

    char test[]={"abcde"};
    char* test1={"xyz"};
    memcpy(test+5,test1,3);
    printf("%s",test);

我試圖了解memcpy的工作原理,這是我到目前為止編寫的示例。 這將輸出作為abcdexyz&vjunkcharacters

和以下消息。

*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]

這種情況背后的原因是什么?

根本原因:

char test[]={"abcde"};

分配足夠的內存空間以僅存儲5字符。

memcpy(test+5,test1,3);  

test1指向的數據復制到分配的內存空間之外。
從技術上講,以這種方式寫超出已分配內存的邊界是Undefined Behavior ,這意味着可能發生任何事情。

實際發生了什么?

實際發生的是memcpy字符復制到分配的內存之外,從而覆蓋了NULL終止符,該終止符標志着字符數組test結束。
此外, printftest起始地址讀取內容,直到遇到隨機NULL從而打印出垃圾字符。

解:
在執行memcpy之前,應確保目標緩沖區已分配足夠的內存。 由於您打算復制3字符,因此目標緩沖區test應至少:

5 + 3 + 1 byte for NULL terminator = 9 bytes

您可以簡單地使用:

char test[9]="abcde";

您的memcpy調用確實粉碎了堆棧,這就是為什么您看到該消息的原因。 您正在復制test數組末尾的數據,這是不允許的。

無需額外的緩沖

實際上,最直接的方法是避免復制:

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

int main() {
  char a[] = "abcde";
  char b[] = "xyz";
  printf("%s%s\n", a, b);
  return 0;
}

用memcpy做

memcpy將src n個字節復制到dest 您需要自己正確跟蹤復制字符串的空終止字節。

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

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  memcpy(c, a, sizeof(a));

  /* copy the content of b to where a ends (concatenate the strings) */
  memcpy(c + sizeof(a) - 1, b, sizeof(b));

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

用strcpy和strcat來做

請注意,使用memcpy時,有很多陷阱可以正確處理字符串的空終止。 為了簡化字符串的此過程,您應該執行以下操作。

如果這些確實是字符串而不是隨機字節,則應使用標准庫的字符串函數。 這是完成的方式。

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

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  strcpy(c, a);

  /* copy the content of b to where a ends (concatenate the strings) */
  strcat(c, b);

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

知道琴弦的大小

關於知道緩沖區的大小,請注意,通常不能簡單地執行sizeof(a_string) 如果將字符數組傳遞給函數,則它會衰減為指針,並且此操作不再返回數組的預期大小,而是返回指針的大小。

對於字符串,您需要發出strlen(a_string)來掃描空終止符的出現並返回字符串的長度(不包括終止符)。

對於包含隨機數據的字符緩沖區(或需要寫入的空緩沖區),此方法也不起作用。 您始終需要將緩沖區的大小作為附加參數傳遞。

memcpy(test+5,test1,3); 用簡單的話做以下事情:

“從數組“ test”的最后一個元素開始,然后從數組“ test1”復制3個字符到那里”,這基本上寫了2個字符,超出了數組“ test”的長度。

因此,如果您只想玩'memcpy',請定義第三個數組:

char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);

變量test1在內存中為4個字符,3個加上結束字符串終止符。 嘗試這個:

char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM