This releases the requirement that we need to preserve the memory for
all regions at the beginning. It needs a huge amount of contiguous pages
and which may be a challenge in certain cases. Therefore, adding a new
flag, EnableContiguousRegions, to indicate whether we want to allocate
all the regions next to each other.
Note that once the EnableContiguousRegions is disabled,
EnableRandomOffset becomes irrelevant because the base of each region is
already random.
Clean-up all of the calls and remove the redundant == 0 checks.
There is only one small visible change. For non-Android, the memalign
function will now fail if alignment is zero. Before this would have
passed.
It appears that qemu does not actually cause mmap to fail when calling
setrlimit to limit the address space size. In the two tests that use
setrlimit, detect if mmap still works and skip the tests in that case.
Since all Android targets should support setrlimit, compile out the mmap
check code for them.
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.
In the StackDepot::isValid function, there is work to validate the
TabMask variable. Unfortunately, if TabMask is set to the maximum
allowed value, TabSize = TabMask + 1 becomes zero and validation passes.
Disallow that case to prevent invalid reads into the Tab structure.
This reverts commit 36ca9a29025a2f678096e9545fa2ec44e8432592.
We were using the `time` as the seed while choosing a new TSD. To make
the access of TSDs evenly distributed, we require a higher precision in
`time`. Otherwise, many threads may result in having the same random
access pattern on TSDs because they share the same `time` in certain
period. On Linux, CLOCK_MONOTONIC_COARSE usually adopts 4 ms precision.
This is way higher than the average accessing time of TSD (which is
usually less than 1 us). As a result, when multiple threads try to
select a new TSD in a 4 ms interval, they share the same `time` seed and
end up choosing and congesting on the same TSD.
Do not abort if a vector cannot increase its own capacity. In that case,
push_back calls silently fail.
Modify the ScopedString implementation so that it no longer requires two
passes to do the format. Move the helper functions to be private member
functions so that they can use push_back directly. This allows the
capacity to be increased under the hood and/or silently discards data if
the capacity is exceeded and cannot be increased.
Add new tests for the Vector and ScopedString for capacity increase
failures.
Doing this so that if a map call fails, and we are attempting to write
an error string, we can still get some of the message dumped. This also
avoids crashing in Scudo code, and makes the caller handle any failures.
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.
All these unit tests already include ${COMPILER_RT_GTEST_SOURCE} as an
input source file and the target llvm_gtest does not exist for
standalone builds. Currently the DEPS argument is ignored for standalone
builds so the missing target is not a problem, but as part of fixing a
build race for standalone builds I am planning to include those
dependencies in COMPILER_RT_TEST_STANDALONE_BUILD_LIBS configurations.
Reviewed By: vitalybuka
Pull Request: https://github.com/llvm/llvm-project/pull/83649
Don't use multiple tagged pages at the beginning of an allocation, since
it prevents using such allocations for memrefs, and mappings aren't
reused anyway since Trusty uses MapAllocatorNoCache.
Upstreamed from https://r.android.com/2537251.
Co-authored-by: Marco Nelissen <marcone@google.com>
Reverts llvm/llvm-project#70390
There's a bug caught by
`ScudoCombinedTestReallocateInPlaceStress_DefaultConfig.ReallocateInPlaceStress`
with gwp asan. It's an easy fix but given that this is a major change, I
would like to revert it first
Instead of always storing the same number of blocks as cached, we prefer
increasing the utilization by saving more blocks in a single
TransferBatch. This may slightly impact the performance, but it will
save a lot of memory used by BatchClassId (especially for larger
blocks).
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.
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
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.
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.
To enable the condition variable, you have to define both
UseConditionVariable and the ConditionVariableT. Otherwise, it'll be
disabled. However, you may want to disable the condition variable by
setting UseConditionVariable=false, for example, while measuring the
performance and you want to turn it off temporarily. Instead of
requiring the removal of the variable, examining its value makes more
sense.
almost NFC, just that now we accept INT_MIN and INT_MAX
as discussed in https://r.android.com/2831100, but I didn't add the
*ValueEnd != Value check because I want to keep this change
behaviour-keeping.
`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. In general, this can be
resolved on the hook side. To alleviate the task of handling it, we add
two new hooks to mark the range so that the hook user can combine those
calls together.
These will be used in follow-up CLs, committing this separately because
it needs a matching change in AOSP. This way we can avoid complicated
multi-repo rollbacks if something is wrong with the follow up CLs.
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.
`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.