aboutsummaryrefslogtreecommitdiff
path: root/expr.c
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2013-10-10 14:50:28 +0200
committerPetr Machata <pmachata@redhat.com>2013-10-10 14:50:28 +0200
commitcd6ff36657ef51369f72fe109d581bc2530be5f2 (patch)
treecc8a38f4a7850767a1f9f5da6a3b2699a81d7e29 /expr.c
parent53a6c37fdb496674cf1fa70a04cc777414c4fe09 (diff)
downloadltrace-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.c81
1 files changed, 80 insertions, 1 deletions
diff --git a/expr.c b/expr.c
index 552a53c..4059a32 100644
--- a/expr.c
+++ b/expr.c
@@ -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)
{