summaryrefslogtreecommitdiffstats
path: root/mojo/public/bindings/lib/scratch_buffer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/public/bindings/lib/scratch_buffer.cc')
-rw-r--r--mojo/public/bindings/lib/scratch_buffer.cc98
1 files changed, 98 insertions, 0 deletions
diff --git a/mojo/public/bindings/lib/scratch_buffer.cc b/mojo/public/bindings/lib/scratch_buffer.cc
new file mode 100644
index 0000000..abfb5fe
--- /dev/null
+++ b/mojo/public/bindings/lib/scratch_buffer.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/bindings/lib/scratch_buffer.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "mojo/public/bindings/lib/bindings_serialization.h"
+
+// Scrub memory in debug builds to help catch use-after-free bugs.
+#ifdef NDEBUG
+#define DEBUG_SCRUB(address, size) (void) (address), (void) (size)
+#else
+#define DEBUG_SCRUB(address, size) memset(address, 0xCD, size)
+#endif
+
+namespace mojo {
+namespace internal {
+
+ScratchBuffer::ScratchBuffer()
+ : overflow_(NULL) {
+ fixed_.next = NULL;
+ fixed_.cursor = fixed_data_;
+ fixed_.end = fixed_data_ + kMinSegmentSize;
+}
+
+ScratchBuffer::~ScratchBuffer() {
+ // Invoke destructors in reverse order to mirror allocation order.
+ std::deque<PendingDestructor>::reverse_iterator it;
+ for (it = pending_dtors_.rbegin(); it != pending_dtors_.rend(); ++it)
+ it->func(it->address);
+
+ while (overflow_) {
+ Segment* doomed = overflow_;
+ overflow_ = overflow_->next;
+ DEBUG_SCRUB(doomed, doomed->end - reinterpret_cast<char*>(doomed));
+ free(doomed);
+ }
+ DEBUG_SCRUB(fixed_data_, sizeof(fixed_data_));
+}
+
+void* ScratchBuffer::Allocate(size_t delta, Destructor func) {
+ delta = internal::Align(delta);
+
+ void* result = AllocateInSegment(&fixed_, delta);
+ if (!result) {
+ if (overflow_)
+ result = AllocateInSegment(overflow_, delta);
+
+ if (!result) {
+ AddOverflowSegment(delta);
+ result = AllocateInSegment(overflow_, delta);
+ }
+ }
+
+ if (func) {
+ PendingDestructor dtor;
+ dtor.func = func;
+ dtor.address = result;
+ pending_dtors_.push_back(dtor);
+ }
+ return result;
+}
+
+void* ScratchBuffer::AllocateInSegment(Segment* segment, size_t delta) {
+ void* result;
+ if (static_cast<size_t>(segment->end - segment->cursor) >= delta) {
+ result = segment->cursor;
+ memset(result, 0, delta);
+ segment->cursor += delta;
+ } else {
+ result = NULL;
+ }
+ return result;
+}
+
+void ScratchBuffer::AddOverflowSegment(size_t delta) {
+ if (delta < kMinSegmentSize)
+ delta = kMinSegmentSize;
+
+ // Ensure segment buffer is aligned.
+ size_t segment_size = internal::Align(sizeof(Segment)) + delta;
+
+ Segment* segment = static_cast<Segment*>(malloc(segment_size));
+ segment->next = overflow_;
+ segment->cursor = reinterpret_cast<char*>(segment + 1);
+ segment->end = segment->cursor + delta;
+
+ overflow_ = segment;
+}
+
+} // namespace internal
+} // namespace mojo