Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dyninst: New package #7473

Open
wants to merge 38 commits into
base: master
Choose a base branch
from

Conversation

eschnett
Copy link
Contributor

@eschnett eschnett commented Oct 3, 2023

No description provided.

@eschnett
Copy link
Contributor Author

eschnett commented Oct 5, 2023

While the build works fine, the checks afterwards crash with

[ Info: Checking shared library lib/libcommon.so.12.3.0
  | free(): invalid pointer
  |  
signal (6): Aborted

(libcommon is one of the libraries that's built.) How would I debug this?

@giordano
Copy link
Member

giordano commented Oct 5, 2023

It's the dlopening that's failing, maybe the init function of the library does something nasty?

@eschnett eschnett marked this pull request as draft October 10, 2023 14:08
D/Dyninst/build_tarballs.jl Outdated Show resolved Hide resolved
D/Dyninst/build_tarballs.jl Outdated Show resolved Hide resolved
@eschnett
Copy link
Contributor Author

@giordano I can successfully dlopen each of the shared libraries from within the build script. However, this still fails from within Julia. Do you have an idea why this might be?

I also looked at the libraries' initialization routines but that's a bit hopeless because these are large C++ libraries and I don't know which objects would be created or which functions would be called.

@giordano
Copy link
Member

To leave some breadcrumbs, the init function of the shared library is marked with __attribute__((constructor)) and it's called runDYNINSTBaseInit: https://github.com/dyninst/dyninst/blob/ddd2315b562efdca3fe6aa25d6da2a3842c293fa/dyninstAPI_RT/src/RTlinux.c#L644-L661. But this function only calls the function r_debugCheck() and DYNINSTBaseInit: the former looks relatively innocuous (only running an assert: https://github.com/dyninst/dyninst/blob/ddd2315b562efdca3fe6aa25d6da2a3842c293fa/dyninstAPI_RT/src/RTlinux.c#L412), but the latter is more convoluted because it then calls other functions: https://github.com/dyninst/dyninst/blob/ddd2315b562efdca3fe6aa25d6da2a3842c293fa/dyninstAPI_RT/src/RTcommon.c#L163-L174

@giordano
Copy link
Member

This is what we do during audit to dlopen the library: https://github.com/JuliaPackaging/BinaryBuilder.jl/blob/54284653349b50eef5ad50b0c579659c38ef99e6/src/Auditor.jl#L150-L159. Not really much (using Libdl; dlopen(/path/to/library))

@eschnett
Copy link
Contributor Author

I saw the call in Auditor.jl, and I am using the same flags when calling dlopen from C in the build script, which is working (no segfault). I think I don't understand the difference between the build environment and the environment in which the auditor is running in CI. I assume the build script is running in a Docker container that (somehow) makes things work? Maybe a system library is different?

@eschnett
Copy link
Contributor Author

There are different libstdc++ libraries:

libstdc++.so.6 => /workspace/destdir/lib/libstdc++.so.6 (0x00007fa5b1617000)
libstdc++.so.6 => /usr/lib/csl-glibc-x86_64/libstdc++.so.6 (0x00007f99a555a000)

The first is used by Dyninst, the second by Boost. That doesn't look healthy.

@eschnett
Copy link
Contributor Author

While the dlopen in the auditor fails, I can:

  • generate a package locally
  • using Dyninst_jll
  • dlopen(Dyninst_jll.libcommon)
    and this does not segfault. I think this is somehow a problem in the auditor.

@eschnett eschnett marked this pull request as ready for review October 19, 2023 18:51
@eschnett
Copy link
Contributor Author

@giordano I disabled the auditor. I think (see above) that the generated shared libraries are actually working fine.

@giordano
Copy link
Member

I'm not incredibly happy about disabling the auditor, it does more stuff than just dlopening the library, like ensure the runpath is set correctly, the soname is set, etc...

@giordano
Copy link
Member

giordano commented Oct 20, 2023

I'm still convinced they do something dodgy in their init function: #7473 (comment). If we have problems during audit here, we can have problems elsewhere, if dlopen is failing we should fix it, rather ignoring it.

@eschnett
Copy link
Contributor Author

The current options actually only set dont_dlopen, they don't explicitly disable the auditor. I assume this means that the auditor is still running some other tests?

Apart from setting a few global variables Dyninst installs a signal handler in DYNINSTinitializeTrapHandler:

int DYNINSTinitializeTrapHandler(void)
{
   int result;
   struct sigaction new_handler;
   int signo = SIGTRAP;

   // If environment variable DYNINST_SIGNAL_TRAMPOLINE_SIGILL is set,
   // we use SIGILL as the signal for signal trampoline.
   // The mutatee has to be generated with DYNINST_SIGNAL_TRAMPOLINE_SIGILL set
   // so that the mutator will generates illegal instructions as trampolines.
   if (getenv("DYNINST_SIGNAL_TRAMPOLINE_SIGILL")) {
      signo = SIGILL;
   }

   new_handler.sa_sigaction = dyninstTrapHandler;
   //new_handler.sa_restorer = NULL; obsolete
   sigemptyset(&new_handler.sa_mask);
   new_handler.sa_flags = SA_SIGINFO | SA_NODEFER;
   
   result = sigaction(signo, &new_handler, NULL);
   return (result == 0) ? 1 /*Success*/ : 0 /*Fail*/ ;
}

Maybe Julia doesn't like SIGTRAP being caught?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants