Skip to content

Commit 873cc21

Browse files
committed
honor allocator_may_return_null when set through user-function in windows
1 parent 2f55de4 commit 873cc21

File tree

5 files changed

+77
-2
lines changed

5 files changed

+77
-2
lines changed

compiler-rt/lib/asan/asan_flags.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ void InitializeFlags() {
240240

241241
DisplayHelpMessages(&asan_parser);
242242
ProcessFlags();
243+
244+
// TODO: Update other globals and data structures that may change after
245+
// initialization due to these flags potentially changing.
246+
// These flags can be identified by looking at the work done in
247+
// `AsanInitInternal` inside of `asan_rtl.cpp`.
248+
// See GH issue 'https://github.com/llvm/llvm-project/issues/117925' for details.
249+
SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
243250
});
244251

245252
# if CAN_SANITIZE_UB

compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@ static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) {
8585

8686
void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {
8787
void *p = RawInternalAlloc(size, cache, alignment);
88-
if (UNLIKELY(!p))
88+
if (UNLIKELY(!p)) {
89+
if (AllocatorMayReturnNull()){
90+
return nullptr;
91+
}
8992
ReportInternalAllocatorOutOfMemory(size);
93+
}
9094
return p;
9195
}
9296

compiler-rt/lib/sanitizer_common/sanitizer_win.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,23 @@ void UnmapOrDie(void *addr, uptr size, bool raw_report) {
164164
static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type,
165165
const char *mmap_type) {
166166
error_t last_error = GetLastError();
167-
if (last_error == ERROR_NOT_ENOUGH_MEMORY)
167+
168+
// Assumption: VirtualAlloc is the last system call that was invoked before
169+
// this method.
170+
// VirtualAlloc emits one of 2 error codes when running out of memory
171+
// 1. ERROR_NOT_ENOUGH_MEMORY:
172+
// There's not enough memory to execute the command
173+
// 2. ERROR_INVALID_PARAMETER:
174+
// VirtualAlloc will return this if the request would allocate memory at an
175+
// address exceeding or being very close to the maximum application address
176+
// (the `lpMaximumApplicationAddress` field within the `SystemInfo` struct).
177+
// This does not seem to be officially documented, but is corroborated here:
178+
// https://stackoverflow.com/questions/45833674/why-does-virtualalloc-fail-for-lpaddress-greater-than-0x6ffffffffff
179+
180+
// Note - It's possible that 'ERROR_COMMITMENT_LIMIT' needs to be handled here as well.
181+
// It is currently not handled due to the lack of a reproducer that induces the error code.
182+
if (last_error == ERROR_NOT_ENOUGH_MEMORY ||
183+
last_error == ERROR_INVALID_PARAMETER)
168184
return nullptr;
169185
ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error);
170186
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clangxx_asan -O0 %s -o %t
2+
// RUN: %run %t 2>&1
3+
// CHECK: Success
4+
5+
#include <cstdint>
6+
#include <cstdlib>
7+
#include <limits>
8+
9+
// On Windows, flags configured through the user-defined function `__asan_default_options`
10+
// are suspected to not always be honored according to this GH issue:
11+
// https://github.com/llvm/llvm-project/issues/117925
12+
// This issue is resolved for the `allocator_may_return_null` flag, but not for all others.
13+
// This test ensures we do not regress on `allocator_may_return_null` specifically.
14+
extern "C" __declspec(dllexport) extern const char *__asan_default_options() {
15+
return "allocator_may_return_null=1";
16+
}
17+
18+
int main() {
19+
// Attempt to allocate an excessive amount of memory, which should
20+
// terminate the program unless `allocator_may_return_null` is set.
21+
size_t max = std::numeric_limits<size_t>::max();
22+
23+
free(malloc(max));
24+
printf("Success");
25+
return 0;
26+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clangxx_asan -O0 %s -o %t
2+
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
3+
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
4+
5+
// CHECK1: exceeds maximum supported size
6+
// CHECK1: ABORT
7+
8+
// CHECK2: Success
9+
10+
#include <cstdint>
11+
#include <cstdlib>
12+
#include <limits>
13+
14+
int main() {
15+
// Attempt to allocate an excessive amount of memory, which should
16+
// terminate the program unless `allocator_may_return_null` is set.
17+
size_t max = std::numeric_limits<size_t>::max();
18+
19+
free(malloc(max));
20+
printf("Success");
21+
return 0;
22+
}

0 commit comments

Comments
 (0)