Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 238fa57

Browse filesBrowse files
committed
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: #26207 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Backport-PR-URL: #26302 Reviewed-By: Michaël Zasso <targos@protonmail.com>
1 parent 20dc172 commit 238fa57
Copy full SHA for 238fa57

File tree

Expand file treeCollapse file tree

4 files changed

+103
-1
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+103
-1
lines changed
Open diff view settings
Collapse file

‎src/api/environment.cc‎

Copy file name to clipboardExpand all lines: src/api/environment.cc
+75-1Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,82 @@ void* ArrayBufferAllocator::Allocate(size_t size) {
7575
return UncheckedMalloc(size);
7676
}
7777

78+
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
79+
CHECK(allocations_.empty());
80+
}
81+
82+
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
83+
Mutex::ScopedLock lock(mutex_);
84+
void* data = ArrayBufferAllocator::Allocate(size);
85+
RegisterPointerInternal(data, size);
86+
return data;
87+
}
88+
89+
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
90+
Mutex::ScopedLock lock(mutex_);
91+
void* data = ArrayBufferAllocator::AllocateUninitialized(size);
92+
RegisterPointerInternal(data, size);
93+
return data;
94+
}
95+
96+
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
97+
Mutex::ScopedLock lock(mutex_);
98+
UnregisterPointerInternal(data, size);
99+
ArrayBufferAllocator::Free(data, size);
100+
}
101+
102+
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
103+
size_t old_size,
104+
size_t size) {
105+
Mutex::ScopedLock lock(mutex_);
106+
void* ret = ArrayBufferAllocator::Reallocate(data, old_size, size);
107+
if (ret == nullptr) {
108+
if (size == 0) // i.e. equivalent to free().
109+
UnregisterPointerInternal(data, old_size);
110+
return nullptr;
111+
}
112+
113+
if (data != nullptr) {
114+
auto it = allocations_.find(data);
115+
CHECK_NE(it, allocations_.end());
116+
allocations_.erase(it);
117+
}
118+
119+
RegisterPointerInternal(ret, size);
120+
return ret;
121+
}
122+
123+
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
124+
Mutex::ScopedLock lock(mutex_);
125+
RegisterPointerInternal(data, size);
126+
}
127+
128+
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
129+
Mutex::ScopedLock lock(mutex_);
130+
UnregisterPointerInternal(data, size);
131+
}
132+
133+
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
134+
size_t size) {
135+
if (data == nullptr) return;
136+
auto it = allocations_.find(data);
137+
CHECK_NE(it, allocations_.end());
138+
CHECK_EQ(it->second, size);
139+
allocations_.erase(it);
140+
}
141+
142+
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
143+
size_t size) {
144+
if (data == nullptr) return;
145+
CHECK_EQ(allocations_.count(data), 0);
146+
allocations_[data] = size;
147+
}
148+
78149
ArrayBufferAllocator* CreateArrayBufferAllocator() {
79-
return new ArrayBufferAllocator();
150+
if (per_process::cli_options->debug_arraybuffer_allocations)
151+
return new DebuggingArrayBufferAllocator();
152+
else
153+
return new ArrayBufferAllocator();
80154
}
81155

82156
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
Collapse file

‎src/node_internals.h‎

Copy file name to clipboardExpand all lines: src/node_internals.h
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,34 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
109109
void* AllocateUninitialized(size_t size) override
110110
{ return node::UncheckedMalloc(size); }
111111
void Free(void* data, size_t) override { free(data); }
112+
virtual void* Reallocate(void* data, size_t old_size, size_t size) {
113+
return static_cast<void*>(
114+
UncheckedRealloc<char>(static_cast<char*>(data), size));
115+
}
116+
virtual void RegisterPointer(void* data, size_t size) {}
117+
virtual void UnregisterPointer(void* data, size_t size) {}
112118

113119
private:
114120
uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
115121
};
116122

123+
class DebuggingArrayBufferAllocator final : public ArrayBufferAllocator {
124+
public:
125+
~DebuggingArrayBufferAllocator() override;
126+
void* Allocate(size_t size) override;
127+
void* AllocateUninitialized(size_t size) override;
128+
void Free(void* data, size_t size) override;
129+
void* Reallocate(void* data, size_t old_size, size_t size) override;
130+
void RegisterPointer(void* data, size_t size) override;
131+
void UnregisterPointer(void* data, size_t size) override;
132+
133+
private:
134+
void RegisterPointerInternal(void* data, size_t size);
135+
void UnregisterPointerInternal(void* data, size_t size);
136+
Mutex mutex_;
137+
std::unordered_map<void*, size_t> allocations_;
138+
};
139+
117140
namespace Buffer {
118141
v8::MaybeLocal<v8::Object> Copy(Environment* env, const char* data, size_t len);
119142
v8::MaybeLocal<v8::Object> New(Environment* env, size_t size);
Collapse file

‎src/node_options.cc‎

Copy file name to clipboardExpand all lines: src/node_options.cc
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ PerProcessOptionsParser::PerProcessOptionsParser() {
369369
"SlowBuffer instances",
370370
&PerProcessOptions::zero_fill_all_buffers,
371371
kAllowedInEnvironment);
372+
AddOption("--debug-arraybuffer-allocations",
373+
"", /* undocumented, only for debugging */
374+
&PerProcessOptions::debug_arraybuffer_allocations,
375+
kAllowedInEnvironment);
372376

373377
AddOption("--security-reverts", "", &PerProcessOptions::security_reverts);
374378
AddOption("--completion-bash",
Collapse file

‎src/node_options.h‎

Copy file name to clipboardExpand all lines: src/node_options.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ class PerProcessOptions : public Options {
168168
uint64_t max_http_header_size = 8 * 1024;
169169
int64_t v8_thread_pool_size = 4;
170170
bool zero_fill_all_buffers = false;
171+
bool debug_arraybuffer_allocations = false;
171172

172173
std::vector<std::string> security_reverts;
173174
bool print_bash_completion = false;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.