[hackers] [scc] [cc1] Fix use-affer-free bug in switches || Roberto E. Vargas Caballero

From: <git_AT_suckless.org>
Date: Mon, 2 May 2016 22:01:51 +0200 (CEST)

commit 8e8ce7a93939caeab7fc0e5e149470349746a43f
Author: Roberto E. Vargas Caballero <Roberto E. Vargas Caballero>
AuthorDate: Sun May 1 21:32:15 2016 +0200
Commit: Roberto E. Vargas Caballero <Roberto E. Vargas Caballero>
CommitDate: Sun May 1 21:32:15 2016 +0200

    [cc1] Fix use-affer-free bug in switches
    
    Switches build a list of cases which were emitted after the
    end of the switch statement, and since the switch statement is
    usually a compound statement, it meant that the symbols created
    in the cases were freed when they were emitted. To solve this
    problem this patch simplifies everything emitting the cases
    on the fly, letting the job of creating the switch table to the
    backend.

diff --git a/cc1/cc1.h b/cc1/cc1.h
index 8d135cb..a9fcfe2 100644
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
_AT_@ -10,7 +10,7 @@
  */
 typedef struct type Type;
 typedef struct symbol Symbol;
-typedef struct caselist Caselist;
+typedef struct swtch Switch;
 typedef struct node Node;
 typedef struct input Input;
 
_AT_@ -87,19 +87,9 @@ struct node {
         struct node *left, *right;
 };
 
-struct scase {
- Symbol *label;
- Node *expr;
- struct scase *next;
-};
-
-struct caselist {
+struct swtch {
         short nr;
- Symbol *deflabel;
- Symbol *ltable;
- Symbol *lbreak;
- Node *expr;
- struct scase *head;
+ char hasdef;
 };
 
 struct yystype {
_AT_@ -335,8 +325,8 @@ enum op {
         OCALL,
         ORET,
         ODECL,
- OSWITCH,
- OSWITCHT,
+ OBSWITCH,
+ OESWITCH,
         OINIT
 };
 
_AT_@ -368,7 +358,7 @@ extern void keywords(struct keyword *key, int ns);
 extern Symbol *newstring(char *s, size_t len);
 
 /* stmt.c */
-extern void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
+extern void compound(Symbol *lbreak, Symbol *lcont, Switch *sw);
 
 /* decl.c */
 extern Type *typename(void);
diff --git a/cc1/code.c b/cc1/code.c
index 5ee78b5..e140d56 100644
--- a/cc1/code.c
+++ b/cc1/code.c
_AT_@ -60,6 +60,8 @@ char *optxt[] = {
         [OCOMMA] = ",",
         [OLABEL] = "L%d\n",
         [ODEFAULT] = "\tf\tL%d\n",
+ [OBSWITCH] = "\ts",
+ [OESWITCH] = "\tk\n",
         [OCASE] = "\tv\tL%d",
         [OJUMP] = "\tj\tL%d\n",
         [OBRANCH] = "\ty\tL%d",
_AT_@ -126,8 +128,8 @@ void (*opcode[])(unsigned, void *) = {
         [OFUN] = emitfun,
         [ORET] = emittext,
         [ODECL] = emitdcl,
- [OSWITCH] = emitswitch,
- [OSWITCHT] = emitswitcht,
+ [OBSWITCH] = emittext,
+ [OESWITCH] = emittext,
         [OPAR] = emitbin,
         [OCALL] = emitbin,
         [OINIT] = emitinit
_AT_@ -457,32 +459,6 @@ emitsymid(unsigned op, void *arg)
         printf(optxt[op], sym->id);
 }
 
-static void
-emitswitch(unsigned op, void *arg)
-{
- Caselist *lcase = arg;
-
- printf("\ts\tL%u", lcase->ltable->id);
- emitexp(OEXPR, lcase->expr);
-}
-
-static void
-emitswitcht(unsigned op, void *arg)
-{
- Caselist *lcase = arg;
- struct scase *p, *next;
-
- printf("\tt\t#%c%0x\n", sizettype->letter, lcase->nr);
- for (p = lcase->head; p; p = next) {
- emitsymid(OCASE, p->label);
- emitexp(OEXPR, p->expr);
- next = p->next;
- free(p);
- }
- if (lcase->deflabel)
- emitsymid(ODEFAULT, lcase->deflabel);
-}
-
 Node *
 node(unsigned op, Type *tp, Node *lp, Node *rp)
 {
diff --git a/cc1/stmt.c b/cc1/stmt.c
index 4ad074c..e9f4b7f 100644
--- a/cc1/stmt.c
+++ b/cc1/stmt.c
_AT_@ -10,7 +10,7 @@
 
 Symbol *curfun;
 
-static void stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
+static void stmt(Symbol *lbreak, Symbol *lcont, Switch *lswitch);
 
 static void
 label(void)
_AT_@ -36,7 +36,7 @@ label(void)
 }
 
 static void
-stmtexp(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+stmtexp(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         if (accept(';'))
                 return;
_AT_@ -62,7 +62,7 @@ condition(void)
 }
 
 static void
-While(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+While(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         Symbol *begin, *cond, *end;
         Node *np;
_AT_@ -85,7 +85,7 @@ While(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-For(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+For(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         Symbol *begin, *cond, *end;
         Node *econd, *einc, *einit;
_AT_@ -117,7 +117,7 @@ For(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-Dowhile(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Dowhile(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         Symbol *begin, *end;
         Node *np;
_AT_@ -137,7 +137,7 @@ Dowhile(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-Return(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Return(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         Node *np;
         Type *tp = curfun->type->type;
_AT_@ -160,7 +160,7 @@ Return(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-Break(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Break(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         expect(BREAK);
         if (!lbreak) {
_AT_@ -172,7 +172,7 @@ Break(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-Continue(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Continue(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         expect(CONTINUE);
         if (!lcont) {
_AT_@ -184,7 +184,7 @@ Continue(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-Goto(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Goto(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         Symbol *sym;
 
_AT_@ -204,74 +204,70 @@ Goto(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-Switch(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Swtch(Symbol *obr, Symbol *lcont, Switch *osw)
 {
- Caselist lcase = {.nr = 0, .head = NULL, .deflabel = NULL};
+ Switch sw = {0};
         Node *cond;
+ Symbol *lbreak;
 
         expect(SWITCH);
- expect ('(');
 
+ expect ('(');
         if ((cond = convert(expr(), inttype, 0)) == NULL) {
                 errorp("incorrect type in switch statement");
                 cond = constnode(zero);
         }
         expect (')');
 
- lcase.expr = cond;
- lcase.lbreak = newlabel();
- lcase.ltable = newlabel();
-
- emit(OSWITCH, &lcase);
- stmt(lbreak, lcont, &lcase);
- emit(OJUMP, lcase.lbreak);
- emit(OLABEL, lcase.ltable);
- emit(OSWITCHT, &lcase);
- emit(OLABEL, lcase.lbreak);
+ lbreak = newlabel();
+ emit(OBSWITCH, NULL);
+ emit(OEXPR, cond);
+ stmt(lbreak, lcont, &sw);
+ emit(OESWITCH, NULL);
+ emit(OLABEL, lbreak);
 }
 
 static void
-Case(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Case(Symbol *lbreak, Symbol *lcont, Switch *sw)
 {
         Node *np;
- struct scase *pcase;
+ Symbol *label;
 
         expect(CASE);
- if (!lswitch)
- errorp("case label not within a switch statement");
         if ((np = iconstexpr()) == NULL)
                 errorp("case label does not reduce to an integer constant");
- expect(':');
- if (lswitch && lswitch->nr >= 0) {
- if (++lswitch->nr == NR_SWITCH) {
- errorp("too case labels for a switch statement");
- lswitch->nr = -1;
- } else {
- pcase = xmalloc(sizeof(*pcase));
- pcase->expr = np;
- pcase->next = lswitch->head;
- emit(OLABEL, pcase->label = newlabel());
- lswitch->head = pcase;
- }
+ if (!sw) {
+ errorp("case label not within a switch statement");
+ } else if (sw->nr >= 0 && ++sw->nr == NR_SWITCH) {
+ errorp("too case labels for a switch statement");
+ sw->nr = -1;
         }
- stmt(lbreak, lcont, lswitch);
+ expect(':');
+
+ label = newlabel();
+ emit(OCASE, label);
+ emit(OEXPR, np);
+ emit(OLABEL, label);
+ stmt(lbreak, lcont, sw);
 }
 
 static void
-Default(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+Default(Symbol *lbreak, Symbol *lcont, Switch *sw)
 {
- Symbol *ldefault = newlabel();
+ Symbol *label = newlabel();
 
+ if (sw->hasdef)
+ errorp("multiple default labels in one switch");
+ sw->hasdef = 1;
         expect(DEFAULT);
         expect(':');
- emit(OLABEL, ldefault);
- lswitch->deflabel = ldefault;
- ++lswitch->nr;
- stmt(lbreak, lcont, lswitch);
+ emit(ODEFAULT, label);
+ emit(OLABEL, label);
+ stmt(lbreak, lcont, sw);
 }
 
 static void
-If(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+If(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         Symbol *end, *lelse;
         Node *np;
_AT_@ -294,7 +290,7 @@ If(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-blockit(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+blockit(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         switch (yytoken) {
         case TYPEIDEN:
_AT_@ -313,7 +309,7 @@ blockit(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 void
-compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+compound(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
         static int nested;
 
_AT_@ -342,9 +338,9 @@ compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
 }
 
 static void
-stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
+stmt(Symbol *lbreak, Symbol *lcont, Switch *lswitch)
 {
- void (*fun)(Symbol *, Symbol *, Caselist *);
+ void (*fun)(Symbol *, Symbol *, Switch *);
 
         switch (yytoken) {
         case '{': fun = compound; break;
_AT_@ -356,7 +352,7 @@ stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
         case BREAK: fun = Break; break;
         case CONTINUE: fun = Continue; break;
         case GOTO: fun = Goto; break;
- case SWITCH: fun = Switch; break;
+ case SWITCH: fun = Swtch; break;
         case CASE: fun = Case; break;
         case DEFAULT: fun = Default; break;
         default: fun = stmtexp; break;
Received on Mon May 02 2016 - 22:01:51 CEST

This archive was generated by hypermail 2.3.0 : Mon May 02 2016 - 22:12:24 CEST