понедельник, 20 июня 2011 г.

MinGW bugs

Yesterday I encountered my second MinGW bug.

The whole freaking day was spent in debugging and figuring out what was going on.
Here is a snippet. Yes, it catches 'int' because I tried to reduce my problem to the simplest form (and I learned it crashes with any type).
  1. // inside a newly created Win32 thread  
  2.     virtual void OnStart()  
  3.     {  
  4.   
  5.              /* some code */  
  6.   
  7.                 try  
  8.                 {  
  9.                     resource->CreateAsyncHandle(); // <-- this throws  
  10.                 }  
  11.                 catch(int i)  
  12.                 {  
  13.                     printf("Upper level.\n"); // <-- doesn't print, isn't caught, crashes 
  14.                     exit(1); 
  15.                 }  
  16.          // Some code  
  17.    }  


This is the function that throws the exception:
  1. void TAsyncProxyMaterial::CreateAsyncHandle() // virtual function btw  
  2. {  
  3.     try  
  4.     {  
  5.         throw 2; // test code to simplify, in the actual code it throws a TException  
  6.     }  
  7.     catch(int i)  
  8.     {  
  9.         printf("Lower level.\n");  
  10.   
  11.         throw;  
  12.     }  
  13.   
  14.   
  15.     ... /* some simple code that deals with member fields */  
  16. }  
(original code didn't rethrow, it is done merely to be able to set breakpoints, and it crashes anyway)

Ideally, it should print
"Lower level.
Upper level."

exiting with error code 1.

In fact, it prints only "Lower level." and crashes with "This application has requested the Runtime to terminate it in an unusual way." (crashed with both MinGW 3.4.5 and MinGW 4.4.something)

DebugDiag didn't confirm there was a segfault. gdb's breakpoints were ignored when set to printf("Upper level.\n")

I also tried static builds, -mthread keyword, and many other magic things.

Also, for debugging purposes, I removed all stack-allocated objects, to guarantee it isn't fault of an exception in one of destructors.

Weird.

So I applied a quick and ugly workaround (still to be redesigned):
  1.     bool createAsyncHandle_workaroundMinGWBug(IAsyncResource* res, TException* out_ex) __attribute__ ((noinline))  
  2.     {  
  3.         bool exceptionOccured = false;  
  4.   
  5.         try  
  6.         {  
  7.             res->CreateAsyncHandle();  
  8.         }  
  9.         catch(TException& e)  
  10.         {  
  11.             exceptionOccured = true;  
  12.             *out_ex = e;  
  13.         }  
  14.   
  15.         return exceptionOccured;  
  16.     }  
  17.   
  18.   
  19. virtual void OnStart()  
  20. {  
  21.   
  22.     // ... 
  23.   
  24.                 TException mingwBug_e(EC_OK, 0);  
  25.                 bool errorOccured = createAsyncHandle_workaroundMinGWBug(resource, &mingwBug_e);  
  26.   
  27.     // ...  
  28. }  

Now it catches the exception without problems inside the nested createAsyncHandle_workaroundMinGWBug function. Everything works as expected.


And my first MinGW bug was...
I recently experienced another bug. I spent around an hour debugging. I was getting very random segfaults. Then I narrowed it down to a thread extracting an incorrect thread-local value. Let's check out their official site (I used GCC 4.4 port): "New features since the previous release: ... Thread local storage support: The __thread keyword is honoured."


This is a half-truth. Yes, mingw-4.4, unlike mingw-3.4.5, now doesn't complain anymore when sees the __thread keyword. However, it doesn't make it thread-local either, it still actually remains a shared static variable all threads write to, corrupting memory and logic.


Still have to wrap it with WinAPI's Tls** family of functions, as in MinGW 3.4.5


Such cases.

Комментариев нет:

Отправить комментарий