1 // Copyright 2013 The Chromium 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 "mojo/public/bindings/lib/buffer.h" 6 7 #include <assert.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <algorithm> 12 13 #include "mojo/public/bindings/lib/bindings_serialization.h" 14 #include "mojo/public/bindings/lib/bindings_support.h" 15 16 // Scrub memory in debug builds to help catch use-after-free bugs. 17 #ifdef NDEBUG 18 #define DEBUG_SCRUB(address, size) (void) (address), (void) (size) 19 #else 20 #define DEBUG_SCRUB(address, size) memset(address, 0xCD, size) 21 #endif 22 23 namespace mojo { 24 25 //----------------------------------------------------------------------------- 26 27 Buffer::Buffer() { 28 previous_ = BindingsSupport::Get()->SetCurrentBuffer(this); 29 } 30 31 Buffer::~Buffer() { 32 Buffer* buf MOJO_ALLOW_UNUSED = 33 BindingsSupport::Get()->SetCurrentBuffer(previous_); 34 assert(buf == this); 35 } 36 37 Buffer* Buffer::current() { 38 return BindingsSupport::Get()->GetCurrentBuffer(); 39 } 40 41 //----------------------------------------------------------------------------- 42 43 namespace internal { 44 45 ScratchBuffer::ScratchBuffer() 46 : overflow_(NULL) { 47 fixed_.next = NULL; 48 fixed_.cursor = fixed_data_; 49 fixed_.end = fixed_data_ + kMinSegmentSize; 50 } 51 52 ScratchBuffer::~ScratchBuffer() { 53 // Invoke destructors in reverse order to mirror allocation order. 54 std::deque<PendingDestructor>::reverse_iterator it; 55 for (it = pending_dtors_.rbegin(); it != pending_dtors_.rend(); ++it) 56 it->func(it->address); 57 58 while (overflow_) { 59 Segment* doomed = overflow_; 60 overflow_ = overflow_->next; 61 DEBUG_SCRUB(doomed, doomed->end - reinterpret_cast<char*>(doomed)); 62 free(doomed); 63 } 64 DEBUG_SCRUB(fixed_data_, sizeof(fixed_data_)); 65 } 66 67 void* ScratchBuffer::Allocate(size_t delta, Destructor func) { 68 delta = internal::Align(delta); 69 70 void* result = AllocateInSegment(&fixed_, delta); 71 if (!result) { 72 if (overflow_) 73 result = AllocateInSegment(overflow_, delta); 74 75 if (!result) { 76 AddOverflowSegment(delta); 77 result = AllocateInSegment(overflow_, delta); 78 } 79 } 80 81 if (func) { 82 PendingDestructor dtor; 83 dtor.func = func; 84 dtor.address = result; 85 pending_dtors_.push_back(dtor); 86 } 87 return result; 88 } 89 90 void* ScratchBuffer::AllocateInSegment(Segment* segment, size_t delta) { 91 void* result; 92 if (static_cast<size_t>(segment->end - segment->cursor) >= delta) { 93 result = segment->cursor; 94 memset(result, 0, delta); 95 segment->cursor += delta; 96 } else { 97 result = NULL; 98 } 99 return result; 100 } 101 102 void ScratchBuffer::AddOverflowSegment(size_t delta) { 103 if (delta < kMinSegmentSize) 104 delta = kMinSegmentSize; 105 106 // Ensure segment buffer is aligned. 107 size_t segment_size = internal::Align(sizeof(Segment)) + delta; 108 109 Segment* segment = static_cast<Segment*>(malloc(segment_size)); 110 segment->next = overflow_; 111 segment->cursor = reinterpret_cast<char*>(segment + 1); 112 segment->end = segment->cursor + delta; 113 114 overflow_ = segment; 115 } 116 117 //----------------------------------------------------------------------------- 118 119 FixedBuffer::FixedBuffer(size_t size) 120 : ptr_(NULL), 121 cursor_(0), 122 size_(internal::Align(size)) { 123 ptr_ = static_cast<char*>(calloc(size_, 1)); 124 } 125 126 FixedBuffer::~FixedBuffer() { 127 free(ptr_); 128 } 129 130 void* FixedBuffer::Allocate(size_t delta, Destructor dtor) { 131 assert(!dtor); 132 133 delta = internal::Align(delta); 134 135 // TODO(darin): Using <assert.h> is probably not going to cut it. 136 assert(delta > 0); 137 assert(cursor_ + delta <= size_); 138 if (cursor_ + delta > size_) 139 return NULL; 140 141 char* result = ptr_ + cursor_; 142 cursor_ += delta; 143 144 return result; 145 } 146 147 void* FixedBuffer::Leak() { 148 char* ptr = ptr_; 149 ptr_ = NULL; 150 cursor_ = 0; 151 size_ = 0; 152 return ptr; 153 } 154 155 } // namespace internal 156 } // namespace mojo 157