This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c/54017] New: Incorrect implementation of infinite loops in OpenMP sections leads to SIGILL


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54017

             Bug #: 54017
           Summary: Incorrect implementation of infinite loops in OpenMP
                    sections leads to SIGILL
    Classification: Unclassified
           Product: gcc
           Version: 4.7.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned@gcc.gnu.org
        ReportedBy: iliev@rz.rwth-aachen.de


Consider this very simple OpenMP sections code:

int main()
{
    #pragma omp parallel sections
    {
        #pragma omp section
        {
            for(;1;) {}
        }
    }
    return 0;
}

Since there is only one OpenMP section, if this code is run with more than one
thread, GOMP_sections_start() would return 0 in all but the first thread to
call it. Unfortunately the compiler generates the following assembly code to
test the return value:

        movl    $1, %edi
        call    GOMP_sections_start
        cmpl    $1, %eax
        je      .L4
                .value  0x0b0f
.L4:
        jmp     .L4

In all threads but the first one the JE instruction would not branch and the
UD2 instruction emitted by __builtin_trap() would get hit and the program will
abort with SIGILL. Tested also with "for(;;) {}" and "while(1) {}" - same
assembly code emitted.

If instead the code of the section is modified to read:

    #pragma omp section
    {
        int i = 1;
        for(;i;) {}
    }

the produced assembly code correctly handles 0 as the possible return value of 
GOMP_sections_next():

        call    GOMP_sections_next
.L7:
        testl   %eax, %eax
        je      .L4
        cmpl    $1, %eax
        je      .L5
                .value  0x0b0f
.L4:
        call    GOMP_sections_end_nowait
        jmp     .L8
.L5:
        movl    $1, -4(%rbp)
.L6:
        cmpl    $0, -4(%rbp)
        jne     .L6
        call    GOMP_sections_next
        jmp     .L7
.L8:
        leave

Also if at least one another section without infinite loop is added, e.g.:

    #pragma omp section
    {
        for(;1;) {}
    }
    #pragma omp section
    {
        int k = 5;
    }

return value from GOMP_sections_next() is processed correctly:

        call    GOMP_sections_next
.L8:
        cmpl    $1, %eax
        je      .L6
        cmpl    $1, %eax
        jb      .L5
        cmpl    $2, %eax
        je      .L7
                .value  0x0b0f
.L5:
        call    GOMP_sections_end_nowait
        jmp     .L9
.L7:
        movl    $5, -4(%rbp)
        call    GOMP_sections_next
        jmp     .L8
.L6:
        jmp     .L6
.L9:
        leave

The correct behaviour in the first case should be that other threads would wait
infinitely at the barrier in GOMP_parallel_end() and not crash with SIGILL as
in the first case.

Unfortunately I don't have access to GCC versions higher than 4.7.0 but I've
tested it with previous versions down to 4.3.4 with the same result.
Optimisation level has no influence on the problem. It also fails in 32-bit
mode.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]