This is an archive of the discontinued LLVM Phabricator instance.

Fix include guard and properly order __deregister_frame_info.
ClosedPublic

Authored by saugustine on Nov 8 2019, 4:15 PM.

Details

Summary

This patch fixes two problems with the crtbegin.c as written:

  1. In do_init, register_frame_info is not guarded by a #define, but in do_fini, deregister_frame_info is guarded by #ifndef CRT_HAS_INITFINI_ARRAY. Thus when CRT_HAS_INITFINI_ARRAY is not defined, frames are registered but then never deregistered.

    The frame registry mechanism builds a linked-list from the .so's static variable do_init.object, and when the .so is unloaded, this memory becomes invalid and should be deregistered.

    Further, libgcc's crtbegin treats the frame registry as independent from the initfini array mechanism.

    This patch fixes this by adding a new #define, "EH_USE_FRAME_INFO_REGISTRY", which is set by the cmake option COMPILER_RT_CRT_USE_EH_FRAME_REGISTRY
  1. Currently, do_init calls register_frame_info, and then calls the binary's constructors. This allows constructors to safely use libunwind. However, do_fini calls deregister_frame_info and then calls the binary's destructors. This prevents destructors from safely using libunwind.

    This patch also switches that ordering, so that destructors can safely use libunwind. As it happens, this is a fairly common scenario for thread sanitizer.

Event Timeline

saugustine created this revision.Nov 8 2019, 4:15 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptNov 8 2019, 4:15 PM
Herald added subscribers: llvm-commits, Restricted Project. · View Herald Transcript
phosek accepted this revision.Nov 8 2019, 6:32 PM

Thanks for these fixes! Personally, I'd be fine making a hard transition and making EH_USE_FRAME_REGISTRY independent from CRT_HAS_INITFINI_ARRAY, at least in our case it shouldn't cause any issue and I'd be surprised if anyone relied on the current behavior which is clearly a bug and not something I did intentionally.

Regarding the test, I think it'd be still useful to include it, but the dependency on libunwind might be a problem for actually running it, we might need to include a special check to only run that test when libunwind is being available.

This revision is now accepted and ready to land.Nov 8 2019, 6:32 PM
  • Address upstream comments. Move backward compatibility handling to CMakeLists.
  • Make USE_FRAME_REGISTRY completely independent of CRT_HAS_INITFINI_ARRAY,

Thanks for these fixes! Personally, I'd be fine making a hard transition and making EH_USE_FRAME_REGISTRY independent from CRT_HAS_INITFINI_ARRAY, at least in our case it shouldn't cause any issue and I'd be surprised if anyone relied on the current behavior which is clearly a bug and not something I did intentionally.

Regarding the test, I think it'd be still useful to include it, but the dependency on libunwind might be a problem for actually running it, we might need to include a special check to only run that test when libunwind is being available.

I figured out a more clever way on the test. It now just checks that register/deregister_frame_info is called at the proper time. That avoids the problem altogether.

EH_USE_FRAME_INFO is now completely separate from CRT_HAS_INITFINI_ARRAY, and on by default, as the original code always registered frames.

Thanks for the quick review. Will commit after running a few of the complicated cases that got me here, but I think this is right.

MaskRay added inline comments.
compiler-rt/test/crt/ctor_dtor.c
17

The LLVM coding standard uses const void * instead of const void*.

This patch fixes this by adding a new #define, "USING_FRAME_INFO_REGISTRY", which is set by the top-level define "USE_FRAME_INFO_REGISTRY". The indirection allows combining the first test with the backward compatibility check below.

I can't find USING_FRAME_INFO_REGISTRY.

saugustine updated this revision to Diff 228785.EditedNov 11 2019, 5:05 PM

In the original code, register_frame_info was always called. But in the original version of this patch, I awkwardly tied it to CRT_USE_INITFINI_ARRAY, which would make it uncalled in certain circumstances. Also, we agreed that tying the two things together didn't make a lot of sense.

This revision restores the original behavior, and unties the two. It also calls __unregister_frame_info unconditionally.

  • Fix space.
Harbormaster completed remote builds in B40783: Diff 228786.
MaskRay accepted this revision.Nov 11 2019, 5:18 PM

LG aside from a request for a description update.

Now that USE_FRAME_INFO_REGISTRY no longer exists (neither does USING_FRAME_INFO_REGISTRY), the summary should be updated.

Fix include guard

Maybe the title should be updated as well. The patch does not touch any #include directive.

  • Make using the eh_frame registry a configure-time option.
saugustine edited the summary of this revision. (Show Details)Nov 12 2019, 12:21 PM
MaskRay added inline comments.Nov 12 2019, 12:30 PM
compiler-rt/lib/crt/crtbegin.c
17

Place declarations in the scope of #ifdef EH_USE_FRAME_REGISTRY

...and finally, after some off line feedback, someone pointed out to me that we really do want using the frame registry to be configurable. Not the least of which because llvm-libunwind does nothing inside __register_frame_info.

Assuming no objections, will commit later today, as nothing functional has changed since acceptance.

saugustine marked an inline comment as done.Nov 12 2019, 2:38 PM

Move prototypes for the frame info functions as requested.

phosek accepted this revision.Nov 13 2019, 4:05 PM

LGTM

MaskRay closed this revision.Dec 2 2019, 10:00 PM

Closed by rG38c356176b5370164578c1d08e984964354b7189

You need Differential Revision: https://reviews.llvm.org/D70034 in the commit message so that Phabricator can close the revision automatically for you:)