Skip to content

Commit f6ea0c2

Browse files
bnoordhuisindutny
authored andcommitted
src: fix segfaults, fix 32 bits integer negation
Make calls to v8::Isolate::AdjustAmountOfExternalAllocatedMemory() take special care when negating 32 bits unsigned types like size_t. Before this commit, values were negated before they got promoted to 64 bits, meaning that on 32 bits architectures, a value like 42 got cast to 4294967254 instead of -42. That in turn made the garbage collector start scavenging like crazy because it thought the system was out of memory. That's bad enough but calls to AdjustAmountOfExternalAllocatedMemory() were made from weak callbacks, i.e. at a time when the garbage collector was already busy. It triggered asserts in debug builds and caused random crashes and memory corruption in release builds. The behavior in release builds is arguably a V8 bug and should perhaps be reported upstream. Partially fixes nodejs#7309 but requires further bug fixes to src/smalloc.cc that I'll address in a follow-up commit.
1 parent a3dca9a commit f6ea0c2

3 files changed

Lines changed: 12 additions & 8 deletions

File tree

src/node_zlib.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ class ZCtx : public AsyncWrap {
110110

111111
if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
112112
(void)deflateEnd(&strm_);
113-
env()->isolate()
114-
->AdjustAmountOfExternalAllocatedMemory(-kDeflateContextSize);
113+
int64_t change_in_bytes = -static_cast<int64_t>(kDeflateContextSize);
114+
env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
115115
} else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
116116
mode_ == UNZIP) {
117117
(void)inflateEnd(&strm_);
118-
env()->isolate()
119-
->AdjustAmountOfExternalAllocatedMemory(-kInflateContextSize);
118+
int64_t change_in_bytes = -static_cast<int64_t>(kInflateContextSize);
119+
env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
120120
}
121121
mode_ = NONE;
122122

src/smalloc.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ void TargetCallback(const WeakCallbackData<Object, char>& data) {
291291
assert(array_size * len >= len);
292292
len *= array_size;
293293
if (info != NULL && len > 0) {
294-
data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(-len);
294+
int64_t change_in_bytes = -static_cast<int64_t>(len);
295+
data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
295296
free(info);
296297
}
297298

@@ -338,7 +339,8 @@ void AllocDispose(Environment* env, Handle<Object> obj) {
338339
free(data);
339340
}
340341
if (length != 0) {
341-
env->isolate()->AdjustAmountOfExternalAllocatedMemory(-length);
342+
int64_t change_in_bytes = -static_cast<int64_t>(length);
343+
env->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
342344
}
343345
}
344346

@@ -407,7 +409,8 @@ void TargetFreeCallback(Isolate* isolate,
407409
assert(len * array_size > len);
408410
len *= array_size;
409411
}
410-
isolate->AdjustAmountOfExternalAllocatedMemory(-(len + sizeof(*cb_info)));
412+
int64_t change_in_bytes = -static_cast<int64_t>(len + sizeof(*cb_info));
413+
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
411414
cb_info->p_obj.Reset();
412415
cb_info->cb(data, cb_info->hint);
413416
delete cb_info;

src/string_bytes.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ class ExternString: public ResourceType {
5050
public:
5151
~ExternString() {
5252
delete[] data_;
53-
isolate()->AdjustAmountOfExternalAllocatedMemory(-length_);
53+
int64_t change_in_bytes = -static_cast<int64_t>(length_);
54+
isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
5455
}
5556

5657
const TypeName* data() const {

0 commit comments

Comments
 (0)