~mcf/cproc#80: 
segfault when returning before a switch statement

The following code causes a segfault

void
foo(int n)
{
        return;

        switch (n) {
        case 0:
                break;
        }
}
$ cproc -o test.o -c test.c
cproc: compile: process signaled: Segmentation fault
cproc: codegen: process 24579 exited with status 1
cproc: assemble: process signaled: Terminated
$ valgrind --trace-children=yes cproc -o test.o -c test.c
...
==24591== Invalid read of size 4
==24591==    at 0x11E12F: emitvalue (qbe.c:1031)
==24591==    by 0x11E720: emitinst (qbe.c:1139)
==24591==    by 0x11ED14: emitfunc (qbe.c:1254)
==24591==    by 0x10E2FF: decl (decl.c:1001)
==24591==    by 0x1144BD: main (main.c:60)
==24591==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
Status
RESOLVED FIXED
Submitter
~lattis
Assigned to
No-one
Submitted
9 months ago
Updated
9 months ago
Labels
No labels applied.

~lattis 9 months ago

The code where I encountered this had the return; wrapped in a #ifdef so that the function became a noop under certain conditions.

~mcf REPORTED FIXED 9 months ago

This is a long-standing issue that stems from funcinst returning NULL when we haven't introduced a new QBE block, and we have already have a jump for the current block. The intent was to avoid generating unreachable code, but it causes problems when more control flow follows after the jump.

One fix could be to make stmt() split up parsing and code generation, and skip the latter if the current block is already terminated. However, the much simpler solution is just to insert a dummy block when we encounter this situation. QBE will discard unreachable blocks quite early in the pipeline, so I think that's what I'll do.

Fixed by 4fa48e716d6381e51ae8dc7a9992c4c7d50219a1.

Register here or Log in to comment, or comment via email.