Bugzilla – Bug 124
[llvmg++] ?: expressions do not run correct number of destructors!
Last modified: 2003-11-25 20:46:02
You need to log in before you can comment on or make changes to this bug.
The webcpp bytecode (/home/vadve/criswell/Downloads/CXXCode/webcpp-0.8.0-src/webcpp/webcpp.bc) causes lli to segfault after the webcpp program has terminated. The program also segfaults when run through the CBE, but does not run through completion.
This sounds like a miscompilation of some sort. Just to be sure, please compile the program with a native compiler and valgrind the result. If that's happy, then try compiling without gccas/gccld. If that STILL doesn't work, it's a FE bug. Brian has some tasty scripts for narrowing bugs down to a single translation unit, you might ask him for them... -Chris
If you could, please look into this. This is the last LLVM-core 1.1 bug that I know of. Thanks, -Chris
Errr, not last, but close to last. :) -Chris
I've cut out a lot of the code in this program; it now only does C to HTML translations. It segfaults when run through the x86 JIT, but performs correctly via llc and the CBE. The JIT stack trace is as follows: #0 0x401857c3 in chunk_free () from /lib/libc.so.6 #1 0x40185548 in free () from /lib/libc.so.6 #2 0x400bee03 in operator delete(void*) (ptr=0x40230fa8) at /home/vadve/criswell/gcc/gcc33/gcc/libstdc++-v3/libsupc++/del_op.cc:39 #3 0x08282509 in ~Emitter (this=0x86b4d68) at iostream:123 #4 0x08281ce5 in ~VM (this=0x86b4ce0) at /home/vadve/criswell/llvm/lib/ExecutionEngine/JIT/VM.cpp:25 #5 0x0826a28a in main (argc=4, argv=0xbffff4d4, envp=0xbffff4e8) at /home/vadve/criswell/llvm/tools/lli/lli.cpp:167
Ok, try running the CBE generated code through valgrind. It looks like the program is trashing the malloc heap. If this is the case, the program is buggy and it is just LUCKY to work with the non-jit configurations. -Chris
Reduced the bug to the following (thanks Chris!): #include <string> using namespace std; string Picture ="\0"; string Data () { string CSS; string John="\0"; CSS = ( (John == "\0") ? "\n}\n\n": ";\nbackground-image: url(\"" + Picture + "\");\nbackground-attachment: fixed\n}\n\n" ); return CSS; } int main (int argc, char ** argv) { Data (); return 0; }
I've reduced this problem to this testcase: #include <stdio.h> static int X = 0; struct T { int V; T() : V(++X) { printf("Construct %d\n", V); } T(const T &) : V(++X) { printf("Copy Construct %d\n", V); } ~T() { printf("Destruct %d\n", V); } void operator=(const T &t) { printf("Overwrite %d with %d\n", V, t.V); V = t.V; } }; T func(const T &t) { return T(); } T test(bool C) { return C ? T() : func(T()); } int main() { T x; x = test(true); return 0; }
Fixed. Testcase: test/Programs/SingleSource/Regression/C++/EH/ConditionalExpr.cpp The patch: $ diff -u llvm-expand.c~ llvm-expand.c --- llvm-expand.c~ 2003-11-25 19:13:56.000000000 -0600 +++ llvm-expand.c 2003-11-25 20:43:57.000000000 -0600 @@ -4847,9 +4847,6 @@ break; case COND_EXPR: { /* ?: expression */ - /* FIXME: This does not correctly conditionalize CLEANUP expressions because - no scopes are created!!! */ - /* Allocate a new temporary to hold the result of the expression */ llvm_basicblock *TrueBlock = llvm_basicblock_new("cond_true"); llvm_basicblock *FalseBlock = llvm_basicblock_new("cond_false"); @@ -4866,6 +4863,9 @@ /* Add the true block as the fall through */ llvm_ilist_push_back(llvm_basicblock, Fn->BasicBlocks, TrueBlock); + /* Start a region for the conditional expression destructors */ + llvm_expand_start_bindings(Fn); + /* One branch of the cond can be void, if it never returns. For example A ? throw : E */ if (TREE_TYPE(TREE_OPERAND(exp, 1)) != void_type_node) { @@ -4879,12 +4879,18 @@ llvm_expand_expr(Fn, TREE_OPERAND (exp, 1), 0); } + /* Stop the scope */ + llvm_expand_end_bindings(Fn, NULL_TREE); + /* Branch to the mainline computation */ append_inst(Fn, create_uncond_branch(ContinueBlock)); /* Add the false block next */ llvm_ilist_push_back(llvm_basicblock, Fn->BasicBlocks, FalseBlock); + /* Start a region for the conditional expression destructors */ + llvm_expand_start_bindings(Fn); + /* One branch of the cond can be void, if it never returns. For example A ? throw : E */ if (TREE_TYPE(TREE_OPERAND(exp, 2)) != void_type_node) { @@ -4898,6 +4904,9 @@ llvm_expand_expr(Fn, TREE_OPERAND (exp, 2), 0); } + /* Stop the scope */ + llvm_expand_end_bindings(Fn, NULL_TREE); + /* Add the branch and continue block */ llvm_emit_label(Fn, ContinueBlock); @@ -5508,9 +5517,6 @@ break; } case COND_EXPR: { /* ?: expression */ - /* FIXME: This does not correctly conditionalize CLEANUP expressions because - no scopes are created!!! */ - /* Allocate a new temporary to hold the result of the expression */ llvm_basicblock *TrueBlock = llvm_basicblock_new("cond_true"); llvm_basicblock *FalseBlock = llvm_basicblock_new("cond_false"); @@ -5529,6 +5535,9 @@ /* Add the true block as the fall through */ llvm_ilist_push_back(llvm_basicblock, Fn->BasicBlocks, TrueBlock); + /* Start a region for the conditional expression destructors */ + llvm_expand_start_bindings(Fn); + /* One branch of the cond can be void, if it never returns. For example A ? throw : E */ if (Result && TREE_TYPE(TREE_OPERAND(exp, 1)) != void_type_node) @@ -5536,17 +5545,26 @@ else llvm_expand_expr(Fn, TREE_OPERAND (exp, 1), 0); + /* Stop the scope */ + llvm_expand_end_bindings(Fn, NULL_TREE); + /* Branch to the mainline computation */ append_inst(Fn, create_uncond_branch(ContinueBlock)); /* Add the false block next */ llvm_ilist_push_back(llvm_basicblock, Fn->BasicBlocks, FalseBlock); + /* Start a region for the conditional expression destructors */ + llvm_expand_start_bindings(Fn); + if (Result && TREE_TYPE(TREE_OPERAND(exp, 2)) != void_type_node) llvm_store_expr(Fn, TREE_OPERAND(exp, 2), Result, 0, 0, 0, 0); else llvm_expand_expr(Fn, TREE_OPERAND (exp, 2), 0); + /* Stop the scope */ + llvm_expand_end_bindings(Fn, NULL_TREE); + /* Add the branch and continue block */ llvm_emit_label(Fn, ContinueBlock);