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