From bd8401d5381bd47d61b901e7e7d111348db66cea Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 10 Jul 2011 23:44:18 -0700 Subject: [PATCH] expr_simplify_identity: Pass int_term via pointer. This allows signaling to the caller (expr_level_op) that the int_term was destroyed. Without this, the new expr-simplify-identity testcase has a use-after-free. [#232 state:resolved] --- libyasm/expr.c | 37 ++++++++++++------------ libyasm/tests/Makefile.inc | 2 ++ libyasm/tests/expr-simplify-identity.asm | 4 +++ libyasm/tests/expr-simplify-identity.hex | 13 +++++++++ 4 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 libyasm/tests/expr-simplify-identity.asm create mode 100644 libyasm/tests/expr-simplify-identity.hex diff --git a/libyasm/expr.c b/libyasm/expr.c index a067229b..0c777403 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -535,7 +535,7 @@ expr_can_destroy_int_right(yasm_expr_op op, yasm_intnum *intn) * NOTE: Really designed to only be used by expr_level_op(). */ static int -expr_simplify_identity(yasm_expr *e, int numterms, int int_term, +expr_simplify_identity(yasm_expr *e, int numterms, int *int_term, int simplify_reg_mul) { int i; @@ -547,26 +547,27 @@ expr_simplify_identity(yasm_expr *e, int numterms, int int_term, save_numterms = e->numterms; e->numterms = numterms; if (simplify_reg_mul || e->op != YASM_EXPR_MUL - || !yasm_intnum_is_pos1(e->terms[int_term].data.intn) + || !yasm_intnum_is_pos1(e->terms[*int_term].data.intn) || !yasm_expr__contains(e, YASM_EXPR_REG)) { /* Check for simple identities that delete the intnum. * Don't delete if the intnum is the only thing in the expn. */ - if ((int_term == 0 && numterms > 1 && + if ((*int_term == 0 && numterms > 1 && expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) || - (int_term > 0 && - expr_can_destroy_int_right(e->op, e->terms[int_term].data.intn))) { + (*int_term > 0 && + expr_can_destroy_int_right(e->op, + e->terms[*int_term].data.intn))) { /* Delete the intnum */ - yasm_intnum_destroy(e->terms[int_term].data.intn); + yasm_intnum_destroy(e->terms[*int_term].data.intn); /* Slide everything to its right over by 1 */ - if (int_term != numterms-1) /* if it wasn't last.. */ - memmove(&e->terms[int_term], &e->terms[int_term+1], - (numterms-1-int_term)*sizeof(yasm_expr__item)); + if (*int_term != numterms-1) /* if it wasn't last.. */ + memmove(&e->terms[*int_term], &e->terms[*int_term+1], + (numterms-1-*int_term)*sizeof(yasm_expr__item)); /* Update numterms */ numterms--; - int_term = -1; /* no longer an int term */ + *int_term = -1; /* no longer an int term */ } } e->numterms = save_numterms; @@ -574,23 +575,23 @@ expr_simplify_identity(yasm_expr *e, int numterms, int int_term, /* Check for simple identites that delete everything BUT the intnum. * Don't bother if the intnum is the only thing in the expn. */ - if (numterms > 1 && int_term != -1 && - expr_is_constant(e->op, e->terms[int_term].data.intn)) { + if (numterms > 1 && *int_term != -1 && + expr_is_constant(e->op, e->terms[*int_term].data.intn)) { /* Loop through, deleting everything but the integer term */ for (i=0; inumterms; i++) - if (i != int_term) + if (i != *int_term) expr_delete_term(&e->terms[i], 1); /* Move integer term to the first term (if not already there) */ - if (int_term != 0) - e->terms[0] = e->terms[int_term]; /* structure copy */ + if (*int_term != 0) + e->terms[0] = e->terms[*int_term]; /* structure copy */ /* Set numterms to 1 */ numterms = 1; } /* Compute NOT, NEG, and LNOT on single intnum. */ - if (numterms == 1 && int_term == 0 && + if (numterms == 1 && *int_term == 0 && (e->op == YASM_EXPR_NOT || e->op == YASM_EXPR_NEG || e->op == YASM_EXPR_LNOT)) yasm_intnum_calc(e->terms[0].data.intn, e->op, NULL); @@ -698,7 +699,7 @@ expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const, int new_fold_numterms; /* Simplify identities and make IDENT if possible. */ new_fold_numterms = - expr_simplify_identity(e, fold_numterms, first_int_term, + expr_simplify_identity(e, fold_numterms, &first_int_term, simplify_reg_mul); level_numterms -= fold_numterms-new_fold_numterms; fold_numterms = new_fold_numterms; @@ -789,7 +790,7 @@ expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const, /* Simplify identities, make IDENT if possible, and save to e->numterms. */ if (simplify_ident && first_int_term != -1) { e->numterms = expr_simplify_identity(e, level_numterms, - first_int_term, simplify_reg_mul); + &first_int_term, simplify_reg_mul); } else { e->numterms = level_numterms; if (level_numterms == 1) diff --git a/libyasm/tests/Makefile.inc b/libyasm/tests/Makefile.inc index 005fbbc5..13460c01 100644 --- a/libyasm/tests/Makefile.inc +++ b/libyasm/tests/Makefile.inc @@ -25,6 +25,8 @@ EXTRA_DIST += libyasm/tests/equ-expand.asm EXTRA_DIST += libyasm/tests/equ-expand.hex EXTRA_DIST += libyasm/tests/expr-fold-level.asm EXTRA_DIST += libyasm/tests/expr-fold-level.hex +EXTRA_DIST += libyasm/tests/expr-simplify-identity.asm +EXTRA_DIST += libyasm/tests/expr-simplify-identity.hex EXTRA_DIST += libyasm/tests/expr-wide-ident.asm EXTRA_DIST += libyasm/tests/expr-wide-ident.hex EXTRA_DIST += libyasm/tests/externdef.asm diff --git a/libyasm/tests/expr-simplify-identity.asm b/libyasm/tests/expr-simplify-identity.asm new file mode 100644 index 00000000..cda9c3bb --- /dev/null +++ b/libyasm/tests/expr-simplify-identity.asm @@ -0,0 +1,4 @@ +d_key equ 0 +cachedata: DQ 0 +dtable: +cmp al, [esi + (dtable-cachedata) + ebx*4 + d_key] diff --git a/libyasm/tests/expr-simplify-identity.hex b/libyasm/tests/expr-simplify-identity.hex new file mode 100644 index 00000000..4a236bc5 --- /dev/null +++ b/libyasm/tests/expr-simplify-identity.hex @@ -0,0 +1,13 @@ +00 +00 +00 +00 +00 +00 +00 +00 +67 +3a +44 +9e +08 -- 2.40.0