This is an archive of the discontinued LLVM Phabricator instance.

[scudo] Call __scudo_deallocate_hook on reallocations.
ClosedPublic

Authored by chelfi on Jan 10 2023, 9:36 AM.

Details

Summary

Scudo is expected to call scudo_allocate_hook on allocations, and
scudo_deallocate_hook on deallocations, but it's behavior is not
clear on reallocations. Currently, non-trivial reallocations call
scudo_allocate_hook but never scudo_deallocate_hook. We should
prefer either calling both, none, or a dedicated
hook (__scudo_reallocate_hook, for instance).

This patch implements the former, and adds a unit test to enforce
those expectations.

Diff Detail

Event Timeline

chelfi created this revision.Jan 10 2023, 9:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 10 2023, 9:36 AM
chelfi requested review of this revision.Jan 10 2023, 9:36 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 10 2023, 9:36 AM
Herald added a subscriber: Restricted Project. · View Herald Transcript
cryptoad added inline comments.Jan 10 2023, 11:15 AM
compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
780 ↗(On Diff #487847)

Can this test be put in a separate unit so that the hooks don't impact the rest of combined_test?

786 ↗(On Diff #487847)

Maybe __attribute__((visibility("default")))?

813 ↗(On Diff #487847)

This likely will depend on the chosen SizeClass for the platform this is running on.
Ideally you could check that the returned pointer is indeed different, and then verified the callbacks were called.
Same for next test case, check that they are the same.

Chia-hungDuan added inline comments.Jan 10 2023, 11:39 AM
compiler-rt/lib/scudo/standalone/combined.h
691

I'm thinking that we can move this to quarantineOrDeallocateChunk() then we have single location for both allocation and deallocation. Then for the tests, we only need to ensure that calling allocate/deallocate have the callback invoked, i.e., we don't need to depend on the implementation (like the size-class in the test case)

The only case we may miss is when nullptr deallocation but I think that may be fine.

@cryptoad, what do you think?

cryptoad added inline comments.Jan 10 2023, 11:53 AM
compiler-rt/lib/scudo/standalone/combined.h
691

I think we would miss more than the nullptr.
Any report... in deallocate as well a the GWP-ASan path wouldn't have the hook called, and those cases are arguably valuable.
So I think it makes sense to have the hook in a "top" functions.

Chia-hungDuan added inline comments.Jan 10 2023, 12:08 PM
compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
813 ↗(On Diff #487847)

You can also try to do realloc according to the sizes in SizeClassMap so that you can expect its returning different pointer, then you can always check thing like,

ptr = malloc(...);
for (size : size_in_size_class_map) {
  new_ptr = realloc(ptr, size);
  if (same_pointer) 
    // expect no allocate
  else
    // expect deallocation and allocation
}
Chia-hungDuan added inline comments.Jan 10 2023, 12:25 PM
compiler-rt/lib/scudo/standalone/combined.h
691

I see. I thought this is only used to report the valid pointers. May I know what's the goal of using these hooks?

cryptoad added inline comments.Jan 10 2023, 12:35 PM
compiler-rt/lib/scudo/standalone/combined.h
691

Generally, yes, as it is mostly used for memory tracing (like https://cs.github.com/vsrinivas/fuchsia/blob/30435a9d0f0b67c94e3c70760b522c9f7fbbd6be/src/performance/memory/profile/memory_trace.cc#L120).
But ideally, it should report *all* allocations and deallocations, including the "bogus" ones (eg: allocation of 0-sized chunks, free of null pointers, non-fatal inconsistencies, etc), mostly because we initially did not want to make a choice for the user as to what is reported and what isn't.

chelfi added inline comments.
compiler-rt/lib/scudo/standalone/combined.h
691

What would you prefer we do, in the context of this patch? I see two obvious options:

  1. Keep it here, with maybe a comment to revisit exposing more info in a future patch.
  2. Call the hook everywhere relevant. We can maybe move those calls to the top of the allocate/deallocate/reallocate, so that everything is reported regardless of what is actually happening in the allocator. We might even introduce a __scudo_reallocate_hook so that we don't have to translate reallocate calls to non-obvious combinations of allocate/deallocate calls (though this might just push the complexity downwards to profiler implementations.)

Any preference?

chelfi marked an inline comment as not done.Jan 12 2023, 5:54 AM
chelfi updated this revision to Diff 488678.Jan 12 2023, 8:57 AM

Apply reviewer comments.

  • Move tests to a separate compile unit.
  • Programmatically iterate through the size class map to ensure meaningful reallocations.

This update copies a non-trivial amount of helper macros from combined_test.cpp, in order to reuse the nice support for iterating tests on allocator configs.

chelfi marked 4 inline comments as done.Jan 12 2023, 8:59 AM
cryptoad added inline comments.Jan 12 2023, 9:33 AM
compiler-rt/lib/scudo/standalone/combined.h
691

I personally prefer it this way in reallocate

Chia-hungDuan added inline comments.Jan 12 2023, 11:18 AM
compiler-rt/lib/scudo/standalone/combined.h
691

@cryptoad , thanks for the background and Yes, I agree with you. Let's stick on the way here

compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp
47–56

I think we don't need to distinguish the platform and a DefaultConfig may be enough. The goal is to ensure the hooks are invoked properly and iterate the size-class-map is to ensure the hooks will be called.

In addition, we may not need the SCUDO_TYPED_TEST, a simple TEST with the use of DefaultConfig should be enough

133–134

I may suggest just to add something more concrete rather than just a counter. For example,

if (NewPtr != Ptr) {
  // We expect Ptr to be reported to deallocate-hook and NewPtr to be reported allocate-hook
}

So that we won't report wrong information (e.g., report the block address rather than the aligned address)

1c3t3a added a subscriber: 1c3t3a.Jan 13 2023, 1:57 AM
chelfi updated this revision to Diff 488991.Jan 13 2023, 7:00 AM
chelfi marked an inline comment as done.

Improve unit tests.

  • Remove the SCUDO_TYPED_TEST machinery.
  • Further verify the data reported by the hooks (i.e. check content rather than just calls).
chelfi updated this revision to Diff 488993.Jan 13 2023, 7:05 AM

Fix whitespace issues.

chelfi marked 2 inline comments as done.Jan 13 2023, 7:06 AM
chelfi updated this revision to Diff 489032.Jan 13 2023, 9:06 AM

Fix type issue.

I've manually tested the change in a Fuchsia checkout, because I was worried about the binary stripping policy in that toolchain.
My worries were unwarranted, so I removed part of the warnings in the test comments.

Chia-hungDuan accepted this revision.Jan 18 2023, 12:04 PM
Chia-hungDuan added inline comments.
compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp
23

compilation

26–28

Do we need them to be in the scope of extern "C"? I may suggest moving them out and mark as static

55

lint: I suggest spelling it out, void

75

Let's still catch the return value and you may want to expect the same pointer.

98

Same as above

102

I may suggest LastRequestSize

This revision is now accepted and ready to land.Jan 18 2023, 12:04 PM
chelfi updated this revision to Diff 490543.Jan 19 2023, 8:59 AM

Applying reviewer comments:

  • Use explicit type names instead of auto.
  • Make unnecessarily exposed symbols static.
  • Ensure no-op reallocations return the same pointer.
chelfi marked 6 inline comments as done.Jan 19 2023, 9:00 AM
Chia-hungDuan added inline comments.Feb 13 2023, 11:12 PM
compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
134

lit: align with s like others

compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp
47

scudo::Allocator has larger alignment requirement so that we can't use make_unique here. Can you change this to local variable instead? Like

scudo::Allocator<scudo::DefaultConfig> Allocator;
...

I'll fix the other tests which are luckily got aligned.

chelfi updated this revision to Diff 497272.Feb 14 2023, 4:32 AM
  • Fix alignment issues.
  • Rebase.
chelfi marked 2 inline comments as done.Feb 14 2023, 4:34 AM
This revision was automatically updated to reflect the committed changes.

@chelfi
It looks like this changeset has broken one of the bots on PowerPC.
https://lab.llvm.org/buildbot/#/builders/57

Could you please take a look at this?
If you have any questions or would like help reproducing the issue please let me know.

Seems to be EXPECT_EQ(0, LastRequestSize); related. Potential fix would be 0U for both instances.

Seems to be EXPECT_EQ(0, LastRequestSize); related. Potential fix would be 0U for both instances.

Yep, I'm on it. D144121

Sorry for the breakage; thanks for the fix!