This is an archive of the discontinued LLVM Phabricator instance.

[DebugInfo][Metadata] Make AllEnumTypes holding TrackingMDNodeRef
ClosedPublic

Authored by krisb on Oct 31 2022, 3:15 AM.

Details

Summary

Having AllEnumtypes to be a vector of TrackingMDNodeRef makes it possible
to reflect changes in metadata in the vector if they took place before DIBuilder
being finalized.

Otherwise, we end up with heap-use-after-free because AllEnumTypes contains
metadata that no longer valid.

Consider a case where we have a class containing a definition of a enum,
so this enum has the class as a scope. For some reason (doesn't matter for
the current issue), we create a temporary debug metadata for this class, and
then resolve it while finalizing CGDebugInfo.

Once resolved the temporary, we may need to replace its uses with a new pointer.
If a temporary's user is unique (this is the enum mentioned above), we
may need re-uniqueing it, which may return a new pointer in a case of collision.
If so, the pointer we stored in AllEnumTypes vector become dangling.
Making AllEnumTypes hodling TrackingMDNodeRef should solve this problem
(see debug-info-enum-metadata-collision.cpp test for details).

Diff Detail

Event Timeline

krisb created this revision.Oct 31 2022, 3:15 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 31 2022, 3:15 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
krisb requested review of this revision.Oct 31 2022, 3:15 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptOct 31 2022, 3:15 AM
dblaikie accepted this revision.Oct 31 2022, 8:02 AM

Test case can be simplified a bit further:

template <typename> struct Struct1 {
  enum { enumValue1 };
  Struct1();
};
void function2() {
  struct Struct3 {};
  int i = Struct1<Struct3>::enumValue1;
}
void function3() {
  struct Struct3 {};
  int i = Struct1<Struct3>::enumValue1;
}

but otherwise I'm OK with this - I don't /fully/ understand it, but it sounds plausible enough. (if you have time, I wouldn't mind hearing more about why this requires local types (Struct3) and two similar functions to tickle the issue)

This revision is now accepted and ready to land.Oct 31 2022, 8:02 AM
krisb updated this revision to Diff 472079.Oct 31 2022, 11:17 AM

Apply review comments.

krisb added a comment.EditedOct 31 2022, 11:18 AM

Test case can be simplified a bit further:

Thank you!

but otherwise I'm OK with this - I don't /fully/ understand it, but it sounds plausible enough. (if you have time, I wouldn't mind hearing more about why this requires local types (Struct3) and two similar functions to tickle the issue)

The test is just a simplified code sample where the issue was original faced. I'm not sure we specifically need local types or two particular functions, but artificially reproducing the same conditions may be tricky.
Basically, the issue happens only when collisions take place twice:

  • first time when a record's temporary debug metadata being replaced by a unique, and
  • second time when tempopary's enum user being re-uniquefied.

I haven't studied deeply why the collisions happen in this particular test, since if collisions /may/ happen, we should handle this case correctly anyway.

This revision was landed with ongoing or failed builds.Nov 3 2022, 1:30 AM
This revision was automatically updated to reflect the committed changes.