tinycc-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Tinycc-devel] Seeking help to finish debugging a crash


From: John Scott
Subject: [Tinycc-devel] Seeking help to finish debugging a crash
Date: Sun, 18 Oct 2020 19:55:43 -0400

Hello,

I've pushed a couple miniscule commits to mob and would like to work up to more 
complex tasks. I've reported more issues than I've fixed and would like to turn 
that around 😀

I'm two-thirds of the way debugging this NULL pointer dereference in *cur_scope 
I found fuzzing with afl++. The minimal test case is
n[sizeof({

It may not crash outright unless you use -fstack-protector (ProPolice), which 
is enabled on Debian's package for example. Bisecting (0.9.27 was in the clear) 
I found this is the responsible commit:
commit 4a70b2bc2d080baa4082d9d902f9172f88021019
Author: Michael Matz <matz@suse.de>
Date:   Wed Jan 15 23:32:40 2020 +0100

    Fix handling of unevaluated subexpression of const

    we were emitting error messages for something like
    'static int i = 2 || 1/0', even though the exception would be in
    the unevaluated part.  This doesn't destroy const-ness, so we must
    accept it.  This requires splitting the nocode_wanted values a bit more,
    so that nocode_wanted due to const_wanted can be differentiated from
    nocode_wanted due to non-evaluation.
 tccgen.c                                   |  9 +++++----

Here's a portion of the non-test-suite changes that are pertinent:

@@ -53,6 +53,7 @@ static SValue _vstack[1 + VSTACK_SIZE];
 ST_DATA int nocode_wanted; /* no code generation wanted */
+#define unevalmask 0xffff /* unevaluated subexpression */
 #define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted 
either */
 #define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data 
output */

@@ -5104,7 +5105,7 @@ ST_FUNC void unary(void)
             }
         } else if (tok == '{') {
            int saved_nocode_wanted = nocode_wanted;
-            if (const_wanted)
+            if (const_wanted && !(nocode_wanted & unevalmask))
                 tcc_error("expected constant");
             /* save all registers */
             save_regs(0);
@@ -6152,9 +6153,9 @@ ST_FUNC void gexpr(void)
 static void expr_const1(void)
 {
     const_wanted++;
-    nocode_wanted++;
+    nocode_wanted += unevalmask + 1;
     expr_cond();
-    nocode_wanted--;
+    nocode_wanted -= unevalmask + 1;

Notice how the change in unary() pertains to the '{' character. Commenting out 
the '&& !(nocode_wanted & unevalmask)' check is sufficient to fix this, but 
surely it was put there for a reason.

Anyway, unary() doesn't stop the bad input right away and hands the input off 
to block():
} else if (t == '{') {
        struct scope o;
        new_scope(&o);

The NULL pointer dereference happens in new_scope() right here (I put the 
following assertion myself which fails even without ProPolice)
void new_scope(struct scope *o)
{   
    /* copy and link previous scope */
    assert(cur_scope != NULL);
    *o = *cur_scope;

Here's a backtrace excerpt:
#5  new_scope (o=<optimized out>) at tccgen.c:6425
#6  0x000055555556affa in block (is_expr=is_expr@entry=1) at tccgen.c:6538
#7  0x000055555556ccae in unary () at tccgen.c:5117

I think most variable names aren't very descriptive however and `bt full` looks 
like alphabet soup, so I guess cur_scope is probably uninitialized but this is 
as far as I've got. If someone could nudge me along or feels like finishing the 
job, either would be great.

Sincerely,
John

Attachment: signature.asc
Description: This is a digitally signed message part.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]