https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91311

            Bug ID: 91311
           Summary: __attribute__ ((aligned (128))) results in
                    stack-use-after-scope and stack-buffer-overflow
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: sanitizer
          Assignee: unassigned at gcc dot gnu.org
          Reporter: Hi-Angel at yandex dot ru
                CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
                    jakub at gcc dot gnu.org, kcc at gcc dot gnu.org, marxin at 
gcc dot gnu.org
  Target Milestone: ---

This is sporadically (as in, ≈6/10) reproducible on 8.3.0, and not reproducible
on 7.4.0 and 9.1.0. Running the testcase sometimes results in
stack-buffer-overflow sanitizer report, othertimes it's stack-use-after-scope,
and sometimes code passes with no crashes and warnings.

This code is not so small (58 lines) because removing anything from it, or
trying to merge functions, results in getting less crashes or none at all.
Removing the `__attribute__ ((aligned (128)))` results in no crashes from 100
runs; and it's the only odd line of this code, so I suspect this is the
culprit.

Doing `export ASAN_OPTIONS=detect_stack_use_after_return=1` also seems to fix
that.

Despite the testcase being specific to 8.3.0, it seems likely that some similar
problem is present in at least older GCC versions as well. In a project I'm
working on, another developer, with 7.x.x GCC version, also had its share of
odd sanitizer crashes. It's possible, there's the same root reason.

Any suggestions or ideas for how to debug it are welcome.

# Steps to reproduce (in terms of terminal commands)

    $ cat asan_testcase.c
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>

    struct MyStruct1 {
        uint64_t ptr1;
        char a;
        uint64_t ptr2;
        char b;
    };

    typedef struct {
        const uint8_t *raw;
        uint64_t err_off;
    } MyStruct2 __attribute__ ((aligned (128)));



    void test_func() {
        struct MyStruct1 test;
        char* foo = (char*)&test;
        for (size_t i = 0; i < sizeof(struct MyStruct1); ++i)
            foo[i] = 0;
        printf("test addr: %p", &test);
        struct MyStruct1 test2 = {0};
        printf("test addr: %p", &test2);
        exit(0);
    }

    void my_bson_destroy(void *foo) {
    }

    void my_bson_iter_init_find(MyStruct2 *foo, void *bar, const void* p) {
    }

    void* my_bson_new_from_json(const void* p, int a, int b) {
        return 0;
    }

    static void test_func3() {
        void *bson_param = my_bson_new_from_json((const uint8_t*)"{}", -1, 0);
        do {
            MyStruct2 it;
            my_bson_iter_init_find(&it, bson_param, "");
        } while(0);
        my_bson_destroy(bson_param);
    }

    static void test_func2(const char* json_params) {
        test_func3();
        fputs("### rpc_operation_cud_obj called!\n", stderr);
        test_func();
    }

    static void test_func4() { test_func2(0); }
    static void* test_func5(void *arg) { test_func4(); abort(); }

    int main() {
        test_func5(0);
    }
    $ gcc -fsanitize=address -g3 -O0 -o asan_testcase asan_testcase.c
    $ for i in {1..100}; do ./asan_testcase; done

## Expected

Only output from the app, bunch of lines like:
    ### rpc_operation_cud_obj called!
    test addr: 0x7ffe31c987d0test addr: 0x7ffe31c98810%

## Actual

Aborts by address sanitizer: sometimes it's a stack-buffer-overflow:

    =================================================================
    ==819==ERROR: AddressSanitizer: stack-buffer-overflow on address
0x7fff118a9010 at pc 0x564fb240f2f6 bp 0x7fff118a8fd0 sp 0x7fff118a8fc0
    WRITE of size 1 at 0x7fff118a9010 thread T0
        #0 0x564fb240f2f5 in test_func ../iscsi/asan_testcase.c:23
        #1 0x564fb240f55c in test_func2 ../iscsi/asan_testcase.c:50
        #2 0x564fb240f56d in test_func4 ../iscsi/asan_testcase.c:53
        #3 0x564fb240f586 in test_func5 ../iscsi/asan_testcase.c:54
        #4 0x564fb240f59e in main ../iscsi/asan_testcase.c:57
        #5 0x7f1d87092ce2 in __libc_start_main (/usr/lib/libc.so.6+0x23ce2)
        #6 0x564fb240f13d in _start (/tmp/asan_testcase+0x113d)

    Address 0x7fff118a9010 is located in stack of thread T0 at offset 32 in
frame
        #0 0x564fb240f218 in test_func ../iscsi/asan_testcase.c:19

    This frame has 2 object(s):
        [32, 64) 'test' <== Memory access at offset 32 is inside this variable
        [96, 128) 'test2'
    HINT: this may be a false positive if your program uses some custom stack
unwind mechanism or swapcontext
        (longjmp and C++ exceptions *are* supported)
    SUMMARY: AddressSanitizer: stack-buffer-overflow
../iscsi/asan_testcase.c:23 in test_func
    Shadow bytes around the buggy address:
    0x10006230d1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d1c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d1d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d1e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d1f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
    =>0x10006230d200: f1 f1[f2]f2 00 00 f2 f2 f2 f2 00 00 00 00 f3 f3
    0x10006230d210: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x10006230d250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Shadow byte legend (one shadow byte represents 8 application bytes):
    Addressable:           00
    Partially addressable: 01 02 03 04 05 06 07
    Heap left redzone:       fa
    Freed heap region:       fd
    Stack left redzone:      f1
    Stack mid redzone:       f2
    Stack right redzone:     f3
    Stack after return:      f5
    Stack use after scope:   f8
    Global redzone:          f9
    Global init order:       f6
    Poisoned by user:        f7
    Container overflow:      fc
    Array cookie:            ac
    Intra object redzone:    bb
    ASan internal:           fe
    Left alloca redzone:     ca
    Right alloca redzone:    cb
    ==819==ABORTING

…othertimes it's a stack-use-after-scope:

    =================================================================
    ==822==ERROR: AddressSanitizer: stack-use-after-scope on address
0x7ffd32b5ca00 at pc 0x560f4f7a32f6 bp 0x7ffd32b5c9c0 sp 0x7ffd32b5c9b0
    WRITE of size 1 at 0x7ffd32b5ca00 thread T0
        #0 0x560f4f7a32f5 in test_func ../iscsi/asan_testcase.c:23
        #1 0x560f4f7a355c in test_func2 ../iscsi/asan_testcase.c:50
        #2 0x560f4f7a356d in test_func4 ../iscsi/asan_testcase.c:53
        #3 0x560f4f7a3586 in test_func5 ../iscsi/asan_testcase.c:54
        #4 0x560f4f7a359e in main ../iscsi/asan_testcase.c:57
        #5 0x7f9a0a1acce2 in __libc_start_main (/usr/lib/libc.so.6+0x23ce2)
        #6 0x560f4f7a313d in _start (/tmp/asan_testcase+0x113d)

    Address 0x7ffd32b5ca00 is located in stack of thread T0 at offset 32 in
frame
        #0 0x560f4f7a3218 in test_func ../iscsi/asan_testcase.c:19

    This frame has 2 object(s):
        [32, 64) 'test' <== Memory access at offset 32 is inside this variable
        [96, 128) 'test2'
    HINT: this may be a false positive if your program uses some custom stack
unwind mechanism or swapcontext
        (longjmp and C++ exceptions *are* supported)
    SUMMARY: AddressSanitizer: stack-use-after-scope
../iscsi/asan_testcase.c:23 in test_func
    Shadow bytes around the buggy address:
    0x1000265638f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563930: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
    =>0x100026563940:[f8]f8 f2 f2 f2 f2 f2 f2 00 00 00 00 f3 f3 f3 f3
    0x100026563950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x100026563990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Shadow byte legend (one shadow byte represents 8 application bytes):
    Addressable:           00
    Partially addressable: 01 02 03 04 05 06 07
    Heap left redzone:       fa
    Freed heap region:       fd
    Stack left redzone:      f1
    Stack mid redzone:       f2
    Stack right redzone:     f3
    Stack after return:      f5
    Stack use after scope:   f8
    Global redzone:          f9
    Global init order:       f6
    Poisoned by user:        f7
    Container overflow:      fc
    Array cookie:            ac
    Intra object redzone:    bb
    ASan internal:           fe
    Left alloca redzone:     ca
    Right alloca redzone:    cb
    ==822==ABORTING

Reply via email to