Phát hiện đập vỡ ngăn xếp


246

Tôi đang thực hiện tập tin a.out của tôi. Sau khi thực hiện chương trình chạy một thời gian rồi thoát với thông báo:

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

Điều gì có thể là lý do có thể cho việc này và làm thế nào để tôi khắc phục nó?


2
Có lẽ bạn có thể xác định phần nào trong mã của bạn gây ra sự cố đập ngăn xếp và đăng nó? Sau đó, chúng tôi có thể sẽ có thể chỉ ra chính xác lý do tại sao nó xảy ra và làm thế nào để sửa nó.
Bjarke Freund-Hansen

Tôi nghĩ đó là từ đồng nghĩa với lỗi tràn. Ví dụ: nếu bạn khởi tạo và mảng 5 phần tử, lỗi này sẽ xuất hiện khi cố gắng viết phần tử thứ 6 hoặc bất kỳ phần tử nào nằm ngoài giới hạn của mảng.
DorinPopescu

Câu trả lời:


349

Stack Smashing ở đây thực sự gây ra do một cơ chế bảo vệ được sử dụng bởi gcc để phát hiện lỗi tràn bộ đệm. Ví dụ trong đoạn trích sau:

#include <stdio.h>

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

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

Trình biên dịch, (trong trường hợp này là gcc) thêm các biến bảo vệ (được gọi là canaries) có các giá trị đã biết. Chuỗi đầu vào có kích thước lớn hơn 10 gây ra tham nhũng của biến này dẫn đến SIGABRT chấm dứt chương trình.

Để hiểu rõ hơn, bạn có thể thử tắt chức năng bảo vệ gcc này bằng cách sử dụng tùy chọn -fno-stack-protector trong khi biên dịch. Trong trường hợp đó, bạn sẽ gặp một lỗi khác, rất có thể là lỗi phân đoạn khi bạn đang cố truy cập vào một vị trí bộ nhớ bất hợp pháp. Lưu ý rằng-fstack-protector phải luôn được bật cho các bản dựng phát hành vì đây là một tính năng bảo mật.

Bạn có thể nhận được một số thông tin về điểm tràn bằng cách chạy chương trình với trình gỡ lỗi. Valgrind không hoạt động tốt với các lỗi liên quan đến ngăn xếp, nhưng giống như trình gỡ lỗi, nó có thể giúp bạn xác định vị trí và lý do cho sự cố.


3
cảm ơn vì câu trả lời này Tôi thấy rằng trong trường hợp của mình, tôi đã không khởi tạo biến mà tôi đang cố viết cho
Ted Pennings

5
Valgrind không hoạt động tốt đối với các lỗi liên quan đến ngăn xếp, vì nó không thể thêm các vùng màu đỏ ở đó
to nướng_flakes

7
Câu trả lời này là không chính xác, và cung cấp lời khuyên nguy hiểm. Trước hết, loại bỏ bảo vệ ngăn xếp không phải là giải pháp phù hợp - nếu bạn gặp lỗi đập ngăn xếp, có thể bạn có một lỗ hổng bảo mật nghiêm trọng trong mã của mình. Đáp ứng đúng là sửa mã lỗi . Thứ hai, như grasGendarme chỉ ra, khuyến nghị dùng thử Valgrind sẽ không hiệu quả. Valgrind thường không hoạt động để phát hiện truy cập bộ nhớ bất hợp pháp vào dữ liệu được cấp phát ngăn xếp.
DW

22
OP yêu cầu các lý do có thể cho hành vi này, câu trả lời của tôi cung cấp một ví dụ và cách nó liên quan đến một lỗi được biết một cách hợp lý. Bên cạnh đó, loại bỏ bộ bảo vệ ngăn xếp không phải là một giải pháp, đây là một thử nghiệm mà người ta có thể làm để hiểu rõ hơn về vấn đề. Lời khuyên thực sự là sửa lỗi bằng cách nào đó, cảm ơn vì đã chỉ về valgrind, tôi sẽ chỉnh sửa câu trả lời của mình để phản ánh điều này.
sud03r

4
@DW bảo vệ ngăn xếp nên được tắt trong phiên bản phát hành, bởi vì lúc đầu - thông báo phát hiện ngăn xếp ngăn xếp chỉ là trợ giúp cho nhà phát triển; ở lần thứ hai - một ứng dụng có thể có cơ hội sống sót; và ở thứ ba - đây là một tối ưu hóa nhỏ.
Hi-Angel

33

Ví dụ sinh sản tối thiểu với phân tích tháo gỡ

C chính

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

GitHub ngược dòng .

Biên dịch và chạy:

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

thất bại như mong muốn:

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

Đã thử nghiệm trên Ubuntu 16.04, GCC 6.4.0.

Tháo gỡ

Bây giờ chúng tôi xem xét việc tháo gỡ:

objdump -D a.out

trong đó có:

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 

Chú ý các ý kiến tiện tự động thêm bởi objdump's mô-đun trí tuệ nhân tạo .

Nếu bạn chạy chương trình này nhiều lần thông qua GDB, bạn sẽ thấy rằng:

  • chim hoàng yến nhận được một giá trị ngẫu nhiên khác nhau mỗi lần
  • vòng lặp cuối cùng myfuncchính xác là những gì sửa đổi địa chỉ của chim hoàng yến

Chim hoàng yến ngẫu nhiên bằng cách đặt nó với %fs:0x28, chứa một giá trị ngẫu nhiên như được giải thích tại:

Nỗ lực gỡ lỗi

Từ bây giờ, chúng tôi sửa đổi mã:

    myfunc(arr, len + 1);

thay vào đó:

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

để thú vị hơn

Sau đó, chúng tôi sẽ cố gắng xem liệu chúng tôi có thể xác định chính xác + 1cuộc gọi thủ phạm bằng một phương thức tự động hơn là chỉ đọc và hiểu toàn bộ mã nguồn.

gcc -fsanitize=address để bật Công cụ vệ sinh địa chỉ của Google (ASan)

Nếu bạn biên dịch lại với cờ này và chạy chương trình, nó sẽ xuất ra:

#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

tiếp theo là một số đầu ra màu hơn.

Điều này xác định rõ ràng dòng 12 có vấn đề.

Mã nguồn cho việc này là tại: https://github.com/google/sanitulators nhưng như chúng ta đã thấy từ ví dụ này, nó đã được đưa vào GCC.

ASan cũng có thể phát hiện các vấn đề bộ nhớ khác như rò rỉ bộ nhớ: Làm thế nào để tìm rò rỉ bộ nhớ trong mã / dự án C ++?

Valgrind SGCheck

Như những người khác đã đề cập , Valgrind không giỏi trong việc giải quyết loại vấn đề này.

Nó có một công cụ thử nghiệm gọi là SGCheck :

SGCheck là một công cụ để tìm các phần vượt quá của ngăn xếp và mảng toàn cầu. Nó hoạt động bằng cách sử dụng một cách tiếp cận heuristic xuất phát từ một quan sát về các dạng truy cập của ngăn xếp và mảng toàn cầu.

Vì vậy, tôi đã không rất ngạc nhiên khi nó không tìm thấy lỗi:

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

Thông báo lỗi sẽ trông như thế này rõ ràng: Lỗi thiếu Valgrind

GDB

Một quan sát quan trọng là nếu bạn chạy chương trình thông qua GDB, hoặc kiểm tra coretệp sau khi thực tế:

gdb -nh -q a.out core

sau đó, như chúng ta đã thấy trên hội đồng, GDB sẽ chỉ cho bạn đến cuối chức năng đã kiểm tra canary:

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

Và do đó, vấn đề có thể xảy ra ở một trong những cuộc gọi mà chức năng này thực hiện.

Tiếp theo, chúng tôi cố gắng xác định chính xác cuộc gọi thất bại bằng cách bước đầu tiên ngay sau khi hoàng yến được thiết lập:

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

và xem địa chỉ:

(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

Bây giờ, điều này không cho chúng ta theo hướng dẫn vi phạm đúng: len = 5i = 4, trong trường hợp cụ thể này, đã chỉ chúng ta đến dòng 12 thủ phạm.

Tuy nhiên, backtrace bị hỏng và chứa một số rác. Một backtrace chính xác sẽ trông như:

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

vì vậy có lẽ điều này có thể làm hỏng ngăn xếp và ngăn bạn nhìn thấy dấu vết.

Ngoài ra, phương pháp này yêu cầu biết cuộc gọi cuối cùng của chức năng kiểm tra canary là gì nếu không bạn sẽ có kết quả dương tính giả, điều này sẽ không luôn khả thi, trừ khi bạn sử dụng gỡ lỗi ngược .


16

Hãy nhìn vào tình huống sau đây:

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:$ 

Khi tôi vô hiệu hóa trình bảo vệ đập ngăn xếp, không có lỗi nào được phát hiện, điều này đã xảy ra khi tôi sử dụng "./a.out wepassssssssssssssssss"

Vì vậy, để trả lời câu hỏi của bạn ở trên, thông báo "** đập vỡ ngăn xếp được phát hiện: xxx" đã được hiển thị do bộ bảo vệ đập ngăn xếp của bạn đã hoạt động và thấy rằng có tràn ngăn xếp trong chương trình của bạn.

Chỉ cần tìm ra nơi xảy ra, và sửa chữa nó.


7

Bạn có thể thử gỡ lỗi bằng cách sử dụng valgrind :

Bản phân phối Valgrind hiện bao gồm sáu công cụ chất lượng sản xuất: trình phát hiện lỗi bộ nhớ, hai trình phát hiện lỗi luồng, trình lưu trữ dự đoán bộ đệm và dự đoán nhánh, trình lược tả bộ đệm tạo biểu đồ cuộc gọi và trình lược tả heap. Nó cũng bao gồm hai công cụ thử nghiệm: bộ phát hiện vượt mức heap / stack / global và bộ tạo vector khối cơ bản SimPoint. Nó chạy trên các nền tảng sau: X86 / Linux, AMD64 / Linux, PPC32 / Linux, PPC64 / Linux và X86 / Darwin (Mac OS X).


2
Vâng, nhưng Valgrind không hoạt động tốt khi tràn bộ đệm được phân bổ ngăn xếp, đó là tình huống mà thông báo lỗi này chỉ ra.
DW

4
Làm thế nào chúng ta có thể sử dụng máy phát hiện mảng chồng tràn đó ? Bạn có thể xây dựng?
Craig McQueen

@CraigMcQueen Tôi đã thử sử dụng trình phát hiện phá vỡ ngăn xếp SGCheck thử nghiệm của Valgrind trên một ví dụ tối thiểu: stackoverflow.com/a/51897264/895245 nhưng không thành công.
Ciro Santilli 郝海东 冠状 病 事件

4

Điều đó có nghĩa là bạn đã viết cho một số biến trên ngăn xếp một cách bất hợp pháp, rất có thể là kết quả của việc tràn bộ đệm .


9
Chồng tràn là ngăn xếp đập vào một cái gì đó khác. Đây là cách khác: một cái gì đó đã đập vào ngăn xếp.
Peter Mortensen

5
Không hẳn vậy. Đó là một phần của ngăn xếp đập vào một phần khác. Vì vậy, nó thực sự là một lỗi tràn bộ đệm, không chỉ trên đỉnh của ngăn xếp, mà "chỉ" vào một phần khác của ngăn xếp.
Bas Wijnen

2

Điều gì có thể là lý do có thể cho việc này và làm thế nào để tôi khắc phục nó?

Một kịch bản sẽ có trong ví dụ sau:

#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--;
    }
}

Trong chương trình này, bạn có thể đảo ngược một Chuỗi hoặc một phần của chuỗi nếu bạn ví dụ gọi reverse()bằng một cái gì đó như thế này:

reverse( arr + 2 );

Nếu bạn quyết định vượt qua độ dài của mảng như thế này:

#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--;
    }
}

Hoạt động tốt quá.

Nhưng khi bạn làm điều này:

revSTR( arr + 2, len );

Bạn nhận được:

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

Và điều này xảy ra bởi vì trong mã đầu tiên, độ dài của arrđược kiểm tra bên trong revSTR()là tốt, nhưng trong mã thứ hai nơi bạn vượt qua độ dài:

revSTR( arr + 2, len );

Độ dài bây giờ dài hơn độ dài thực sự bạn vượt qua khi bạn nói arr + 2.

Độ dài của strlen ( arr + 2 )! = strlen ( arr ).


1
Tôi thích ví dụ này vì nó không dựa trên các chức năng thư viện tiêu chuẩn như getsscrcpy. Tôi tự hỏi nếu chúng ta có thể giảm thiểu nếu hơn nữa. Tôi ít nhất sẽ thoát khỏi string.hvới size_t len = sizeof( arr );. Đã thử nghiệm trên gcc 6.4, Ubuntu 16.04. Tôi cũng sẽ đưa ra ví dụ thất bại với việc arr + 2giảm thiểu dán sao chép.
Ciro Santilli 郝海东 冠状 病 事件

1

Ngăn xếp tham nhũng vô dụng gây ra bởi tràn bộ đệm. Bạn có thể phòng thủ chống lại chúng bằng cách lập trình phòng thủ.

Bất cứ khi nào bạn truy cập vào một mảng, đặt một xác nhận trước nó để đảm bảo quyền truy cập không nằm ngoài giới hạn. Ví dụ:

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

Điều này khiến bạn suy nghĩ về giới hạn mảng và cũng khiến bạn suy nghĩ về việc thêm các bài kiểm tra để kích hoạt chúng nếu có thể. Nếu một số khẳng định này có thể thất bại trong quá trình sử dụng bình thường, hãy biến chúng thành bình thường if.


0

Tôi đã gặp lỗi này trong khi sử dụng malloc () để cấp phát một số bộ nhớ cho struct * sau khi sử dụng một số mã gỡ lỗi này, cuối cùng tôi đã sử dụng hàm free () để giải phóng bộ nhớ được phân bổ và sau đó thông báo lỗi đã biến mất :)


0

Một nguồn khác của việc đập ngăn xếp là (không chính xác) sử dụng vfork()thay vìfork() .

Tôi vừa gỡ lỗi một trường hợp này, trong đó tiến trình con không thể execve()thực thi đích và trả về mã lỗi thay vì gọi_exit() .

Bởi vì vfork() đã sinh ra đứa trẻ đó, nó đã quay trở lại trong khi thực sự vẫn đang thực thi trong không gian quy trình của cha mẹ, không chỉ làm hỏng ngăn xếp của cha mẹ mà còn khiến hai bộ chẩn đoán khác nhau được in bằng mã "xuôi dòng".

Thay đổi vfork()để fork()sửa cả hai vấn đề, cũng như thay đổi returntuyên bố của trẻ thành_exit() thay thế.

Nhưng vì mã con đi trước execve()cuộc gọi với các cuộc gọi đến các thói quen khác (để đặt uid / gid, trong trường hợp cụ thể này), về mặt kỹ thuật, nó không đáp ứng các yêu cầu vfork(), vì vậy thay đổi nó để sử dụngfork() là chính xác ở đây.

(Lưu ý rằng returncâu lệnh có vấn đề không thực sự được mã hóa như vậy - thay vào đó, một macro được gọi và macro đó đã quyết định xem có _exit()hay không returndựa trên một biến toàn cục. Vì vậy, rõ ràng mã con không phù hợp vớivfork() Cách sử dụng. )

Để biết thêm thông tin, xem:

Sự khác biệt giữa fork (), vfork (), exec () và clone ()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.