153 Commits

Author SHA1 Message Date
Christopher Ferris
ef962752d9
[scudo] Allow the quarantine code to be compiled out (#151064)
Add a new configuration option QuarantineDisabled that allows all of the
quarantine code to be compiled out.

Add new tests that verify that the code is removed properly.

On Android, this saves ~4000 bytes for 32 bit and ~6000 bytes for 64
bit.

On Android, I used some microbenchmarks that do malloc/free in a loop
and for allocations in the primary, the performance is about the same
for both 32 bit and 64 bit. For secondary allocations, I saw ~8% speed
up on 32 bit and ~3% on 64 bit speed up which feels like it could just
be code size improvements.
2025-07-30 19:41:14 -07:00
Christopher Ferris
a2cee05449
[scudo] Make report pointers const. (#144624)
Mark as many of the reportXX functions that take pointers const. This
avoid the need to use const_cast when calling these functions on an
already const pointer.

Fix reportHeaderCorruption calls where an argument was passed into an
append call that didn't use them.
2025-06-18 09:12:53 -07:00
Christopher Ferris
1756fcb8b0
[scudo] Add primary option to enable/disable cache blocks. (#129794)
When configured this way, no primary blocks will be cached except the
batch class. Nothing else changes, no change in the page releasing
strategy.
2025-04-17 14:23:42 -07:00
Christopher Ferris
ed0fd13783
[scudo] Double frees result in chunk state error (#110345)
Fixes bug where a device that supports tagged pointers doesn't use
the tagged pointer when computing the checksum.

Add tests to verify that double frees result in chunk state error
not corrupted header errors.
2024-10-15 17:14:50 -07:00
Evgenii Stepanov
00989f4ab1
[scudo] Fix isOwned on MTE devices. (#111060)
If called on address that is actually not owned, the tags could not
match. Disable tag checks in isOwned().
2024-10-07 14:13:17 -07:00
NAKAMURA Takumi
e656b1a690 Revert "[scudo] Fix isOwned on MTE devices. (#110717)"
This caused failures in aarch64 builders.

This reverts commit 98c9523113b550eaca3728bf30cbc346af5eff07.
(llvmorg-20-init-7659-g98c9523113b5)
2024-10-02 20:16:36 +09:00
Evgenii Stepanov
98c9523113
[scudo] Fix isOwned on MTE devices. (#110717)
If called on an address that is actually not owned, the header tag might not
match. This would cause an MTE fault in Chunk::isValid.

Disable tag checks in isOwned().
2024-10-01 12:48:56 -07:00
Christopher Ferris
4634a480e0
[scudo] Add a method to use a hard-coded page size (#106646)
Currently, only Android supports using a hard-code page size. Make this
a bit more generic so any platform that wants to can use this.

In addition, add a getPageSizeLogCached() function since this value is
used in release.h and can avoid keeping this value around in objects.

Finally, change some of the release.h page size multiplies to shifts
using the new page size log value.
2024-09-05 13:43:34 -07:00
ChiaHungDuan
dd741fc1b1
[scudo][NFC] Add a default unmap() to unmap all pages (#102234) 2024-08-07 11:50:25 -07:00
Fabio D'Urso
7fc975aa26
Reland "[scudo] Apply filling when realloc shrinks and re-grows a block in-place" (#95838)
Reland of #93212, which had been reverted in
commit bddd8eae17df6511aee789744ccdc158de817081.
2024-06-19 09:37:23 +02:00
Fabio D'Urso
bddd8eae17 Revert "[scudo] Apply filling when realloc shrinks and re-grows a block in-place (#93212)"
This reverts commit 760d880ea602117aa2e6bba4cf31069f09225b4b.

It broke https://lab.llvm.org/buildbot/#/builders/169/builds/32309
2024-06-10 13:35:42 +02:00
Fabio D'Urso
760d880ea6
[scudo] Apply filling when realloc shrinks and re-grows a block in-place (#93212) 2024-06-10 10:39:17 +02:00
Andrei Homescu
b17d44558b
[scudo] Compute the default aligned pointer without tag (#92989)
https://github.com/llvm/llvm-project/pull/83493 slightly
changed the order of computation of block addresses and
pointers, causing the value of DefaultAlignedPtr to
include the MTE tag. Move this computation earlier so it
matches the old behavior.

This fixes a UBSan failure in Trusty:
secure os: UBSan: (overflow:-)
external/scudo/standalone/combined.h:1070:35
secure os: Details: unsigned integer overflow: 8988807738704 -
144124176883594576 cannot be represented in type 'uptr'
2024-05-23 10:08:05 -07:00
ChiaHungDuan
772b1b0cb2
[scudo] Move the chunk update into functions (#83493)
The code paths for mte enabled and disabled were interleaving and which
increases the difficulty of reading each path in both source level and
assembly level. In this change, we move the parts that they have
different logic into functions and minor refactors on the code
structure.
2024-05-15 17:13:08 -07:00
ChiaHungDuan
11f4f458d9
[scudo] Support setting default value of ReleaseToOsIntervalMs in config (#90256) 2024-04-29 08:41:46 -07:00
Christopher Ferris
0dbd804a69
[scudo] Only init RingBuffer when needed. (#85994)
Only attempt to initialize the ring buffer when tracking is enabled.

Updated unit tests, and added a few new unit tests to verify the
RingBuffer is not initialized by default.

Verified that the two maps associated with the RingBuffer are not
created in processes by default.
2024-03-29 09:44:17 -07:00
ChiaHungDuan
2dc9ec47fb
[scudo] Refactor allocator config to support optional flags (#81805)
Instead of explicitly disabling a feature by declaring the variable and
set it to false, this change supports the optional flags. I.e., you can
skip certain flags if you are not using it.

This optional feature supports both forms,
  1. Value: A parameter for a feature. E.g., EnableRandomOffset
  2. Type: A C++ type implementing a feature. E.g., ConditionVariableT

On the other hand, to access the flags will be through one of the
wrappers, BaseConfig/PrimaryConfig/SecondaryConfig/CacheConfig
(CacheConfig is embedded in SecondaryConfig). These wrappers have the
getters to access the value and the type. When adding a new feature, we
need to add it to `allocator_config.def` and mark the new variable with
either *_REQUIRED_* or *_OPTIONAL_* macro so that the accessor will be
generated properly.

In addition, also remove the need of `UseConditionVariable` to flip
on/off of condition variable. Now we only need to define the type of
condition variable.
2024-03-13 16:05:24 -07:00
Florian Mayer
337a200715
[NFC] [scudo] Move static_assert to class it concerns (#84245) 2024-03-11 11:47:59 -07:00
Florian Mayer
b4e0890458
[NFC] [scudo] move static_assert closer to class it relates to (#84257)
delete other static_assert
2024-03-11 11:46:45 -07:00
Florian Mayer
8acef12030
[NFC] [scudo] remove DCHECK (#84255)
this gets checked in StackDepot::init anyway
2024-03-06 15:45:49 -08:00
Fabio D'Urso
cda413087c
[scudo] Do not unmap the memory containing the this object in unmapRingBuffer (#83034) 2024-02-27 00:00:20 +01:00
Florian Mayer
6dd6d487d0
[NFC] Make RingBuffer an atomic pointer (#82547)
This will allow us to atomically swap out RingBuffer and StackDepot.

Patched into AOSP and ran debuggerd_tests.
2024-02-23 11:28:20 -08:00
Florian Mayer
6ddb25ed9c
[scudo] increase frames per stack to 16 for stack depot (#82427)
8 was very low and it is likely that in real workloads we have more than
an average of 8 frames per stack given on Android we have 3 at the
bottom: __start_main, __libc_init, main, and three at the top: malloc,
scudo_malloc and Allocator::allocate. That leaves 2 frames for
application code, which is clearly unreasonable.
2024-02-22 11:19:02 -08:00
Florian Mayer
d17eade22a
Do not call disable / enable on null depot (#82542)
depot can be null if allocation_ring_buffer_size=0
2024-02-21 14:28:34 -08:00
Florian Mayer
3da0166331 Reland^2 "[scudo] resize stack depot for allocation ring buffer"
Fix some warnings by matching types.

This reverts commit e1164d063558b1e89f20109d83c079caae1825d8.
2024-02-16 22:59:53 -08:00
Florian Mayer
e1164d0635
Revert "Reland "[scudo] resize stack depot for allocation ring buffer"" (#82088)
Reverts llvm/llvm-project#81028
2024-02-16 17:58:54 -08:00
Florian Mayer
aff6cb4957
Reland "[scudo] resize stack depot for allocation ring buffer" (#81028)
First commit of the stack is a clean reland, second is  the fix.

There was a typo in the `static_assert` that meant we were asserting the
size of the pointer, not the struct.

Also changed `alignas` to be more intuitive, but that is NFC.

Ran builds in Android here: https://r.android.com/2954411
2024-02-16 17:10:54 -08:00
Florian Mayer
c3291253c3
Revert "[scudo] [MTE] resize stack depot for allocation ring buffer" (#80777)
Reverts llvm/llvm-project#74515

Broke build: https://lab.llvm.org/buildbot/#/builders/75/builds/42512
2024-02-05 16:56:39 -08:00
Florian Mayer
eff77d8456
[scudo] [MTE] resize stack depot for allocation ring buffer (#74515)
Co-authored-by: ChiaHungDuan <f103119@gmail.com>
2024-02-05 16:47:02 -08:00
ChiaHungDuan
8ce036d539
[scudo] Add ScopedTSD to avoid releasing TSD manually (#80061)
This makes the use of TSD be RAII style and avoid the exposing of the
type of TSDs.

Also move some thread safety analyses from static to runtime because of
its limitation. Even we mark some code path as NO_THREAD_SAFETY_ANALYSIS
but we still have the `assertLocked()` cover the correctness.
2024-02-05 14:36:04 -08:00
Evgenii Stepanov
c82f3caf56
[scudo] Add StackDepot lock to enable/disable. (#79670)
Scudo grabs all allocator locks in a pthread_atfork before the fork, and releases them after. This allows malloc to be used in a fork child of a multithreaded process, which is expressly forbidden by the standard, but very widely used. For example, Android's init uses std::string after fork when spawning services in android::init::EnterNamespaces and other places.

Any lock that is necessary to serve an allocator call must be handled this way. Otherwise there is a possibility that the lock is held during the call to fork, which results in it being held forever in the child process, and the next operation that needs it deadlocks.
2024-01-29 14:22:24 -08:00
Florian Mayer
4f9ad0f856 [scudo] [NFC] remove unused method 2023-12-18 18:54:32 -08:00
Florian Mayer
a5bdc4a460
[scudo] do not store size inside ring buffer (#74541) 2023-12-08 17:16:56 -08:00
Evgenii Stepanov
54c30953b9
Do not initialize the allocator on free(nullptr). (#74366)
free(nullptr) is guaranteed by ISO and POSIX to be a no-op, we should not pay for the overhead of maybeInit() in this case.

Additionally, Bionic calls free(nullptr) before the allocator settings are finalized.
Scudo should not run allocator initialization at that time. Doing so
causes various bad things to happen, like mapping primary regions with
the wrong PROT_MTE setting.
2023-12-04 13:45:37 -08:00
ChiaHungDuan
75867f8e4a
[scudo] Fix realloc hooks behavior (#74149)
`realloc` may involve both allocation and deallocation. Given that the
reporting the events is not atomic and which may lead the hook user to a
false case that the double-use pattern happens, we always report the old
pointer is released and report the new allocation afterward (even it's
the same pointer).

This also fixes that we didn't report the new size when it doesn't need
to allocate a new space.
2023-12-01 14:41:43 -08:00
Florian Mayer
a66dc461ac
[scudo] allocation_ring_buffer_size <= 0 disables buffer (#71791)
Prevent a null pointer exception for allocation_ring_buffer_size < 0.
2023-11-14 14:58:05 -08:00
ChiaHungDuan
b53ff43d36
[scudo] Improve the message of region exhaustion (#68444)
In this CL, we move the printing of allocator stats from primary.h to
combined.h. This will also dump the secondary stats and reduce the log
spam when an OOM happens

Also change the symbol `F` to `E` to indicate region pages exhausted. It
means the region can't map more pages for blocks but it may still have
free blocks to allocate. `F` may hint the failure of fatel error in the
region. Also update the related comments.
2023-10-07 05:31:33 +08:00
ChiaHungDuan
ea2036e1e5
[scudo] Fix the use of ASSERT_CAPABILITY in TSD (#68273)
In getCache()/getQuarantineCache(), they return a reference to variable
guarded by a mutex. After #67776, thread-safey analysis checks if a
variable return by reference has the lock held. The ASSERT_CAPABILITY
only claims after calling that function, the lock will be held. But not
asserting that the lock is held *before* calling that function.

In the patch, we switch to use REQUIRES() and assertLocked() to mark the
code paths. Also remove the misused ASSERT_CAPABILITY.

Fixes #67795, #67796
2023-10-05 11:35:41 -07:00
ChiaHungDuan
54ddd0762b
[scudo] Update header without read-modify-write operation (#66955)
We used to update the deallocated block with
atomic_compare_exchange_strong to ensure the concurrent double-free will
be detected. However, this operation incurs huge performance overhead
which takes over 50% execution time in deallocate(). Given that we
already have the checksum to guard the most double-free cases and other
block verifications in the primary allocator, use atomic-store instead.
2023-09-28 13:05:35 -07:00
Fabio D'Urso
42069258c6 [scudo] Use MemMap for AllocationRingBuffer
Reviewed By: Chia-hungDuan

Differential Revision: https://reviews.llvm.org/D159466
2023-09-26 10:34:26 +02:00
Fabio D'Urso
fdb29f7db5 [scudo] Rename AllocatorRingBuffer into scudo:ring_buffer
To maintain the convention of Scudo names starting with "scudo:",
which is used by some tooling to categorize memory usage.

Reviewed By: Chia-hungDuan

Differential Revision: https://reviews.llvm.org/D157102
2023-09-06 11:23:27 +02:00
Christopher Ferris
c8bf93dba0 [scudo] Remove RSS checking code.
The RSS code is not very useful and can be replicated by using
ulimit. Remove it and remove the options associated with it.

Reviewed By: Chia-hungDuan

Differential Revision: https://reviews.llvm.org/D159155
2023-08-30 12:35:14 -07:00
Chia-hung Duan
4f76810d48 [scudo] Detach the hooks from Scudo's internal implementation
Move the invocation of hooks from Scudo internal to wrapper_c.cpp and
wrapper_c_bionic.cpp respectively. Therefore, Scudo's core algorithm
doesnt need to worry about the reentrant of hooks and leave the caring
of reentrant to the hook users.

Reviewed By: hctim, cferris, chelfi

Differential Revision: https://reviews.llvm.org/D152188
2023-08-25 16:19:56 +00:00
Chia-hung Duan
5f771c9936 [scudo] Support dumping fragmentation data in SizeClassAllocator64
This tells the number of pages that still have blocks in-used, i.e.,
those pages can't do releaseToOSMaybe(). Along with the information of
getStats() and RSS usage from the system (like smaps), we can tell if
the heuristic in releaseToOSMaybe() works well in certain scenarios.

Here's the sample output:
```
    Fragmentation Stats: SizeClassAllocator64: page size = 4096
      01 (    32): inuse/total blocks:    275/   416 inuse/total pages:      4/     4 inuse bytes:     16K
      02 (    48): inuse/total blocks:    182/   312 inuse/total pages:      4/     4 inuse bytes:     16K
      03 (    64): inuse/total blocks:    169/   312 inuse/total pages:      5/     5 inuse bytes:     20K
      ...
      32 (  1040): inuse/total blocks:     90/   152 inuse/total pages:     37/    39 inuse bytes:    148K
      33 (  1168): inuse/total blocks:    136/   232 inuse/total pages:     64/    67 inuse bytes:    256K
      34 (  1296): inuse/total blocks:    138/   226 inuse/total pages:     68/    72 inuse bytes:    272K
      35 (  1424): inuse/total blocks:    140/   232 inuse/total pages:     78/    81 inuse bytes:    312K
      36 (  1552): inuse/total blocks:    157/   248 inuse/total pages:     89/    94 inuse bytes:    356K
      ...
```

SizeClassAllocator32 requires further refactoring to support this.

Reviewed By: cferris

Differential Revision: https://reviews.llvm.org/D158225
2023-08-21 17:26:42 +00:00
Christopher Ferris
867f2d9e5c [scudo] Make Options a reference for functions.
Modify all places that use the Options structure to be a const
reference. The underlying structure is a u32 so making it a
reference doesn't really do anything. However, if the structure
changes in the future it already works and avoids future coders
wondering why a structure is being passed by value. This also
makes it clear that the Options should not be modified in those functions.

Reviewed By: Chia-hungDuan

Differential Revision: https://reviews.llvm.org/D156372
2023-07-26 18:21:39 -07:00
Chia-hung Duan
bce8c9e3d7 [scudo] Try to release pages after unlocking the TSDs
This increases the parallelism and the usage of TSDs

Reviewed By: cferris

Differential Revision: https://reviews.llvm.org/D152988
2023-07-06 17:40:26 +00:00
Evgenii Stepanov
ed552f2151 [scudo] Disable OddEvenTags by default.
Scudo has zero-tagged headers between any two allocation that will catch
a linear buffer overflow of up to 16 bytes. OddEvenTags extends this
guarantee to one chunk of the given SizeClass at the cost of the reduced
entropy for all heap tags (i.e. lower chance to catch use-after-free and
large overflows).

Given that the first 16 bytes are already deterministic, I feel this is
a bad tradeoff.

Differential Revision: https://reviews.llvm.org/D152984
2023-06-15 16:36:27 -07:00
Chia-hung Duan
2f08a08f61 [scudo] Support importing custom configuration
To define custom allocation, you only need to put the configuration in
custom_scudo_config.h and define two required aliases, then you will be
switched to the customized config and the tests will also run with your
configuration.

In this CL, we also have a minor refactor the structure of
configuration. Now the essential fields are put under the associated
hierarchy and which will make the defining new configuration easier.

Reviewed By: cferris

Differential Revision: https://reviews.llvm.org/D150481
2023-06-02 16:28:00 +00:00
Fabio D'Urso
0f1a92ba30 [scudo] Deallocate the AllocatorRingBuffer too in unmapTestOnly
The AllocatorRingBuffer is allocated dynamically when Allocator is
initialized. This patch adds a corresponding deinitialization call in
unmapTestOnly, to avoid running out of virtual memory if the tests are run
a large number of times on memory-constrained platforms.

Reviewed By: Chia-hungDuan

Differential Revision: https://reviews.llvm.org/D149266
2023-05-16 20:09:08 +00:00
Chia-hung Duan
6a057e7b51 [scudo] Drain caches when release with M_PURGE_ALL
This will drain both quarantine and local caches.

Reviewed By: cferris

Differential Revision: https://reviews.llvm.org/D150242
2023-05-10 20:20:17 +00:00