स्टैक स्मैशिंग का पता चला


246

मैं अपनी a.out फ़ाइल निष्पादित कर रहा हूं। निष्पादन के बाद कार्यक्रम कुछ समय के लिए चलता है फिर संदेश के साथ बाहर निकलता है:

**** stack smashing detected ***: ./a.out terminated*
*======= Backtrace: =========*
*/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)Aborted*

इसके संभावित कारण क्या हो सकते हैं और मैं इसे कैसे ठीक करूं?


2
क्या आप शायद पहचान सकते हैं कि आप के कौन से कोड स्टैक मुंहतोड़ का कारण बनते हैं, और इसे पोस्ट करते हैं? तब हम संभवत: यह इंगित करने में सक्षम होंगे कि ऐसा क्यों होता है और इसे कैसे ठीक किया जाए।
बजरैक फ्रायंड-हैन्सन

मुझे लगता है कि यह अतिप्रवाह त्रुटि का पर्याय है। उदाहरण के लिए यदि आप 5 तत्वों को आरंभीकरण और सरणी करते हैं, तो यह त्रुटि 6 वें तत्व, या किसी भी तत्व को सरणी के सीमा के बाहर लिखने की कोशिश करते समय दिखाई देगी।
डोरिनपोपस्क्यू

जवाबों:


349

स्टैक स्मैशिंग वास्तव में बफर ओवरफ्लो त्रुटियों का पता लगाने के लिए जीसीसी द्वारा उपयोग किए जाने वाले एक सुरक्षा तंत्र के कारण होता है। निम्नलिखित स्निपेट में उदाहरण के लिए:

#include <stdio.h>

void func()
{
    char array[10];
    gets(array);
}

int main(int argc, char **argv)
{
    func();
}

संकलक, (इस मामले में gcc) सुरक्षा चर (कनारी कहा जाता है) जोड़ता है जिसमें ज्ञात मूल्य होते हैं। 10 से अधिक आकार की एक इनपुट स्ट्रिंग इस चर के भ्रष्टाचार का कारण बनती है जिसके परिणामस्वरूप SIGABRT कार्यक्रम को समाप्त कर देता है।

कुछ अंतर्दृष्टि पाने के लिए, आप -fno-stack-protector संकलन करते समय विकल्प का उपयोग करके जीसीसी के इस संरक्षण को अक्षम करने का प्रयास कर सकते हैं । उस मामले में आपको एक अलग त्रुटि मिलेगी, सबसे अधिक संभावना एक विभाजन दोष है क्योंकि आप एक अवैध मेमोरी स्थान तक पहुंचने का प्रयास कर रहे हैं। ध्यान दें कि -fstack-protectorहमेशा रिलीज बिल्ड के लिए चालू होना चाहिए क्योंकि यह एक सुरक्षा विशेषता है।

आप डिबगर के साथ प्रोग्राम चलाकर अतिप्रवाह के बिंदु के बारे में कुछ जानकारी प्राप्त कर सकते हैं। Valgrind स्टैक-संबंधित त्रुटियों के साथ अच्छी तरह से काम नहीं करता है, लेकिन डिबगर की तरह, यह आपको दुर्घटना के स्थान और कारण को इंगित करने में मदद कर सकता है।


3
इस उत्तर के लिए धन्यवाद! मैंने पाया कि मेरे मामले में मैंने उस वैरिएबल को इनिशियलाइज़ नहीं किया था जिसे मैं लिखने की कोशिश कर रहा था
टेड पेन्निंग्स

5
Valgrind स्टैक-संबंधित त्रुटियों के लिए अच्छी तरह से काम नहीं करता है, क्योंकि यह वहां लाल ज़ोन नहीं जोड़ सकता है
toasted_flakes

7
यह उत्तर गलत है, और खतरनाक सलाह प्रदान करता है। सबसे पहले, स्टैक प्रोटेक्टर को हटाना सही समाधान नहीं है - यदि आपको स्टैक स्मैशिंग की त्रुटि मिल रही है, तो संभवतः आपके पास कोड में एक गंभीर सुरक्षा भेद्यता है। सही प्रतिक्रिया छोटी गाड़ी कोड को ठीक करने के लिए है । दूसरा, जैसा कि ग्रासगेर्मे बताते हैं, वैलग्राइंड को आजमाने की सिफारिश प्रभावी नहीं है। Valgrind आमतौर पर स्टैक-आबंटित डेटा तक अवैध मेमोरी एक्सेस का पता लगाने के लिए काम नहीं करता है।
DW

22
ओपी इस व्यवहार के लिए संभावित कारण पूछता है, मेरा जवाब एक उदाहरण प्रदान करता है और यह कैसे एक यथोचित ज्ञात त्रुटि से संबंधित है। इसके अलावा, स्टैक-रक्षक को हटाना एक समाधान नहीं है, यह एक प्रयोग की तरह है जो समस्या को और अधिक जानकारी प्राप्त करने के लिए कर सकता है। सलाह वास्तव में किसी तरह त्रुटि को ठीक करने के लिए है, वेलग्रिंड के बारे में इंगित करने के लिए धन्यवाद, मैं इसे प्रतिबिंबित करने के लिए अपने उत्तर को संपादित करूंगा।
sud03r

4
@ डब्लूडी स्टैक प्रोटेक्शन को रिलीज़ संस्करण में बंद किया जाना चाहिए, क्योंकि पहली बार में - स्टैक मुंहतोड़ किया गया संदेश केवल एक डेवलपर्स के लिए एक मदद है; दूसरे स्थान पर - एक आवेदन में अभी तक जीवित रहने की संभावना हो सकती है; और तीसरे पर - यह एक छोटा अनुकूलन है।
हाय-एंजेल

33

Disassembly विश्लेषण के साथ न्यूनतम प्रजनन उदाहरण

main.c

void myfunc(char *const src, int len) {
    int i;
    for (i = 0; i < len; ++i) {
        src[i] = 42;
    }
}

int main(void) {
    char arr[] = {'a', 'b', 'c', 'd'};
    int len = sizeof(arr);
    myfunc(arr, len + 1);
    return 0;
}

गिटहब ऊपर

संकलित करें और चलाएं:

gcc -fstack-protector -g -O0 -std=c99 main.c
ulimit -c unlimited && rm -f core
./a.out

वांछित के रूप में विफल रहता है:

*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)

उबंटू 16.04, जीसीसी 6.4.0 पर परीक्षण किया गया।

disassembly

अब हम डिससैड को देखते हैं:

objdump -D a.out

जिसमें है:

int main (void){
  400579:       55                      push   %rbp
  40057a:       48 89 e5                mov    %rsp,%rbp

  # Allocate 0x10 of stack space.
  40057d:       48 83 ec 10             sub    $0x10,%rsp

  # Put the 8 byte canary from %fs:0x28 to -0x8(%rbp),
  # which is right at the bottom of the stack.
  400581:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400588:       00 00 
  40058a:       48 89 45 f8             mov    %rax,-0x8(%rbp)

  40058e:       31 c0                   xor    %eax,%eax
    char arr[] = {'a', 'b', 'c', 'd'};
  400590:       c6 45 f4 61             movb   $0x61,-0xc(%rbp)
  400594:       c6 45 f5 62             movb   $0x62,-0xb(%rbp)
  400598:       c6 45 f6 63             movb   $0x63,-0xa(%rbp)
  40059c:       c6 45 f7 64             movb   $0x64,-0x9(%rbp)
    int len = sizeof(arr);
  4005a0:       c7 45 f0 04 00 00 00    movl   $0x4,-0x10(%rbp)
    myfunc(arr, len + 1);
  4005a7:       8b 45 f0                mov    -0x10(%rbp),%eax
  4005aa:       8d 50 01                lea    0x1(%rax),%edx
  4005ad:       48 8d 45 f4             lea    -0xc(%rbp),%rax
  4005b1:       89 d6                   mov    %edx,%esi
  4005b3:       48 89 c7                mov    %rax,%rdi
  4005b6:       e8 8b ff ff ff          callq  400546 <myfunc>
    return 0;
  4005bb:       b8 00 00 00 00          mov    $0x0,%eax
}
  # Check that the canary at -0x8(%rbp) hasn't changed after calling myfunc.
  # If it has, jump to the failure point __stack_chk_fail.
  4005c0:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
  4005c4:       64 48 33 0c 25 28 00    xor    %fs:0x28,%rcx
  4005cb:       00 00 
  4005cd:       74 05                   je     4005d4 <main+0x5b>
  4005cf:       e8 4c fe ff ff          callq  400420 <__stack_chk_fail@plt>

  # Otherwise, exit normally.
  4005d4:       c9                      leaveq 
  4005d5:       c3                      retq   
  4005d6:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4005dd:       00 00 00 

सूचना आसान टिप्पणियों का स्वचालित रूप से जोड़ा objdumpहै कृत्रिम बुद्धि मॉड्यूल

यदि आप GDB के माध्यम से इस कार्यक्रम को कई बार चलाते हैं, तो आप देखेंगे कि:

  • कैनरी को हर बार एक अलग यादृच्छिक मूल्य मिलता है
  • का अंतिम लूप myfuncबिल्कुल वही है जो कैनरी के पते को संशोधित करता है

कैनरी को इसके साथ सेट करके यादृच्छिक किया जाता है %fs:0x28, जिसमें एक यादृच्छिक मूल्य होता है जैसा कि समझाया गया है:

डिबग के प्रयास

अब से, हम कोड को संशोधित करते हैं:

    myfunc(arr, len + 1);

इसके बजाय:

    myfunc(arr, len);
    myfunc(arr, len + 1); /* line 12 */
    myfunc(arr, len);

अधिक दिलचस्प होना।

फिर हम यह देखने की कोशिश करेंगे कि क्या हम + 1पूरे स्रोत कोड को पढ़ने और समझने की तुलना में अधिक स्वचालित विधि से अपराधी कॉल को इंगित कर सकते हैं ।

gcc -fsanitize=address Google के एड्रेस सैनिटाइज़र (आसन) को सक्षम करने के लिए

यदि आप इस झंडे के साथ घूमते हैं और कार्यक्रम चलाते हैं, तो यह आउटपुट करता है:

#0 0x4008bf in myfunc /home/ciro/test/main.c:4
#1 0x40099b in main /home/ciro/test/main.c:12
#2 0x7fcd2e13d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#3 0x400798 in _start (/home/ciro/test/a.out+0x40079

कुछ और रंगीन आउटपुट के बाद।

यह स्पष्ट रूप से समस्याग्रस्त रेखा 12 को इंगित करता है।

इसके लिए स्रोत कोड इस प्रकार है: https://github.com/google/sanitizers लेकिन जैसा कि हमने उदाहरण से देखा कि यह पहले से ही जीसीसी में अपस्ट्रीम है।

आसन मेमोरी मेमोरी जैसी अन्य मेमोरी समस्याओं का भी पता लगा सकता है: C ++ कोड / प्रोजेक्ट में मेमोरी लीक कैसे खोजें?

वेलग्रिंड SGCheck

जैसा कि दूसरों ने उल्लेख किया है , वालग्रिंड इस तरह की समस्या को हल करने में अच्छा नहीं है।

इसमें एक प्रयोगात्मक उपकरण है जिसे SGCheck कहा जाता है :

SGCheck स्टैक और वैश्विक सरणियों के ओवररन को खोजने के लिए एक उपकरण है। यह स्टैक और वैश्विक सरणी एक्सेस के संभावित रूपों के बारे में अवलोकन से प्राप्त एक हेयुरिस्टिक दृष्टिकोण का उपयोग करके काम करता है।

इसलिए मुझे बहुत आश्चर्य नहीं हुआ जब इसमें त्रुटि नहीं मिली:

valgrind --tool=exp-sgcheck ./a.out

त्रुटि संदेश इस तरह से स्पष्ट रूप से दिखना चाहिए: लापता त्रुटि त्रुटि

GDB

एक महत्वपूर्ण अवलोकन यह है कि यदि आप GDB के माध्यम से प्रोग्राम चलाते हैं, या coreइस तथ्य के बाद फाइल की जांच करते हैं :

gdb -nh -q a.out core

फिर, जैसा कि हमने असेंबली में देखा था, जीडीबी आपको उस फ़ंक्शन के अंत में इंगित करना चाहिए जिसने कैनरी चेक किया था:

(gdb) bt
#0  0x00007f0f66e20428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007f0f66e2202a in __GI_abort () at abort.c:89
#2  0x00007f0f66e627ea in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f0f66f7a49f "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f0f66f0415c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f0f66f7a481 "stack smashing detected") at fortify_fail.c:37
#4  0x00007f0f66f04100 in __stack_chk_fail () at stack_chk_fail.c:28
#5  0x00000000004005f6 in main () at main.c:15
(gdb) f 5
#5  0x00000000004005f6 in main () at main.c:15
15      }
(gdb)

और इसलिए समस्या इस फ़ंक्शन द्वारा किए गए कॉल में से एक में होने की संभावना है।

अगला हम कैनरी सेट होने के तुरंत बाद पहले सिंगल स्टेपिंग द्वारा सटीक असफल कॉलिंग को इंगित करने का प्रयास करते हैं:

  400581:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  400588:       00 00 
  40058a:       48 89 45 f8             mov    %rax,-0x8(%rbp)

और पता देख रहे हैं:

(gdb) p $rbp - 0x8
$1 = (void *) 0x7fffffffcf18
(gdb) watch 0x7fffffffcf18
Hardware watchpoint 2: *0x7fffffffcf18
(gdb) c
Continuing.

Hardware watchpoint 2: *0x7fffffffcf18

Old value = 1800814336
New value = 1800814378
myfunc (src=0x7fffffffcf14 "*****?Vk\266", <incomplete sequence \355\216>, len=5) at main.c:3
3           for (i = 0; i < len; ++i) {
(gdb) p len
$2 = 5
(gdb) p i
$3 = 4
(gdb) bt
#0  myfunc (src=0x7fffffffcf14 "*****?Vk\266", <incomplete sequence \355\216>, len=5) at main.c:3
#1  0x00000000004005cc in main () at main.c:12

अब, यह हमें सही अपमानजनक निर्देश पर छोड़ देता है: len = 5और i = 4, और इस विशेष मामले में, हमें अपराधी लाइन 12 की ओर इशारा किया।

हालाँकि, बैकट्रेस दूषित है, और इसमें कुछ कचरा है। एक सही बैकट्रेस लगेगा:

#0  myfunc (src=0x7fffffffcf14 "abcd", len=4) at main.c:3
#1  0x00000000004005b8 in main () at main.c:11

तो शायद यह स्टैक को दूषित कर सकता है और आपको ट्रेस देखने से रोक सकता है।

इसके अलावा, इस विधि में यह जानना आवश्यक है कि कैनरी चेकिंग फ़ंक्शन की अंतिम कॉल क्या है अन्यथा आपके पास झूठी सकारात्मकताएं होंगी, जो हमेशा संभव नहीं होंगी, जब तक कि आप रिवर्स डिबगिंग का उपयोगकरें


16

कृपया निम्नलिखित स्थिति देखें:

ab@cd-x:$ cat test_overflow.c 
#include <stdio.h>
#include <string.h>

int check_password(char *password){
    int flag = 0;
    char buffer[20];
    strcpy(buffer, password);

    if(strcmp(buffer, "mypass") == 0){
        flag = 1;
    }
    if(strcmp(buffer, "yourpass") == 0){
        flag = 1;
    }
    return flag;
}

int main(int argc, char *argv[]){
    if(argc >= 2){
        if(check_password(argv[1])){
            printf("%s", "Access granted\n");
        }else{
            printf("%s", "Access denied\n");
        }
    }else{
        printf("%s", "Please enter password!\n");
    }
}
ab@cd-x:$ gcc -g -fno-stack-protector test_overflow.c 
ab@cd-x:$ ./a.out mypass
Access granted
ab@cd-x:$ ./a.out yourpass
Access granted
ab@cd-x:$ ./a.out wepass
Access denied
ab@cd-x:$ ./a.out wepassssssssssssssssss
Access granted

ab@cd-x:$ gcc -g -fstack-protector test_overflow.c 
ab@cd-x:$ ./a.out wepass
Access denied
ab@cd-x:$ ./a.out mypass
Access granted
ab@cd-x:$ ./a.out yourpass
Access granted
ab@cd-x:$ ./a.out wepassssssssssssssssss
*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xce0ed8]
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0xce0e90]
./a.out[0x8048524]
./a.out[0x8048545]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xc16b56]
./a.out[0x8048411]
======= Memory map: ========
007d9000-007f5000 r-xp 00000000 08:06 5776       /lib/libgcc_s.so.1
007f5000-007f6000 r--p 0001b000 08:06 5776       /lib/libgcc_s.so.1
007f6000-007f7000 rw-p 0001c000 08:06 5776       /lib/libgcc_s.so.1
0090a000-0090b000 r-xp 00000000 00:00 0          [vdso]
00c00000-00d3e000 r-xp 00000000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d3e000-00d3f000 ---p 0013e000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d3f000-00d41000 r--p 0013e000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d41000-00d42000 rw-p 00140000 08:06 1183       /lib/tls/i686/cmov/libc-2.10.1.so
00d42000-00d45000 rw-p 00000000 00:00 0 
00e0c000-00e27000 r-xp 00000000 08:06 4213       /lib/ld-2.10.1.so
00e27000-00e28000 r--p 0001a000 08:06 4213       /lib/ld-2.10.1.so
00e28000-00e29000 rw-p 0001b000 08:06 4213       /lib/ld-2.10.1.so
08048000-08049000 r-xp 00000000 08:05 1056811    /dos/hacking/test/a.out
08049000-0804a000 r--p 00000000 08:05 1056811    /dos/hacking/test/a.out
0804a000-0804b000 rw-p 00001000 08:05 1056811    /dos/hacking/test/a.out
08675000-08696000 rw-p 00000000 00:00 0          [heap]
b76fe000-b76ff000 rw-p 00000000 00:00 0 
b7717000-b7719000 rw-p 00000000 00:00 0 
bfc1c000-bfc31000 rw-p 00000000 00:00 0          [stack]
Aborted
ab@cd-x:$ 

जब मैंने स्टैक मुंहतोड़ रक्षक को निष्क्रिय कर दिया, तो कोई त्रुटि नहीं मिली, जो कि तब होनी चाहिए थी जब मैंने "./a.out wepassssssssssssssssss" का प्रयोग किया।

इसलिए आपके प्रश्न का उत्तर देने के लिए, संदेश "** स्टैक स्मैशिंग डिटेक्टेड: xxx" प्रदर्शित किया गया क्योंकि आपका स्टैक स्मैशिंग रक्षक सक्रिय था और पाया गया कि आपके प्रोग्राम में स्टैक ओवरफ्लो है।

बस यह पता करें कि यह कहां होता है, और इसे ठीक करें।


7

आप वेलग्रिंड का उपयोग करके समस्या को दूर करने का प्रयास कर सकते हैं :

Valgrind वितरण में वर्तमान में छह उत्पादन-गुणवत्ता के उपकरण शामिल हैं: एक मेमोरी त्रुटि डिटेक्टर, दो थ्रेड एरर डिटेक्टर, एक कैश और शाखा-भविष्यवाणी प्रोफाइलर, एक कॉल-ग्राफ जनरेटिंग कैश प्रोफाइलर और एक ढेर प्रोफाइलर। इसमें दो प्रायोगिक उपकरण भी शामिल हैं: एक ढेर / स्टैक / ग्लोबल एरे ओवररन डिटेक्टर , और एक सिम्पसन बेसिक ब्लॉक वेक्टर जेनरेटर। यह निम्नलिखित प्लेटफार्मों पर चलता है: X86 / Linux, AMD64 / Linux, PPC32 / Linux, PPC64 / Linux, और X86 / Darwin (Mac OS X)।


2
हाँ, लेकिन Valgrind ढेर-आवंटित बफ़र्स के ओवरफ्लो के लिए अच्छी तरह से काम नहीं करता है, जो कि इस त्रुटि संदेश को इंगित करता है।
DW

4
हम उस स्टैक ऐरे से अधिक डिटेक्टर का उपयोग कैसे कर सकते हैं ? क्या आप विस्तार से समझा सकते हैं?
क्रेग मैकक्वीन

@CraigMcQueen मैंने Valgrind के प्रायोगिक हेरास्टिक SGCheck स्टैक स्मैशिंग डिटेक्टर का कम से कम उदाहरण में उपयोग करने का प्रयास किया है: stackoverflow.com/a/51897264/895245 लेकिन यह विफल रहा।
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

4

इसका मतलब है कि आपने स्टैक पर कुछ वैरिएबल को अवैध तरीके से लिखा था, सबसे अधिक बफ़र ओवरफ्लो के परिणामस्वरूप ।


9
स्टैक ओवरफ्लो किसी और चीज में फंसने वाला स्टैक है। यहाँ यह दूसरा तरीका है: कुछ स्टैक में धंस गया है।
पीटर मोर्टेंसन

5
ज़रुरी नहीं। यह स्टैक का एक हिस्सा दूसरे भाग में मुंहतोड़ है। तो यह वास्तव में एक बफर अतिप्रवाह है, बस स्टैक के शीर्ष पर नहीं है, लेकिन स्टैक के दूसरे हिस्से में "केवल" है।
बास विज्नेन

2

इसके संभावित कारण क्या हो सकते हैं और मैं इसे कैसे ठीक करूं?

एक उदाहरण निम्नलिखित उदाहरण में होगा:

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

void swap ( char *a , char *b );
void revSTR ( char *const src );

int main ( void ){
    char arr[] = "A-B-C-D-E";

    revSTR( arr );
    printf("ARR = %s\n", arr );
}

void swap ( char *a , char *b ){
    char tmp = *a;
    *a = *b;
    *b = tmp;
}

void revSTR ( char *const src ){
    char *start = src;
    char *end   = start + ( strlen( src ) - 1 );

    while ( start < end ){
        swap( &( *start ) , &( *end ) );
        start++;
        end--;
    }
}

इस कार्यक्रम में आप स्ट्रिंग या स्ट्रिंग के एक भाग को उल्टा कर सकते हैं यदि आप उदाहरण के लिए reverse()इस तरह से कुछ के साथ कॉल करते हैं:

reverse( arr + 2 );

यदि आप इस तरह से सरणी की लंबाई पास करने का निर्णय लेते हैं:

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

void swap ( char *a , char *b );
void revSTR ( char *const src, size_t len );

int main ( void ){
    char arr[] = "A-B-C-D-E";
    size_t len = strlen( arr );

    revSTR( arr, len );
    printf("ARR = %s\n", arr );
}

void swap ( char *a , char *b ){
    char tmp = *a;
    *a = *b;
    *b = tmp;
}

void revSTR ( char *const src, size_t len ){
    char *start = src;
    char *end   = start + ( len - 1 );

    while ( start < end ){
        swap( &( *start ) , &( *end ) );
        start++;
        end--;
    }
}

ठीक भी काम करता है।

लेकिन जब आप ऐसा करते हैं:

revSTR( arr + 2, len );

आपको मिलता है:

==7125== Command: ./program
==7125== 
ARR = A-
*** stack smashing detected ***: ./program terminated
==7125== 
==7125== Process terminating with default action of signal 6 (SIGABRT)
==7125==    at 0x4E6F428: raise (raise.c:54)
==7125==    by 0x4E71029: abort (abort.c:89)
==7125==    by 0x4EB17E9: __libc_message (libc_fatal.c:175)
==7125==    by 0x4F5311B: __fortify_fail (fortify_fail.c:37)
==7125==    by 0x4F530BF: __stack_chk_fail (stack_chk_fail.c:28)
==7125==    by 0x400637: main (program.c:14)

और ऐसा इसलिए होता है क्योंकि पहले कोड में, जिस लंबाई के arrअंदर जाँच की revSTR()जाती है वह ठीक है, लेकिन दूसरे कोड में जहाँ आप लंबाई पास करते हैं:

revSTR( arr + 2, len );

लंबाई अब लंबी है जब आप कहते हैं कि वास्तव में आप जिस लंबाई से गुजरते हैं arr + 2

लंबाई strlen ( arr + 2 )! = strlen ( arr )


1
मुझे यह उदाहरण पसंद है क्योंकि यह मानक पुस्तकालय कार्यों जैसे getsऔर पर निर्भर नहीं करता है scrcpy। मुझे आश्चर्य है कि अगर हम आगे भी कम कर सकते हैं। मैं कम से कम से छुटकारा पाने चाहते हैं string.hके साथ size_t len = sizeof( arr );। Gcc 6.4, Ubuntu 16.04 पर परीक्षण किया गया। मैं arr + 2कॉपी पेस्ट को कम करने के साथ असफल उदाहरण भी दूंगा ।
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

1

ढेर बफर के कारण ususally ढेर भ्रष्टाचार। आप रक्षात्मक रूप से प्रोग्रामिंग करके उनके खिलाफ बचाव कर सकते हैं।

जब भी आप किसी ऐरे को एक्सेस करते हैं, तो सुनिश्चित करने के लिए इससे पहले कि यह सीमा से बाहर नहीं है, एसेर डाल दें। उदाहरण के लिए:

assert(i + 1 < N);
assert(i < N);
a[i + 1] = a[i];

यह आपको सरणी सीमाओं के बारे में सोचने देता है और यदि संभव हो तो उन्हें ट्रिगर करने के लिए परीक्षणों को जोड़ने के बारे में भी सोचता है। यदि इन उपयोगों में से कुछ सामान्य उपयोग के दौरान विफल हो सकते हैं तो उन्हें एक नियमित में बदल दें if


0

मैलोडोक () को किसी मेमोरी को किसी संरचना में आवंटित करने के लिए यह त्रुटि आई। * इस डिबगिंग कोड को खर्च करने के बाद, मैंने अंत में आवंटित मेमोरी को मुक्त करने के लिए मुफ्त () फ़ंक्शन का उपयोग किया और बाद में त्रुटि संदेश चला गया :)


0

स्टैक स्मैशिंग का एक अन्य स्रोत vfork()इसके बजाय (गलत) उपयोग है fork()

मैंने सिर्फ इसके एक मामले पर बहस की, जहां बच्चे की प्रक्रिया execve()निष्पादन योग्य नहीं थी और कॉल करने के बजाय एक त्रुटि कोड दिया _exit()

क्योंकि vfork()उस बच्चे को जन्म दिया था, यह वास्तव में माता-पिता के प्रक्रिया स्थान के भीतर निष्पादित करते समय वापस आया, न केवल माता-पिता के ढेर को भ्रष्ट कर रहा था, बल्कि डायग्नोस्टिक्स के दो विषम सेटों को "डाउनस्ट्रीम" कोड द्वारा मुद्रित किया गया था।

बदलने vfork()के लिए fork()तय हो गई दोनों समस्याओं, के रूप में बच्चे के बदलते किया returnकरने के लिए बयान _exit()के बजाय।

लेकिन चूँकि चाइल्ड कोड execve()कॉल को अन्य रूटीन (कॉल को uid / gid सेट करने के लिए, इस विशेष मामले में) से पहले करता है vfork(), इसलिए यह तकनीकी रूप से इसके लिए आवश्यकताओं को पूरा नहीं करता है , इसलिए इसे उपयोग करने के लिए बदलना fork()यहाँ सही है।

(ध्यान दें कि समस्याग्रस्त returnबयान को वास्तव में इस तरह कोडित नहीं किया गया था - इसके बजाय, एक मैक्रो को लागू किया गया था, और उस मैक्रो ने फैसला किया कि क्या वैश्विक चर पर आधारित है _exit()या returnनहीं। इसलिए यह तुरंत स्पष्ट नहीं था कि बाल कोड vfork()उपयोग के लिए गैर-अनुरूप था । )

अधिक जानकारी के लिए देखें:

कांटा (), vfork (), निष्पादन () और क्लोन () के बीच का अंतर

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.