changeset 437:3f48bed56ab4

Fix bug in ||, &&, ! (save registers through jumps), grischka-2005-09-25 case_2 This saves registers through jumps with ||, &&, and !. This patch was originally posted in grischka's 2005-09-25 email as "required fix" case_2 to compile gcc 2.95. It was tweaked by David A. Wheeler to merge the test case into the standard tcc test suite. The original test case only tested || (case 2.1) and ! (case 2.2); Wheeler added the test cases for && (which happens to completely crash the unpatched compiler at compiler time - pretty solid evidence of a problem in the unpatched program!).
author Rob Landley <rob@landley.net>
date Thu, 03 May 2007 13:08:53 -0400
parents 91152e505b77
children 31171653b1ee
files tcc.c tests/tcctest.c
diffstat 2 files changed, 28 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/tcc.c	Thu May 03 12:10:26 2007 -0400
+++ b/tcc.c	Thu May 03 13:08:53 2007 -0400
@@ -6486,8 +6486,10 @@
             vtop->c.i = !vtop->c.i;
         else if ((vtop->r & VT_VALMASK) == VT_CMP)
             vtop->c.i = vtop->c.i ^ 1;
-        else
+        else {
+            save_regs(1);
             vseti(VT_JMP, gtst(1, 0));
+        }
         break;
     case '~':
         next();
@@ -6900,6 +6902,7 @@
     expr_or();
     if (tok == TOK_LAND) {
         t = 0;
+        save_regs(1);
         for(;;) {
             t = gtst(1, t);
             if (tok != TOK_LAND) {
@@ -6919,6 +6922,7 @@
     expr_land();
     if (tok == TOK_LOR) {
         t = 0;
+        save_regs(1);
         for(;;) {
             t = gtst(0, t);
             if (tok != TOK_LOR) {
--- a/tests/tcctest.c	Thu May 03 12:10:26 2007 -0400
+++ b/tests/tcctest.c	Thu May 03 13:08:53 2007 -0400
@@ -646,6 +646,29 @@
            isid('g'), 
            isid('T'), 
            isid('('));
+
+    {
+        /* Check that tcc saves registers before a conditional jump */
+        /* Addresses bug "grischka case_2" */
+        struct test_str { int a, b, c; };
+        struct test_str t1 = {0,0,0};
+        struct test_str t2 = {1,1,1};
+        struct test_str *p1 = &t1;
+        struct test_str *p2 = &t2;
+        int f = 0;
+        int g = 0;
+
+        p1->b = f==0 || isid(0);
+        printf("case_2.1: Expect 0 1 0 -> %d %d %d\n", p1->a, p1->b, p1->c);
+        p1->c = !f || isid(0);
+        printf("case_2.2: Expect 0 1 1 -> %d %d %d\n", p1->a, p1->b, p1->c);
+
+        /* This will crash old versions of tcc during compilation: */
+        p2->b = (f==1) && isid(0);
+        printf("case_2.1AND: Expect 0 1 0 -> %d %d %d\n", p2->a, p2->b, p2->c);
+        p2->b = (!(f==1)) && isid(0);
+        printf("case_2.2AND: Expect 0 1 0 -> %d %d %d\n", p2->a, p2->b, p2->c);
+    }
 }
 
 int isid(int c)