Skip to content

Commit 7e067ab

Browse files
committedJun 20, 2018
[Sanitizers] Remove OOM/BadRequest allocator error handling policies.
Summary: Remove the generic error nadling policies and handle each allocator error explicitly. Although more verbose, it allows for more comprehensive, precise and actionable allocator related failure reports. This finishes up the series of changes of the particular sanitizer allocators, improves the internal allocator error reporting and removes now unused policies. Reviewers: vitalybuka, cryptoad Subscribers: kubamracek, delcypher, #sanitizers, llvm-commits Differential Revision: https://reviews.llvm.org/D48328 llvm-svn: 335147
1 parent 8e3e374 commit 7e067ab

6 files changed

+43
-68
lines changed
 

‎compiler-rt/lib/asan/asan_errors.cc

+8-8
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ void ErrorCallocOverflow::Print() {
182182
count, size, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
183183
Printf("%s", d.Default());
184184
stack->Print();
185-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
185+
PrintHintAllocatorCannotReturnNull();
186186
ReportErrorSummary(scariness.GetDescription(), stack);
187187
}
188188

@@ -198,7 +198,7 @@ void ErrorPvallocOverflow::Print() {
198198
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
199199
Printf("%s", d.Default());
200200
stack->Print();
201-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
201+
PrintHintAllocatorCannotReturnNull();
202202
ReportErrorSummary(scariness.GetDescription(), stack);
203203
}
204204

@@ -212,7 +212,7 @@ void ErrorInvalidAllocationAlignment::Print() {
212212
alignment, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
213213
Printf("%s", d.Default());
214214
stack->Print();
215-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
215+
PrintHintAllocatorCannotReturnNull();
216216
ReportErrorSummary(scariness.GetDescription(), stack);
217217
}
218218

@@ -234,7 +234,7 @@ void ErrorInvalidAlignedAllocAlignment::Print() {
234234
#endif
235235
Printf("%s", d.Default());
236236
stack->Print();
237-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
237+
PrintHintAllocatorCannotReturnNull();
238238
ReportErrorSummary(scariness.GetDescription(), stack);
239239
}
240240

@@ -250,7 +250,7 @@ void ErrorInvalidPosixMemalignAlignment::Print() {
250250
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
251251
Printf("%s", d.Default());
252252
stack->Print();
253-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
253+
PrintHintAllocatorCannotReturnNull();
254254
ReportErrorSummary(scariness.GetDescription(), stack);
255255
}
256256

@@ -266,7 +266,7 @@ void ErrorAllocationSizeTooBig::Print() {
266266
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
267267
Printf("%s", d.Default());
268268
stack->Print();
269-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
269+
PrintHintAllocatorCannotReturnNull();
270270
ReportErrorSummary(scariness.GetDescription(), stack);
271271
}
272272

@@ -278,7 +278,7 @@ void ErrorRssLimitExceeded::Print() {
278278
"soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb);
279279
Printf("%s", d.Default());
280280
stack->Print();
281-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
281+
PrintHintAllocatorCannotReturnNull();
282282
ReportErrorSummary(scariness.GetDescription(), stack);
283283
}
284284

@@ -290,7 +290,7 @@ void ErrorOutOfMemory::Print() {
290290
"0x%zx bytes\n", requested_size);
291291
Printf("%s", d.Default());
292292
stack->Print();
293-
PrintHintAllocatorCannotReturnNull("ASAN_OPTIONS");
293+
PrintHintAllocatorCannotReturnNull();
294294
ReportErrorSummary(scariness.GetDescription(), stack);
295295
}
296296

‎compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc

+19-38
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,19 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
140140

141141
const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
142142

143+
static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) {
144+
SetAllocatorOutOfMemory();
145+
Report("FATAL: %s: internal allocator is out of memory trying to allocate "
146+
"0x%zx bytes\n", SanitizerToolName, requested_size);
147+
Die();
148+
}
149+
143150
void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {
144151
if (size + sizeof(u64) < size)
145152
return nullptr;
146153
void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment);
147154
if (UNLIKELY(!p))
148-
return DieOnFailure::OnOOM();
155+
ReportInternalAllocatorOutOfMemory(size + sizeof(u64));
149156
((u64*)p)[0] = kBlockMagic;
150157
return (char*)p + sizeof(u64);
151158
}
@@ -160,13 +167,17 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
160167
CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
161168
void *p = RawInternalRealloc(addr, size, cache);
162169
if (UNLIKELY(!p))
163-
return DieOnFailure::OnOOM();
170+
ReportInternalAllocatorOutOfMemory(size);
164171
return (char*)p + sizeof(u64);
165172
}
166173

167174
void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
168-
if (UNLIKELY(CheckForCallocOverflow(count, size)))
169-
return DieOnFailure::OnBadRequest();
175+
if (UNLIKELY(CheckForCallocOverflow(count, size))) {
176+
Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) "
177+
"cannot be represented in type size_t\n", SanitizerToolName, count,
178+
size);
179+
Die();
180+
}
170181
void *p = InternalAlloc(count * size, cache);
171182
if (LIKELY(p))
172183
internal_memset(p, 0, count * size);
@@ -215,6 +226,8 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
215226
low_level_alloc_callback = callback;
216227
}
217228

229+
// Allocator's OOM and other errors handling support.
230+
218231
static atomic_uint8_t allocator_out_of_memory = {0};
219232
static atomic_uint8_t allocator_may_return_null = {0};
220233

@@ -226,15 +239,6 @@ void SetAllocatorOutOfMemory() {
226239
atomic_store_relaxed(&allocator_out_of_memory, 1);
227240
}
228241

229-
// Prints error message and kills the program.
230-
void NORETURN ReportAllocatorCannotReturnNull() {
231-
Report("%s's allocator is terminating the process instead of returning 0\n",
232-
SanitizerToolName);
233-
Report("If you don't like this behavior set allocator_may_return_null=1\n");
234-
CHECK(0);
235-
Die();
236-
}
237-
238242
bool AllocatorMayReturnNull() {
239243
return atomic_load(&allocator_may_return_null, memory_order_relaxed);
240244
}
@@ -244,32 +248,9 @@ void SetAllocatorMayReturnNull(bool may_return_null) {
244248
memory_order_relaxed);
245249
}
246250

247-
void *ReturnNullOrDieOnFailure::OnBadRequest() {
248-
if (AllocatorMayReturnNull())
249-
return nullptr;
250-
ReportAllocatorCannotReturnNull();
251-
}
252-
253-
void *ReturnNullOrDieOnFailure::OnOOM() {
254-
atomic_store_relaxed(&allocator_out_of_memory, 1);
255-
if (AllocatorMayReturnNull())
256-
return nullptr;
257-
ReportAllocatorCannotReturnNull();
258-
}
259-
260-
void NORETURN *DieOnFailure::OnBadRequest() {
261-
ReportAllocatorCannotReturnNull();
262-
}
263-
264-
void NORETURN *DieOnFailure::OnOOM() {
265-
atomic_store_relaxed(&allocator_out_of_memory, 1);
266-
ReportAllocatorCannotReturnNull();
267-
}
268-
269-
// Prints hint message.
270-
void PrintHintAllocatorCannotReturnNull(const char *options_name) {
251+
void PrintHintAllocatorCannotReturnNull() {
271252
Report("HINT: if you don't care about these errors you may set "
272-
"%s=allocator_may_return_null=1\n", options_name);
253+
"allocator_may_return_null=1\n");
273254
}
274255

275256
} // namespace __sanitizer

‎compiler-rt/lib/sanitizer_common/sanitizer_allocator.h

+4-16
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,14 @@ extern const char *SecondaryAllocatorName;
3434
bool AllocatorMayReturnNull();
3535
void SetAllocatorMayReturnNull(bool may_return_null);
3636

37-
// Allocator failure handling policies:
38-
// Implements AllocatorMayReturnNull policy, returns null when the flag is set,
39-
// dies otherwise.
40-
struct ReturnNullOrDieOnFailure {
41-
static void *OnBadRequest();
42-
static void *OnOOM();
43-
};
44-
// Always dies on the failure.
45-
struct DieOnFailure {
46-
static void NORETURN *OnBadRequest();
47-
static void NORETURN *OnOOM();
48-
};
49-
50-
void PrintHintAllocatorCannotReturnNull(const char *options_name);
51-
5237
// Returns true if allocator detected OOM condition. Can be used to avoid memory
53-
// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called.
38+
// hungry operations.
5439
bool IsAllocatorOutOfMemory();
40+
// Should be called by a particular allocator when OOM is detected.
5541
void SetAllocatorOutOfMemory();
5642

43+
void PrintHintAllocatorCannotReturnNull();
44+
5745
// Allocators call these callbacks on mmap/munmap.
5846
struct NoOpMapUnmapCallback {
5947
void OnMap(uptr p, uptr size) const { }

‎compiler-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,11 @@ struct SizeClassAllocator32LocalCache {
260260
class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]);
261261
// Failure to allocate a batch while releasing memory is non recoverable.
262262
// TODO(alekseys): Figure out how to do it without allocating a new batch.
263-
if (UNLIKELY(!b))
264-
DieOnFailure::OnOOM();
263+
if (UNLIKELY(!b)) {
264+
Report("FATAL: Internal error: %s's allocator failed to allocate a "
265+
"transfer batch.\n", SanitizerToolName);
266+
Die();
267+
}
265268
b->SetFromArray(&c->batch[first_idx_to_drain], count);
266269
c->count -= count;
267270
allocator->DeallocateBatch(&stats_, class_id, b);

‎compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ class SizeClassAllocator64 {
118118
// Failure to allocate free array space while releasing memory is non
119119
// recoverable.
120120
if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg,
121-
new_num_freed_chunks)))
122-
DieOnFailure::OnOOM();
121+
new_num_freed_chunks))) {
122+
Report("FATAL: Internal error: %s's allocator exhausted the free list "
123+
"space for size class %zd (%zd bytes).\n", SanitizerToolName,
124+
class_id, ClassIdToSize(class_id));
125+
Die();
126+
}
123127
for (uptr i = 0; i < n_chunks; i++)
124128
free_array[old_num_chunks + i] = chunks[i];
125129
region->num_freed_chunks = new_num_freed_chunks;

‎compiler-rt/lib/sanitizer_common/sanitizer_allocator_report.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ class ScopedAllocatorErrorReport {
3030
~ScopedAllocatorErrorReport() {
3131
Printf("%s", d.Default());
3232
stack->Print();
33-
// TODO(alekseyshl): Define SanitizerToolOptionsEnvVarName and use it there.
34-
PrintHintAllocatorCannotReturnNull("");
33+
PrintHintAllocatorCannotReturnNull();
3534
ReportErrorSummary(error_summary, stack);
3635
}
3736

0 commit comments

Comments
 (0)
Please sign in to comment.