This is an archive of the discontinued LLVM Phabricator instance.

Fix an ASAN bug I introduced in debugserver, accessing off the end of an array intentionally
ClosedPublic

Authored by jasonmolenda on Dec 14 2022, 4:21 PM.

Details

Summary

In https://reviews.llvm.org/D136620 I needed to access fp/sp/pc/lr two different ways depending on the compile-time environment -- the headers name these registers differently, and the types are different so one of them needs to be cast. This was tiresome, so instead I indexed off of the array of general purpose registers right before them. ASAN expresses its displeasure with this shortcut.

Before my original patch, this code passed the register context in to the arm_thread_state64_get{sp,fp,lr,pc} and those macros handled this detail.

The ASAN CI bot does not build an in-tree debugserver and test with it, but when I looked into a bot test failure, I hit this first.

Diff Detail

Event Timeline

jasonmolenda created this revision.Dec 14 2022, 4:21 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 14 2022, 4:21 PM
jasonmolenda requested review of this revision.Dec 14 2022, 4:21 PM
JDevlieghere added inline comments.Dec 14 2022, 5:21 PM
lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
2026–2037

reg is a uint32_t so you could use a switch here:

switch(reg) {
  case gpr_pc: 
    ...
}
jasonmolenda added inline comments.Dec 15 2022, 10:31 AM
lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
2026–2037

I thought about that, but then I'd need a break; after each element and it was one extra line. I don't have a real preference, and this was shorter.

aprantl added inline comments.Dec 15 2022, 10:39 AM
lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
2026–2037

If we are already micro-optimizing, I guess the resulting code would be shorter (and 100% UB-free) if it were

uint64_t val = 0;
switch(reg) {
  case gpr_pc: 
      memcpy(&val, m_state.context.gpr.__opaque_pc);
      break;
  ...
}
value->value.uint64 = clear_pac_bits(val);
jasonmolenda added inline comments.Dec 15 2022, 12:41 PM
lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp
2026–2037

I don't have anything against using memcpy instead of the reinterpret_cast, but I don't see it being any clearer (IMO), and it doesn't reduce the code duplication - we still need separate lines for when the members are named __opaque_ and when not. If anyone feels it's clearer to use a switch statement and/or memcpy, I genuinely don't care either way, but I don't see it myself.

JDevlieghere accepted this revision.Dec 15 2022, 12:54 PM

I think a switch case is easier to read (and spot things like missing cases) but this is code you own so go with the approach you like best. LGTM.

This revision is now accepted and ready to land.Dec 15 2022, 12:54 PM

Update the patch to use a case statement for fp/sp/lr/pc instead of conditionals; both Adrian and Jonas preferred it.