Bug 40918 - uncaught_exception() returns wrong (inverted) value if some exception have crossed a DLL boundary before
Summary: uncaught_exception() returns wrong (inverted) value if some exception have cr...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-07-30 20:18 UTC by Andriy Syrovenko
Modified: 2012-01-16 09:40 UTC (History)
3 users (show)

See Also:
Host: mingw32
Target:
Build:
Known to work:
Known to fail: 3.4.2, 4.4.0
Last reconfirmed:


Attachments
Test case (589 bytes, application/zip)
2009-07-30 20:22 UTC, Andriy Syrovenko
Details
Modified test case (not dependent on libstdc++ at all) (657 bytes, application/zip)
2009-07-31 06:58 UTC, Andriy Syrovenko
Details
Yet another test case (728 bytes, application/zip)
2009-08-04 13:53 UTC, Andriy Syrovenko
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Andriy Syrovenko 2009-07-30 20:18:44 UTC
I was not able to reproduce the bug on Linux, so I assume this is a Windows-specific.

If an exception is generated inside shared library (DLL), then crosses the DLL-boundary and gets caught in some other module, the std::uncaught_exception will always return wrong (inverted) value from now on. Here's a small test case.

The DLL (throw.dll) contains just a single function that throws an exception:

throw.cpp
~~~~~~~~~
void do_throw(void)
{
    throw("");
}


The test program (test.exe) is linked against throw.dll:

test.cpp
~~~~~~~~
#include <exception>
#include <iostream>

bool b;
void do_throw(void);

struct UE
{
    ~UE()
    {
        b = std::uncaught_exception();
    }
};


int main(void)
{
    try
    {
        do_throw();
    }
    catch (...)
    {
    }

    try
    {
        UE ue;
        throw "";
    }
    catch (...)
    {
    }

    std::cout << "Expecting 'true', got " << (b ? "'true'" : "'false'") << std::endl;

    {
        UE ue;
    }
    std::cout << "Expecting 'false', got " << (b ? "'true'" : "'false'") << std::endl;

    return 0;
}

test.exe produces the following output:

C:\TEMP\bug>test.exe
Expecting 'true', got 'false'
Expecting 'false', got 'true'

If we comment out the call to do_throw(), std::uncaught_exception will work as expected. If we put do_throw() in a statically linked module, std::uncaught_exception will work as expected as well.
Comment 1 Andriy Syrovenko 2009-07-30 20:22:07 UTC
Created attachment 18275 [details]
Test case
Comment 2 Danny Smith 2009-07-31 04:18:21 UTC
(In reply to comment #0)
> I was not able to reproduce the bug on Linux, so I assume this is a
> Windows-specific.
> 
> If an exception is generated inside shared library (DLL), then crosses the
> DLL-boundary and gets caught in some other module, the std::uncaught_exception
> will always return wrong (inverted) value from now on. Here's a small test
> case.
> 

You need to link against a shared libgcc and a shared libstdc++ for this to work.  Shared libgcc is part of standard build now for mingw  Shared libstdc++ is close.

http://gcc.gnu.org/ml/gcc-patches/2009-07/msg01042.html

Danny
Comment 3 Andriy Syrovenko 2009-07-31 06:56:33 UTC
I'm linking using g++ driver, so shared libgcc is enabled by default in 4.4.0.
I've just tried to enabled shared libstdc++ as described in the Release Notes to the MinGW GCC 4.4.0 release, which made no difference.

More over, I modified the test case the following way: I got rid of std::cout in favor of printf(), added -nodefaultlibs option to the linker and specified all the required libraries manually. Now libstdc++ is not linked at all (neither static nor dynamic), the bug is still here.

I'll attach the modified test case shortly.
Comment 4 Andriy Syrovenko 2009-07-31 06:58:04 UTC
Created attachment 18277 [details]
Modified test case (not dependent on libstdc++ at all)
Comment 5 Danny Smith 2009-08-02 08:57:32 UTC
(In reply to comment #3)
> I'm linking using g++ driver, so shared libgcc is enabled by default in 4.4.0.


> I've just tried to enabled shared libstdc++ as described in the Release Notes
> to the MinGW GCC 4.4.0 release, which made no difference.
> 
> More over, I modified the test case the following way: I got rid of std::cout
> in favor of printf(), added -nodefaultlibs option to the linker and specified
> all the required libraries manually. Now libstdc++ is not linked at all
> (neither static nor dynamic), the bug is still here.
> 

I cannot comment on the build of libsdc++.dll in the mingw 4.4.0 release since I have not looked at that source. 

However, your revised testcase -- linking against a static libsupc++ -- would be expected to fail.  We can have only one instance of the eh_globals structure defined in libsupc++/eh_globals.cc. This is accomplished by linking both the .exe  and the .dll against a shared libstdc++.

Applying Dave Korn's patch mentioned in Comment #2, and linking against libstdc++.dll, I get this with your original testcaase:

Expecting 'true', got 'true'
Expecting 'false', got 'false'
Comment 6 Andriy Syrovenko 2009-08-04 13:41:05 UTC
(In reply to comment #5)
> I cannot comment on the build of libsdc++.dll in the mingw 4.4.0 release since
> I have not looked at that source. 
There is a patch file that is shipped along with the mingw 4.4.0 build instructions/script. The patch adds most of the essential things that the Dave Korn's patch does (i.e. __attribute__((dllimport)) decorations and -no-undefined linker option.) I believe the official MinGW binaries were built with that patch applied. Well, there are your E-mail at the top of that patch file...

> Applying Dave Korn's patch mentioned in Comment #2, and linking against
> libstdc++.dll, I get this with your original testcaase:
> 
> Expecting 'true', got 'true'
> Expecting 'false', got 'false'
> 
Where this patch is supposed to be applied to? trunk?
I have looked through the patches you are referring to and through the source in repository. As far as I can see, libsupc++ is still static only, and eh_globals.cc is a part of libsupc++, not libstdc++. The fact that test-case works correctly for you could be just a coincidence. The more reliable way to check for the problem would be to compare the value returned by the __cxa_get_globals() when being from the main executable and from the dll respectively. I'll prepare the new test case.
Comment 7 Andriy Syrovenko 2009-08-04 13:53:38 UTC
Created attachment 18296 [details]
Yet another test case

This test checks whether main executable and dll share common abi::__cxa_eh_globals structure.
Comment 8 Danny Smith 2009-08-05 04:55:08 UTC
(In reply to comment #6)
> (In reply to comment #5)
> 
> > Applying Dave Korn's patch mentioned in Comment #2, and linking against
> > libstdc++.dll, I get this with your original testcaase:
> > 
> > Expecting 'true', got 'true'
> > Expecting 'false', got 'false'
> > 
> Where this patch is supposed to be applied to? trunk?

Yes, it against trunk.

> I have looked through the patches you are referring to and through the source
> in repository. As far as I can see, libsupc++ is still static only, and
> eh_globals.cc is a part of libsupc++, not libstdc++.

libsupc++ is a convenience lib that is included in libstdc++


 The fact that test-case
> works correctly for you could be just a coincidence. The more reliable way to
> check for the problem would be to compare the value returned by the
> __cxa_get_globals() when being from the main executable and from the dll
> respectively. I'll prepare the new test case.

The new test case succeeds when I link against a shared libstdc++.

Danny


Comment 9 Andriy Syrovenko 2010-01-26 12:16:48 UTC
Well, I have finally managed to build the trunk on Windows (mingw32). Now all test cases work fine for me without any patches (as of revision 156168 at least). Thanks.
Comment 10 Kai Tietz 2012-01-16 09:40:58 UTC
Well, as user problem is solved and new gcc-version providing by default shared version for libstdc++/libgcc, I close this issue.