Hi Arnold and tcc folks,

Perhaps surprisingly, correcting this bug is quite costly.
Here is a tentative patch. I find it messy but working with dynamic data
and passing the cases to the block function are necessary to handle
an "unlimited number" of cases and nested switch blocks.

Also, since the 'block' function is starting to have too many arguments, I
suggest to create a structure that assembles related arguments such
that def_sym, case_sym, cases, and cases_cnt, and any other...

Does that sound ok?

Regards,
Amine


On Thu, Mar 10, 2016 at 2:41 PM, <arn...@skeeve.com> wrote:

> Hi All.
>
> On the latest mob:
>
> $ cat foo.c
> int main(int argc, char**argv)
> {
>         int a;
>
>         switch (a) {
>         case 1:
>         case 2:
>                 break;
>         case 3:
>                 break;
>         case 1:
>                 break;
>         default:
>                 break;
>         }
>
>         return 0;
> }
> $ PATH=/tmp/tcc/bin:$PATH tcc foo.c
> $
>
> $ gcc foo.c -o foo
> foo.c: In function ‘main’:
> foo.c:11:2: error: duplicate case value
>   case 1:
>   ^
> foo.c:6:2: error: previously used here
>   case 1:
>   ^
>
> This is pretty serious....
>
> Thanks,
>
> Arnold
>
> _______________________________________________
> Tinycc-devel mailing list
> Tinycc-devel@nongnu.org
> https://lists.nongnu.org/mailman/listinfo/tinycc-devel
>
From 70364d9a8d1c57da490e0187421ae94af42bf579 Mon Sep 17 00:00:00 2001
From: Amine Najahi <mohami...@gmail.com>
Date: Fri, 11 Mar 2016 17:54:11 +0100
Subject: [PATCH] Fix duplicate case values bug.

---
 tccgen.c | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/tccgen.c b/tccgen.c
index 3cd28ed..ef4b2e6 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -80,7 +80,7 @@ static int parse_btype(CType *type, AttributeDef *ad);
 static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
 static void parse_expr_type(CType *type);
 static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
-static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg, int is_expr);
+static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg, int is_expr, void*** cases, int* cases_cnt);
 static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
 static int decl0(int l, int is_for_loop_init);
 static void expr_eq(void);
@@ -3848,7 +3848,7 @@ ST_FUNC void unary(void)
             save_regs(0); 
             /* statement expression : we do not accept break/continue
                inside as GCC does */
-            block(NULL, NULL, NULL, NULL, 0, 1);
+            block(NULL, NULL, NULL, NULL, 0, 1, NULL, 0);
             skip(')');
         } else {
             gexpr();
@@ -4816,7 +4816,7 @@ static void label_or_decl(int l)
 }
 
 static void block(int *bsym, int *csym, int *case_sym, int *def_sym, 
-                  int case_reg, int is_expr)
+                  int case_reg, int is_expr, void*** cases, int* cases_cnt)
 {
     int a, b, c, d;
     Sym *s, *frame_bottom;
@@ -4842,13 +4842,13 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
         gexpr();
         skip(')');
         a = gvtst(1, 0);
-        block(bsym, csym, case_sym, def_sym, case_reg, 0);
+        block(bsym, csym, case_sym, def_sym, case_reg, 0, cases, cases_cnt);
         c = tok;
         if (c == TOK_ELSE) {
             next();
             d = gjmp(0);
             gsym(a);
-            block(bsym, csym, case_sym, def_sym, case_reg, 0);
+            block(bsym, csym, case_sym, def_sym, case_reg, 0, cases, cases_cnt);
             gsym(d); /* patch else jmp */
         } else
             gsym(a);
@@ -4861,7 +4861,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
         skip(')');
         a = gvtst(1, 0);
         b = 0;
-        block(&a, &b, case_sym, def_sym, case_reg, 0);
+        block(&a, &b, case_sym, def_sym, case_reg, 0, cases, cases_cnt);
         gjmp_addr(d);
         gsym(a);
         gsym_addr(b, d);
@@ -4898,7 +4898,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
             if (tok != '}') {
                 if (is_expr)
                     vpop();
-                block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
+                block(bsym, csym, case_sym, def_sym, case_reg, is_expr, cases, cases_cnt);
             }
         }
         /* pop locally defined labels */
@@ -5053,7 +5053,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
             gsym(e);
         }
         skip(')');
-        block(&a, &b, case_sym, def_sym, case_reg, 0);
+        block(&a, &b, case_sym, def_sym, case_reg, 0, cases, cases_cnt);
         gjmp_addr(c);
         gsym(a);
         gsym_addr(b, c);
@@ -5066,7 +5066,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
         b = 0;
         d = ind;
         vla_sp_restore();
-        block(&a, &b, case_sym, def_sym, case_reg, 0);
+        block(&a, &b, case_sym, def_sym, case_reg, 0, cases, cases_cnt);
         skip(TOK_WHILE);
         skip('(');
         gsym(b);
@@ -5078,6 +5078,8 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
         skip(';');
     } else
     if (tok == TOK_SWITCH) {
+        void** new_cases = NULL;
+        int new_cases_cnt = 0;
         next();
         skip('(');
         gexpr();
@@ -5088,7 +5090,8 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
         a = 0;
         b = gjmp(0); /* jump to first case */
         c = 0;
-        block(&a, csym, &b, &c, case_reg, 0);
+        block(&a, csym, &b, &c, case_reg, 0, &new_cases, &new_cases_cnt);
+        dynarray_reset(&new_cases, &new_cases_cnt);
         /* if no default, jmp after switch */
         if (c == 0)
             c = ind;
@@ -5098,11 +5101,18 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
         gsym(a);
     } else
     if (tok == TOK_CASE) {
-        int v1, v2;
+        int i, v1, v2, *case_value;
+        void** pp;
         if (!case_sym)
             expect("switch");
         next();
         v1 = expr_const();
+        for (i = 0, pp=*cases; i < *cases_cnt; ++i, ++pp)
+          if (v1 == **(int **) pp)
+            tcc_error("duplicate case value '%d'", v1);
+        case_value = tcc_malloc ( sizeof ( int ) );
+        *case_value = v1;
+        dynarray_add(cases, cases_cnt, case_value);
         v2 = v1;
         if (gnu_ext && tok == TOK_DOTS) {
             next();
@@ -5197,7 +5207,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
             } else {
                 if (is_expr)
                     vpop();
-                block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
+                block(bsym, csym, case_sym, def_sym, case_reg, is_expr, cases, cases_cnt);
             }
         } else {
             /* expression case */
@@ -6105,7 +6115,7 @@ static void gen_function(Sym *sym)
     }
 #endif
     rsym = 0;
-    block(NULL, NULL, NULL, NULL, 0, 0);
+    block(NULL, NULL, NULL, NULL, 0, 0, NULL, 0);
     gsym(rsym);
     gfunc_epilog();
     cur_text_section->data_offset = ind;
-- 
2.7.0

_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to