This is an archive of the discontinued LLVM Phabricator instance.

[Clang] Support a user-defined __dso_handle
ClosedPublic

Authored by asavonic on Apr 23 2021, 5:19 AM.

Details

Summary

This fixes PR49198: Wrong usage of __dso_handle in user code leads to a compiler
crash.

When Init is an address of the global itself, we need to track it
across RAUW. Otherwise the initializer can be destroyed if the global
is replaced.

Diff Detail

Event Timeline

asavonic requested review of this revision.Apr 23 2021, 5:19 AM
asavonic created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptApr 23 2021, 5:19 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

John, can you please review this patch?
I originally wanted to add a diagnostic to prevent the crash in CG (PR49198), but the case seems easy enough to support.

What's the crash exactly/ Is IRGen just unhappy about processing the user definition when we've generated a declaration with a different type? Because we're already supposed to be being cautious about this.

What's the crash exactly/ Is IRGen just unhappy about processing the user definition when we've generated a declaration with a different type? Because we're already supposed to be being cautious about this.

Hi John. Sorry for the late reply.

class a {
public:
  ~a();
} b;
void *__dso_handle = &__dso_handle;

This code code causes a crash because the compiler first generates a
__dso_handle with i8 type:

@__dso_handle = external dso_local global i8

... and then reaches the explicit definition of it with a pointer type and a
pointer initializer, and tries to generate this instead:

@__dso_handle = hidden global i8* bitcast (i8** @__dso_handle to i8*), align 8

Since __dso_handle already exists in the module, it must be replaced because the
initializer has an incompatible type.

There is indeed some handling for this case in EmitGlobalVarDefinition, but it
does not work correctly when the initializer is a pointer to the variable
itself. Specifically, the Init variable in EmitGlobalVarDefinition becomes
stale:

p Init->dump()
<badref> = hidden global i8 <null operand!>

The current patch avoids this problem by having two distinct globals, but maybe
it is better to fix EmitGlobalVarDefinition instead? Is it supposed to handle
such case?

asavonic updated this revision to Diff 347341.May 24 2021, 3:54 AM
asavonic edited the summary of this revision. (Show Details)

I went ahead and implemented a fix for EmitGlobalVarDefinition. Please let me know what approach is preferable: Diff 339986 or Diff 347341.

rjmccall added inline comments.Jun 3 2021, 6:36 PM
clang/lib/CodeGen/CodeGenModule.cpp
4425

Can we actually do this bitcast for arbitrary initializers? This seems problematic.

I think we just need to hold Init in an llvm::TrackingVH across the call to GetAddrOfGlobalVar.

asavonic updated this revision to Diff 350134.Jun 6 2021, 2:52 PM
asavonic edited the summary of this revision. (Show Details)
  • Used llvm::TrackingVH to track Init changes.
asavonic added inline comments.Jun 6 2021, 2:58 PM
clang/lib/CodeGen/CodeGenModule.cpp
4425

Thanks a lot! TrackingVH works great, with a few adjustments because it cannot be checked for nullptr.

rjmccall accepted this revision.Jun 6 2021, 7:29 PM

Great, LGTM.

This revision is now accepted and ready to land.Jun 6 2021, 7:29 PM
This revision was automatically updated to reflect the committed changes.
Tuxist added a subscriber: Tuxist.Aug 18 2022, 2:45 AM

i have a problem i'am implement a libc in c++ i can't export now __dso_handle as weak so I can't link other shared libs against my libc.

Herald added a project: Restricted Project. · View Herald TranscriptAug 18 2022, 2:45 AM