summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-02-18 17:30:10 +0100
committerAnna Henningsen <anna@addaleax.net>2019-02-25 02:01:03 +0100
commit376735345088d4b37e0e289c2eb7720419ed37ee (patch)
tree4771426f776ca9e7e30fab08e1a188f8959b29af /src
parenta8ba838e1a94c17ecf7a290c1951040d2957cb62 (diff)
downloadandroid-node-v8-376735345088d4b37e0e289c2eb7720419ed37ee.tar.gz
android-node-v8-376735345088d4b37e0e289c2eb7720419ed37ee.tar.bz2
android-node-v8-376735345088d4b37e0e289c2eb7720419ed37ee.zip
src: add debugging array allocator
Add a subclass of `ArrayBufferAllocator` that performs additional debug checking, which in particular verifies that: - All `ArrayBuffer` backing stores have been allocated with this allocator, or have been explicitly marked as coming from a compatible source. - All memory allocated by the allocator has been freed once it is destroyed. PR-URL: https://github.com/nodejs/node/pull/26207 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/api/environment.cc76
-rw-r--r--src/node_internals.h23
-rw-r--r--src/node_options.cc4
-rw-r--r--src/node_options.h1
4 files changed, 103 insertions, 1 deletions
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 7b6de8ba8d..6a56ddb511 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -75,8 +75,82 @@ void* ArrayBufferAllocator::Allocate(size_t size) {
return UncheckedMalloc(size);
}
+DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
+ CHECK(allocations_.empty());
+}
+
+void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
+ Mutex::ScopedLock lock(mutex_);
+ void* data = ArrayBufferAllocator::Allocate(size);
+ RegisterPointerInternal(data, size);
+ return data;
+}
+
+void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
+ Mutex::ScopedLock lock(mutex_);
+ void* data = ArrayBufferAllocator::AllocateUninitialized(size);
+ RegisterPointerInternal(data, size);
+ return data;
+}
+
+void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
+ Mutex::ScopedLock lock(mutex_);
+ UnregisterPointerInternal(data, size);
+ ArrayBufferAllocator::Free(data, size);
+}
+
+void* DebuggingArrayBufferAllocator::Reallocate(void* data,
+ size_t old_size,
+ size_t size) {
+ Mutex::ScopedLock lock(mutex_);
+ void* ret = ArrayBufferAllocator::Reallocate(data, old_size, size);
+ if (ret == nullptr) {
+ if (size == 0) // i.e. equivalent to free().
+ UnregisterPointerInternal(data, old_size);
+ return nullptr;
+ }
+
+ if (data != nullptr) {
+ auto it = allocations_.find(data);
+ CHECK_NE(it, allocations_.end());
+ allocations_.erase(it);
+ }
+
+ RegisterPointerInternal(ret, size);
+ return ret;
+}
+
+void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
+ Mutex::ScopedLock lock(mutex_);
+ RegisterPointerInternal(data, size);
+}
+
+void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
+ Mutex::ScopedLock lock(mutex_);
+ UnregisterPointerInternal(data, size);
+}
+
+void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
+ size_t size) {
+ if (data == nullptr) return;
+ auto it = allocations_.find(data);
+ CHECK_NE(it, allocations_.end());
+ CHECK_EQ(it->second, size);
+ allocations_.erase(it);
+}
+
+void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
+ size_t size) {
+ if (data == nullptr) return;
+ CHECK_EQ(allocations_.count(data), 0);
+ allocations_[data] = size;
+}
+
ArrayBufferAllocator* CreateArrayBufferAllocator() {
- return new ArrayBufferAllocator();
+ if (per_process::cli_options->debug_arraybuffer_allocations)
+ return new DebuggingArrayBufferAllocator();
+ else
+ return new ArrayBufferAllocator();
}
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
diff --git a/src/node_internals.h b/src/node_internals.h
index 6f09708371..9ac2b0a331 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -109,11 +109,34 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
void* AllocateUninitialized(size_t size) override
{ return node::UncheckedMalloc(size); }
void Free(void* data, size_t) override { free(data); }
+ virtual void* Reallocate(void* data, size_t old_size, size_t size) {
+ return static_cast<void*>(
+ UncheckedRealloc<char>(static_cast<char*>(data), size));
+ }
+ virtual void RegisterPointer(void* data, size_t size) {}
+ virtual void UnregisterPointer(void* data, size_t size) {}
private:
uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
};
+class DebuggingArrayBufferAllocator final : public ArrayBufferAllocator {
+ public:
+ ~DebuggingArrayBufferAllocator() override;
+ void* Allocate(size_t size) override;
+ void* AllocateUninitialized(size_t size) override;
+ void Free(void* data, size_t size) override;
+ void* Reallocate(void* data, size_t old_size, size_t size) override;
+ void RegisterPointer(void* data, size_t size) override;
+ void UnregisterPointer(void* data, size_t size) override;
+
+ private:
+ void RegisterPointerInternal(void* data, size_t size);
+ void UnregisterPointerInternal(void* data, size_t size);
+ Mutex mutex_;
+ std::unordered_map<void*, size_t> allocations_;
+};
+
namespace Buffer {
v8::MaybeLocal<v8::Object> Copy(Environment* env, const char* data, size_t len);
v8::MaybeLocal<v8::Object> New(Environment* env, size_t size);
diff --git a/src/node_options.cc b/src/node_options.cc
index 937298e0d8..bdd39d5d71 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -387,6 +387,10 @@ PerProcessOptionsParser::PerProcessOptionsParser() {
"SlowBuffer instances",
&PerProcessOptions::zero_fill_all_buffers,
kAllowedInEnvironment);
+ AddOption("--debug-arraybuffer-allocations",
+ "", /* undocumented, only for debugging */
+ &PerProcessOptions::debug_arraybuffer_allocations,
+ kAllowedInEnvironment);
AddOption("--security-reverts", "", &PerProcessOptions::security_reverts);
AddOption("--completion-bash",
diff --git a/src/node_options.h b/src/node_options.h
index fe2e1034c9..9313c4a538 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -158,6 +158,7 @@ class PerProcessOptions : public Options {
uint64_t max_http_header_size = 8 * 1024;
int64_t v8_thread_pool_size = 4;
bool zero_fill_all_buffers = false;
+ bool debug_arraybuffer_allocations = false;
std::vector<std::string> security_reverts;
bool print_bash_completion = false;