1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fbl/alloc_checker.h>
6
7 #include <zircon/assert.h>
8 #include <zircon/compiler.h>
9 #include <new>
10
11 namespace fbl {
12 namespace {
13
14 enum : unsigned {
15 alloc_armed = 1,
16 alloc_ok = 2,
17 };
18
panic_if_armed(unsigned state)19 void panic_if_armed(unsigned state) {
20 #if LK_DEBUGLEVEL > 1
21 if (state & alloc_armed)
22 ZX_PANIC("AllocChecker::check() needs to be called\n");
23 #endif
24 }
25
checked(size_t size,AllocChecker * ac,void * mem)26 void* checked(size_t size, AllocChecker* ac, void* mem) {
27 ac->arm(size, mem != nullptr);
28 return mem;
29 }
30
31 } // namespace
32
AllocChecker()33 AllocChecker::AllocChecker()
34 : state_(0u) {
35 }
36
~AllocChecker()37 AllocChecker::~AllocChecker() {
38 panic_if_armed(state_);
39 }
40
arm(size_t size,bool result)41 void AllocChecker::arm(size_t size, bool result) {
42 panic_if_armed(state_);
43 state_ = alloc_armed |
44 ((size == 0u) ? alloc_ok : (result ? alloc_ok : 0u));
45 }
46
check()47 bool AllocChecker::check() {
48 state_ &= ~alloc_armed;
49 return (state_ & alloc_ok) == alloc_ok;
50 }
51
52 // The std::nothrow_t overloads of operator new and operator new[] are
53 // the standard C++ library interfaces that return nullptr instead of
54 // using exceptions, i.e. the same semantics as malloc. We define our
55 // checked versions in terms of those rather than calling malloc
56 // directly to maintain the invariant that only allocations done via
57 // new are freed via delete, only allocations done via new[] are freed
58 // via delete[], and only allocations done via the C malloc family
59 // functions are freed via the C free function. The non-throwing
60 // operator new and operator new[] we call might be trivial ones like
61 // zxcpp's that actually just call malloc, or they might be ones that
62 // enforce this invariant (such as the ASan allocator).
63
64 } // namespace fbl
65
66 #if !_KERNEL
67
operator new(size_t size,fbl::AllocChecker * ac)68 void* operator new(size_t size, fbl::AllocChecker* ac) noexcept {
69 return fbl::checked(size, ac, operator new(size, std::nothrow_t()));
70 }
71
operator new[](size_t size,fbl::AllocChecker * ac)72 void* operator new[](size_t size, fbl::AllocChecker* ac) noexcept {
73 return fbl::checked(size, ac, operator new[](size, std::nothrow_t()));
74 }
75
76 #else // _KERNEL
77
operator new(size_t size,fbl::AllocChecker * ac)78 void* operator new(size_t size, fbl::AllocChecker* ac) noexcept {
79 void* operator new(size_t s, void* caller, const std::nothrow_t&) noexcept;
80 return fbl::checked(size, ac, operator new(size, __GET_CALLER(), std::nothrow_t()));
81 }
82
operator new[](size_t size,fbl::AllocChecker * ac)83 void* operator new[](size_t size, fbl::AllocChecker* ac) noexcept {
84 void* operator new[](size_t s, void* caller, const std::nothrow_t&) noexcept;
85 return fbl::checked(size, ac, operator new[](size, __GET_CALLER(), std::nothrow_t()));
86 }
87
88 #endif // !_KERNEL
89