diff options
author | Petr Machata <pmachata@redhat.com> | 2013-10-10 14:50:28 +0200 |
---|---|---|
committer | Petr Machata <pmachata@redhat.com> | 2013-10-10 14:50:28 +0200 |
commit | cd6ff36657ef51369f72fe109d581bc2530be5f2 (patch) | |
tree | cc8a38f4a7850767a1f9f5da6a3b2699a81d7e29 /expr.c | |
parent | 53a6c37fdb496674cf1fa70a04cc777414c4fe09 (diff) | |
download | ltrace-cd6ff36657ef51369f72fe109d581bc2530be5f2.tar.gz |
Add expr_clone, type_clone; call from value_clone
- This fixes several memory errors in trace_clone and hello_vfork test
cases.
Diffstat (limited to 'expr.c')
-rw-r--r-- | expr.c | 81 |
1 files changed, 80 insertions, 1 deletions
@@ -1,6 +1,6 @@ /* * This file is part of ltrace. - * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -171,6 +171,85 @@ expr_destroy(struct expr_node *node) abort(); } +static int +expr_alloc_and_clone(struct expr_node **retpp, struct expr_node *node, int own) +{ + *retpp = node; + if (own) { + *retpp = malloc(sizeof **retpp); + if (*retpp == NULL || expr_clone(*retpp, node) < 0) { + free(*retpp); + return -1; + } + } + return 0; +} + +int +expr_clone(struct expr_node *retp, const struct expr_node *node) +{ + *retp = *node; + + switch (node->kind) { + struct expr_node *nlhs; + struct expr_node *nrhs; + + case EXPR_OP_ARGNO: + case EXPR_OP_SELF: + return 0; + + case EXPR_OP_CONST: + return value_clone(&retp->u.value, &node->u.value); + + case EXPR_OP_NAMED: + if (node->u.name.own + && (retp->u.name.s = strdup(node->u.name.s)) == NULL) + return -1; + return 0; + + case EXPR_OP_INDEX: + if (expr_alloc_and_clone(&nlhs, node->lhs, node->own_lhs) < 0) + return -1; + + if (expr_alloc_and_clone(&nrhs, node->u.node.n, + node->u.node.own) < 0) { + if (nlhs != node->lhs) { + expr_destroy(nlhs); + free(nlhs); + } + return -1; + } + + retp->lhs = nlhs; + retp->u.node.n = nrhs; + return 0; + + case EXPR_OP_CALL2: + if (expr_alloc_and_clone(&nrhs, node->u.call.rhs, + node->u.call.own_rhs) < 0) + return -1; + retp->u.call.rhs = nrhs; + /* Fall through. */ + + case EXPR_OP_UP: + case EXPR_OP_CALL1: + if (expr_alloc_and_clone(&nlhs, node->lhs, node->own_lhs) < 0) { + if (node->kind == EXPR_OP_CALL2 + && node->u.call.own_rhs) { + expr_destroy(nrhs); + free(nrhs); + return -1; + } + } + + retp->lhs = nlhs; + return 0; + } + + assert(!"Invalid value of node kind"); + abort(); +} + int expr_is_compile_constant(struct expr_node *node) { |