llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.45k stars 11.76k forks source link

Incorrect eh context when throwing expression, which throws exception itself #14549

Open alexey-bataev opened 11 years ago

alexey-bataev commented 11 years ago
Bugzilla Link 14177
Version trunk
OS MacOS X
CC @DougGregor

Extended Description

The following simple test should terminate (calling std::terminate), but it catches the exception thrown in the copy constructor due to incorrect code generated by clang:

include

struct C { C() { } C(const C&) { throw 0; } };

int main() { try { C cc; throw cc; // should call std::terminate() } catch(int) {puts("caught int");} catch(C) {puts("caught C");} }

Here is llvm bitcode corresponding to throwing exception:

invoke.cont: ; preds = %entry %exception = call i8 @​__cxa_allocate_exception(i64 1) nounwind %2 = bitcast i8 %exception to %struct.C invoke void @​ZN1CC1ERKS(%struct.C %2, %struct.C* %cc) to label %invoke.cont2 unwind label %lpad1

invoke.cont2: ; preds = %invoke.cont invoke void @​__cxa_throw(i8 %exception, i8 bitcast ({ i8, i8 } @​_ZTI1C to i8), i8* null) noreturn to label %unreachable unwind label %lpad

lpad: ; preds = %invoke.cont2, %entry %3 = landingpad { i8, i32 } personality i8 bitcast (i32 (...) @​__gxx_personality_v0 to i8) catch i8* bitcast (i8 @​_ZTIi to i8) catch i8 bitcast ({ i8, i8 } @​_ZTI1C to i8) %4 = extractvalue { i8, i32 } %3, 0 store i8 %4, i8 %exn.slot %5 = extractvalue { i8, i32 } %3, 1 store i32 %5, i32 %ehselector.slot br label %catch.dispatch

lpad1: ; preds = %invoke.cont %6 = landingpad { i8, i32 } personality i8 bitcast (i32 (...) @​__gxx_personality_v0 to i8) cleanup catch i8* bitcast (i8 @​_ZTIi to i8) catch i8 bitcast ({ i8, i8 } @​_ZTI1C to i8) %7 = extractvalue { i8, i32 } %6, 0 store i8 %7, i8 %exn.slot %8 = extractvalue { i8, i32 } %6, 1 store i32 %8, i32 %ehselector.slot call void @​__cxa_free_exception(i8* %exception) nounwind br label %catch.dispatch

A call to copy constructor should be in a terminate context, but it's not (unwind edge points to the incorrect landingpad %lpad1).

Alexey Bataev Software Engineer Intel Compiler Team Intel Corp.

Endilll commented 1 year ago

Still reproduces as of post-17 trunk: https://godbolt.org/z/Y6G6oY9KW

llvmbot commented 1 year ago

@llvm/issue-subscribers-clang-codegen

| | | | --- | --- | | Bugzilla Link | [14177](https://llvm.org/bz14177) | | Version | trunk | | OS | MacOS X | | CC | @DougGregor | ## Extended Description The following simple test should terminate (calling std::terminate), but it catches the exception thrown in the copy constructor due to incorrect code generated by clang: #include struct C { C() { } C(const C&) { throw 0; } }; int main() { try { C cc; throw cc; // should call std::terminate() } catch(int) {puts("caught int");} catch(C) {puts("caught C");} } Here is llvm bitcode corresponding to throwing exception: invoke.cont: ; preds = %entry %exception = call i8* @​__cxa_allocate_exception(i64 1) nounwind %2 = bitcast i8* %exception to %struct.C* invoke void @​_ZN1CC1ERKS_(%struct.C* %2, %struct.C* %cc) to label %invoke.cont2 unwind label %lpad1 invoke.cont2: ; preds = %invoke.cont invoke void @​__cxa_throw(i8* %exception, i8* bitcast ({ i8*, i8* }* @​_ZTI1C to i8*), i8* null) noreturn to label %unreachable unwind label %lpad lpad: ; preds = %invoke.cont2, %entry %3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @​__gxx_personality_v0 to i8*) catch i8* bitcast (i8** @​_ZTIi to i8*) catch i8* bitcast ({ i8*, i8* }* @​_ZTI1C to i8*) %4 = extractvalue { i8*, i32 } %3, 0 store i8* %4, i8** %exn.slot %5 = extractvalue { i8*, i32 } %3, 1 store i32 %5, i32* %ehselector.slot br label %catch.dispatch lpad1: ; preds = %invoke.cont %6 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @​__gxx_personality_v0 to i8*) cleanup catch i8* bitcast (i8** @​_ZTIi to i8*) catch i8* bitcast ({ i8*, i8* }* @​_ZTI1C to i8*) %7 = extractvalue { i8*, i32 } %6, 0 store i8* %7, i8** %exn.slot %8 = extractvalue { i8*, i32 } %6, 1 store i32 %8, i32* %ehselector.slot call void @​__cxa_free_exception(i8* %exception) nounwind br label %catch.dispatch A call to copy constructor should be in a terminate context, but it's not (unwind edge points to the incorrect landingpad %lpad1). Alexey Bataev Software Engineer Intel Compiler Team Intel Corp.