aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/new_delete_capture.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/new_delete_capture.cc')
-rw-r--r--src/google/protobuf/new_delete_capture.cc121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/google/protobuf/new_delete_capture.cc b/src/google/protobuf/new_delete_capture.cc
new file mode 100644
index 00000000..baf42ffe
--- /dev/null
+++ b/src/google/protobuf/new_delete_capture.cc
@@ -0,0 +1,121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file exists for testing allocation behavior when using arenas by hooking
+// new/delete. It is a copy of //experimental/mvels/util/new_delete_capture.cc.
+
+#include <google/protobuf/new_delete_capture.h>
+
+#include <pthread.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/malloc_hook.h>
+#include <google/protobuf/stubs/spinlock.h>
+
+namespace google {
+namespace {
+
+pthread_t gthread;
+protobuf_unittest::NewDeleteCapture *ghooked_instance = NULL;
+SpinLock gspinlock(base::LINKER_INITIALIZED);
+
+} // namespace
+
+namespace protobuf_unittest {
+
+NewDeleteCapture::NewDeleteCapture()
+ : alloc_count_(0),
+ alloc_size_(0),
+ alloc_ptr_(NULL),
+ free_count_(0),
+ free_ptr_(NULL) {}
+
+NewDeleteCapture::~NewDeleteCapture() { Unhook(); }
+
+void NewDeleteCapture::Reset() {
+ alloc_count_ = 0;
+ alloc_size_ = 0;
+ free_count_ = 0;
+ alloc_ptr_ = NULL;
+ free_ptr_ = NULL;
+}
+
+bool NewDeleteCapture::Hook(bool reset) {
+ SpinLockHolder spinlock(&gspinlock);
+ if (ghooked_instance != this) {
+ GOOGLE_CHECK(ghooked_instance == NULL)
+ << " NewDeleteCapture can have only 1 active instance";
+ GOOGLE_CHECK(MallocHook::AddNewHook(NewHook));
+ GOOGLE_CHECK(MallocHook::AddDeleteHook(DeleteHook));
+ gthread = pthread_self();
+ ghooked_instance = this;
+ if (reset) {
+ Reset();
+ }
+ return true;
+ }
+ return false;
+}
+
+bool NewDeleteCapture::Unhook() {
+ SpinLockHolder spinlock(&gspinlock);
+ if (ghooked_instance == this) {
+ gthread = pthread_t();
+ ghooked_instance = NULL;
+ GOOGLE_CHECK(MallocHook::RemoveDeleteHook(DeleteHook));
+ GOOGLE_CHECK(MallocHook::RemoveNewHook(NewHook));
+ return true;
+ }
+ return false;
+}
+
+void NewDeleteCapture::NewHook(const void *ptr, size_t size) {
+ SpinLockHolder spinlock(&gspinlock);
+ if (gthread == pthread_self()) {
+ auto &rthis = *ghooked_instance;
+ if (++rthis.alloc_count_ == 1) {
+ rthis.alloc_size_ = size;
+ rthis.alloc_ptr_ = ptr;
+ }
+ }
+}
+
+void NewDeleteCapture::DeleteHook(const void *ptr) {
+ SpinLockHolder spinlock(&gspinlock);
+ if (gthread == pthread_self()) {
+ auto &rthis = *ghooked_instance;
+ if (++rthis.free_count_ == 1) {
+ rthis.free_ptr_ = ptr;
+ }
+ }
+}
+
+} // namespace protobuf_unittest
+} // namespace google