Skip to content

Commit 4394c8a

Browse files
bnoordhuistrevnorris
authored andcommitted
smalloc: rework double free bug fix
Rework the fix from commit 6810132 in a way that removes ~60 lines of code. The bug was introduced in commit e87ceb2 (mea culpa) and is at its core a pointer aliasing bug where sometimes two independent pointers existed that pointed to the same chunk of heap memory. Signed-off-by: Trevor Norris <trev.norris@gmail.com>
1 parent 6f95284 commit 4394c8a

1 file changed

Lines changed: 42 additions & 100 deletions

File tree

src/smalloc.cc

Lines changed: 42 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -54,148 +54,93 @@ using v8::WeakCallbackData;
5454
using v8::kExternalUnsignedByteArray;
5555

5656

57-
template <typename Payload>
5857
class CallbackInfo {
5958
public:
59+
static inline void Free(char* data, void* hint);
6060
static inline CallbackInfo* New(Isolate* isolate,
6161
Handle<Object> object,
62-
Payload payload);
63-
inline void Dispose();
62+
FreeCallback callback,
63+
void* hint = 0);
64+
inline void Dispose(Isolate* isolate);
6465
inline Persistent<Object>* persistent();
65-
inline Payload* payload();
6666
private:
6767
static void WeakCallback(const WeakCallbackData<Object, CallbackInfo>&);
68+
inline void WeakCallback(Isolate* isolate, Local<Object> object);
6869
inline CallbackInfo(Isolate* isolate,
6970
Handle<Object> object,
70-
Payload payload);
71+
FreeCallback callback,
72+
void* hint);
7173
~CallbackInfo();
7274
Persistent<Object> persistent_;
73-
Payload payload_;
74-
};
75-
76-
77-
class Free {
78-
public:
79-
explicit Free(char* data);
80-
void WeakCallback(Isolate* isolate,
81-
Local<Object> object,
82-
CallbackInfo<Free>* info);
83-
private:
84-
char* const data_;
85-
};
86-
87-
88-
class Dispose {
89-
public:
90-
typedef void (*Callback)(char* data, void* hint);
91-
Dispose(Callback callback, void* hint);
92-
void WeakCallback(Isolate* isolate,
93-
Local<Object> object,
94-
CallbackInfo<Dispose>* info);
95-
private:
96-
Callback const callback_;
75+
FreeCallback const callback_;
9776
void* const hint_;
77+
DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
9878
};
9979

10080

101-
template <typename Payload>
102-
CallbackInfo<Payload>* CallbackInfo<Payload>::New(Isolate* isolate,
103-
Handle<Object> object,
104-
Payload payload) {
105-
return new CallbackInfo(isolate, object, payload);
81+
void CallbackInfo::Free(char* data, void*) {
82+
::free(data);
10683
}
10784

10885

109-
template <typename Payload>
110-
void CallbackInfo<Payload>::Dispose() {
111-
delete this;
86+
CallbackInfo* CallbackInfo::New(Isolate* isolate,
87+
Handle<Object> object,
88+
FreeCallback callback,
89+
void* hint) {
90+
return new CallbackInfo(isolate, object, callback, hint);
11291
}
11392

11493

115-
template <typename Payload>
116-
Persistent<Object>* CallbackInfo<Payload>::persistent() {
117-
return &persistent_;
94+
void CallbackInfo::Dispose(Isolate* isolate) {
95+
WeakCallback(isolate, PersistentToLocal(isolate, persistent_));
11896
}
11997

12098

121-
template <typename Payload>
122-
Payload* CallbackInfo<Payload>::payload() {
123-
return &payload_;
99+
Persistent<Object>* CallbackInfo::persistent() {
100+
return &persistent_;
124101
}
125102

126103

127-
template <typename Payload>
128-
CallbackInfo<Payload>::CallbackInfo(Isolate* isolate,
129-
Handle<Object> object,
130-
Payload payload)
104+
CallbackInfo::CallbackInfo(Isolate* isolate,
105+
Handle<Object> object,
106+
FreeCallback callback,
107+
void* hint)
131108
: persistent_(isolate, object),
132-
payload_(payload) {
109+
callback_(callback),
110+
hint_(hint) {
133111
persistent_.SetWeak(this, WeakCallback);
134112
persistent_.SetWrapperClassId(ALLOC_ID);
135113
persistent_.MarkIndependent();
136114
}
137115

138116

139-
template <typename Payload>
140-
CallbackInfo<Payload>::~CallbackInfo() {
117+
CallbackInfo::~CallbackInfo() {
141118
persistent_.Reset();
142119
}
143120

144121

145-
template <typename Payload>
146-
void CallbackInfo<Payload>::WeakCallback(
122+
void CallbackInfo::WeakCallback(
147123
const WeakCallbackData<Object, CallbackInfo>& data) {
148-
CallbackInfo* info = data.GetParameter();
149-
info->payload()->WeakCallback(data.GetIsolate(), data.GetValue(), info);
124+
data.GetParameter()->WeakCallback(data.GetIsolate(), data.GetValue());
150125
}
151126

152127

153-
Free::Free(char* data) : data_(data) {
154-
}
155-
156-
157-
void Free::WeakCallback(Isolate* isolate,
158-
Local<Object> object,
159-
CallbackInfo<Free>* info) {
160-
size_t length = object->GetIndexedPropertiesExternalArrayDataLength();
161-
if (length > 0)
162-
free(data_);
163-
enum ExternalArrayType array_type =
164-
object->GetIndexedPropertiesExternalArrayDataType();
165-
size_t array_size = ExternalArraySize(array_type);
166-
CHECK_GT(array_size, 0);
167-
CHECK_GE(array_size * length, length); // Overflow check.
168-
length *= array_size;
169-
int64_t change_in_bytes = -static_cast<int64_t>(length);
170-
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
171-
info->Dispose();
172-
}
173-
174-
175-
Dispose::Dispose(Callback callback, void* hint)
176-
: callback_(callback),
177-
hint_(hint) {
178-
}
179-
180-
181-
void Dispose::WeakCallback(Isolate* isolate,
182-
Local<Object> object,
183-
CallbackInfo<Dispose>* info) {
184-
char* data =
185-
static_cast<char*>(object->GetIndexedPropertiesExternalArrayData());
186-
size_t len = object->GetIndexedPropertiesExternalArrayDataLength();
128+
void CallbackInfo::WeakCallback(Isolate* isolate, Local<Object> object) {
129+
void* array_data = object->GetIndexedPropertiesExternalArrayData();
130+
size_t array_length = object->GetIndexedPropertiesExternalArrayDataLength();
187131
enum ExternalArrayType array_type =
188132
object->GetIndexedPropertiesExternalArrayDataType();
189133
size_t array_size = ExternalArraySize(array_type);
190134
CHECK_GT(array_size, 0);
191135
if (array_size > 1) {
192-
CHECK_GT(len * array_size, len); // Overflow check.
193-
len *= array_size;
136+
CHECK_GT(array_length * array_size, array_length); // Overflow check.
137+
array_length *= array_size;
194138
}
195-
int64_t change_in_bytes = -static_cast<int64_t>(len + sizeof(*info));
139+
object->SetIndexedPropertiesToExternalArrayData(NULL, array_type, 0);
140+
int64_t change_in_bytes = -static_cast<int64_t>(array_length + sizeof(*this));
196141
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
197-
callback_(data, hint_);
198-
info->Dispose();
142+
callback_(static_cast<char*>(array_data), hint_);
143+
delete this;
199144
}
200145

201146

@@ -403,7 +348,7 @@ void Alloc(Environment* env,
403348
env->isolate()->AdjustAmountOfExternalAllocatedMemory(length);
404349
size_t size = length / ExternalArraySize(type);
405350
obj->SetIndexedPropertiesToExternalArrayData(data, type, size);
406-
CallbackInfo<Free>::New(env->isolate(), obj, Free(data));
351+
CallbackInfo::New(env->isolate(), obj, CallbackInfo::Free);
407352
}
408353

409354

@@ -421,10 +366,8 @@ void AllocDispose(Environment* env, Handle<Object> obj) {
421366
Local<Value> ext_v = obj->GetHiddenValue(env->smalloc_p_string());
422367
if (ext_v->IsExternal()) {
423368
Local<External> ext = ext_v.As<External>();
424-
CallbackInfo<Free>* info = static_cast<CallbackInfo<Free>*>(ext->Value());
425-
Local<Object> object = PersistentToLocal(env->isolate(),
426-
*info->persistent());
427-
info->payload()->WeakCallback(env->isolate(), object, info);
369+
CallbackInfo* info = static_cast<CallbackInfo*>(ext->Value());
370+
info->Dispose(env->isolate());
428371
return;
429372
}
430373
}
@@ -484,8 +427,7 @@ void Alloc(Environment* env,
484427
Isolate* isolate = env->isolate();
485428
HandleScope handle_scope(isolate);
486429
env->set_using_smalloc_alloc_cb(true);
487-
CallbackInfo<Dispose>* info =
488-
CallbackInfo<Dispose>::New(isolate, obj, Dispose(fn, hint));
430+
CallbackInfo* info = CallbackInfo::New(isolate, obj, fn, hint);
489431
obj->SetHiddenValue(env->smalloc_p_string(), External::New(isolate, info));
490432
isolate->AdjustAmountOfExternalAllocatedMemory(length + sizeof(*info));
491433
size_t size = length / ExternalArraySize(type);

0 commit comments

Comments
 (0)