summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Johnson <peter@tortall.net>2011-07-10 23:44:18 -0700
committerPeter Johnson <peter@tortall.net>2011-07-10 23:44:18 -0700
commitbd8401d5381bd47d61b901e7e7d111348db66cea (patch)
treecdc6b29de2d0dbbd69bbfd83c6f1f533a9bacdde
parent3b65acb39d1eae22ecaf9f4286b9ea0f9a6fae93 (diff)
downloadyasm-bd8401d5381bd47d61b901e7e7d111348db66cea.tar.gz
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]
-rw-r--r--libyasm/expr.c37
-rw-r--r--libyasm/tests/Makefile.inc2
-rw-r--r--libyasm/tests/expr-simplify-identity.asm4
-rw-r--r--libyasm/tests/expr-simplify-identity.hex13
4 files changed, 38 insertions, 18 deletions
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; i<e->numterms; 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