bitwiseworks / libcx

kLIBC Extension Library
GNU Lesser General Public License v2.1
11 stars 1 forks source link

Linking with LIBCx does not enable EXCEPTQ on LIBC threads #62

Closed dmik closed 5 years ago

dmik commented 5 years ago

If a program links with LIBCx (-lcx), it should get EXCEPTQ support for the main thread as well as for all threads started with _beginthread. However, it doesn't seem to be the case. At least, this simple program does not generate a .TRP file:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

void thread_func (void *arg)
{
  int * p = 0; *p = 0x123;
  printf ("THREAD %d\n", _gettid ());
}

int main ()
{
  int tid = _beginthread (thread_func, 0, 0, 0);
  if (tid == -1)
  {
    printf ("Cannot start thread.");
    return 1;
  }

  sleep (2);
  return 0;
}

It will generate it, however, if you install EXCEPTQ manually with [Lib]LoadExceptq in thread_func.

dmik commented 5 years ago

I found this when working on https://github.com/bitwiseworks/qtbase-os2/issues/29 — a fatal assertion on a thread started with QThread in tst_QObject didn't generate a .TRP file (which is nesessary to get the stack trace of that assertion).

dmik commented 5 years ago

Note that if I disable the LIBCx own exception handler (which it installs after EXCEPTQ for the needs of mmap), then all starts working fine. So it must be that this own exception handler somehow doesn't let the EXCEPTQ handler handle the exception. Digging.

dmik commented 5 years ago

Funny enough, in the debug version of LIBCx all works. In the release build, the second exception handler in the chain (which is EXCEPTQ) does not get called if the first one (which is LIBCx for mmap) returns XCPT_CONTINUE_SEARCH straight away (no mmap code is involved). This is very strange.

dmik commented 5 years ago

I guess I know what it is. GCC re-orders stack variables in release mode. More over, it even does so if a new scope is introduced with curly braces. I.e. we have:

  EXCEPTIONREGISTRATIONRECORD rec1;
  {
    EXCEPTIONREGISTRATIONRECORD rec2;
  }

Given that the stack grows down, one would expect that the address of rec2 is smaller than the address of rec1 because the rec2 variable should be allocated on the stack after rec1. This is true for the debug build but not for the release one. In the release one, rec1 gets a smaller address than rec2 and this apparently kills the normal exception handler chain processing.

Okay, I know how to force the compiler to maintain the right order.

dmik commented 5 years ago

FIxed above. I used a similar approach in Mozilla when it installed EXCEPTQ on its own. Note that this problem affect virtually all apps using LIBCx and creating threads with _beginthread — in the sense that no .TRP files would be created if those threads crashed. A known issue, actually.