Browse Source

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>
archived-io.js-v0.10
Ben Noordhuis 11 years ago
committed by Trevor Norris
parent
commit
4394c8a9b3
  1. 142
      src/smalloc.cc

142
src/smalloc.cc

@ -54,148 +54,93 @@ using v8::WeakCallbackData;
using v8::kExternalUnsignedByteArray; using v8::kExternalUnsignedByteArray;
template <typename Payload>
class CallbackInfo { class CallbackInfo {
public: public:
static inline void Free(char* data, void* hint);
static inline CallbackInfo* New(Isolate* isolate, static inline CallbackInfo* New(Isolate* isolate,
Handle<Object> object, Handle<Object> object,
Payload payload); FreeCallback callback,
inline void Dispose(); void* hint = 0);
inline void Dispose(Isolate* isolate);
inline Persistent<Object>* persistent(); inline Persistent<Object>* persistent();
inline Payload* payload();
private: private:
static void WeakCallback(const WeakCallbackData<Object, CallbackInfo>&); static void WeakCallback(const WeakCallbackData<Object, CallbackInfo>&);
inline void WeakCallback(Isolate* isolate, Local<Object> object);
inline CallbackInfo(Isolate* isolate, inline CallbackInfo(Isolate* isolate,
Handle<Object> object, Handle<Object> object,
Payload payload); FreeCallback callback,
void* hint);
~CallbackInfo(); ~CallbackInfo();
Persistent<Object> persistent_; Persistent<Object> persistent_;
Payload payload_; FreeCallback const callback_;
};
class Free {
public:
explicit Free(char* data);
void WeakCallback(Isolate* isolate,
Local<Object> object,
CallbackInfo<Free>* info);
private:
char* const data_;
};
class Dispose {
public:
typedef void (*Callback)(char* data, void* hint);
Dispose(Callback callback, void* hint);
void WeakCallback(Isolate* isolate,
Local<Object> object,
CallbackInfo<Dispose>* info);
private:
Callback const callback_;
void* const hint_; void* const hint_;
DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
}; };
template <typename Payload> void CallbackInfo::Free(char* data, void*) {
CallbackInfo<Payload>* CallbackInfo<Payload>::New(Isolate* isolate, ::free(data);
Handle<Object> object,
Payload payload) {
return new CallbackInfo(isolate, object, payload);
} }
template <typename Payload> CallbackInfo* CallbackInfo::New(Isolate* isolate,
void CallbackInfo<Payload>::Dispose() { Handle<Object> object,
delete this; FreeCallback callback,
void* hint) {
return new CallbackInfo(isolate, object, callback, hint);
} }
template <typename Payload> void CallbackInfo::Dispose(Isolate* isolate) {
Persistent<Object>* CallbackInfo<Payload>::persistent() { WeakCallback(isolate, PersistentToLocal(isolate, persistent_));
return &persistent_;
} }
template <typename Payload> Persistent<Object>* CallbackInfo::persistent() {
Payload* CallbackInfo<Payload>::payload() { return &persistent_;
return &payload_;
} }
template <typename Payload> CallbackInfo::CallbackInfo(Isolate* isolate,
CallbackInfo<Payload>::CallbackInfo(Isolate* isolate, Handle<Object> object,
Handle<Object> object, FreeCallback callback,
Payload payload) void* hint)
: persistent_(isolate, object), : persistent_(isolate, object),
payload_(payload) { callback_(callback),
hint_(hint) {
persistent_.SetWeak(this, WeakCallback); persistent_.SetWeak(this, WeakCallback);
persistent_.SetWrapperClassId(ALLOC_ID); persistent_.SetWrapperClassId(ALLOC_ID);
persistent_.MarkIndependent(); persistent_.MarkIndependent();
} }
template <typename Payload> CallbackInfo::~CallbackInfo() {
CallbackInfo<Payload>::~CallbackInfo() {
persistent_.Reset(); persistent_.Reset();
} }
template <typename Payload> void CallbackInfo::WeakCallback(
void CallbackInfo<Payload>::WeakCallback(
const WeakCallbackData<Object, CallbackInfo>& data) { const WeakCallbackData<Object, CallbackInfo>& data) {
CallbackInfo* info = data.GetParameter(); data.GetParameter()->WeakCallback(data.GetIsolate(), data.GetValue());
info->payload()->WeakCallback(data.GetIsolate(), data.GetValue(), info);
} }
Free::Free(char* data) : data_(data) { void CallbackInfo::WeakCallback(Isolate* isolate, Local<Object> object) {
} void* array_data = object->GetIndexedPropertiesExternalArrayData();
size_t array_length = object->GetIndexedPropertiesExternalArrayDataLength();
void Free::WeakCallback(Isolate* isolate,
Local<Object> object,
CallbackInfo<Free>* info) {
size_t length = object->GetIndexedPropertiesExternalArrayDataLength();
if (length > 0)
free(data_);
enum ExternalArrayType array_type =
object->GetIndexedPropertiesExternalArrayDataType();
size_t array_size = ExternalArraySize(array_type);
CHECK_GT(array_size, 0);
CHECK_GE(array_size * length, length); // Overflow check.
length *= array_size;
int64_t change_in_bytes = -static_cast<int64_t>(length);
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
info->Dispose();
}
Dispose::Dispose(Callback callback, void* hint)
: callback_(callback),
hint_(hint) {
}
void Dispose::WeakCallback(Isolate* isolate,
Local<Object> object,
CallbackInfo<Dispose>* info) {
char* data =
static_cast<char*>(object->GetIndexedPropertiesExternalArrayData());
size_t len = object->GetIndexedPropertiesExternalArrayDataLength();
enum ExternalArrayType array_type = enum ExternalArrayType array_type =
object->GetIndexedPropertiesExternalArrayDataType(); object->GetIndexedPropertiesExternalArrayDataType();
size_t array_size = ExternalArraySize(array_type); size_t array_size = ExternalArraySize(array_type);
CHECK_GT(array_size, 0); CHECK_GT(array_size, 0);
if (array_size > 1) { if (array_size > 1) {
CHECK_GT(len * array_size, len); // Overflow check. CHECK_GT(array_length * array_size, array_length); // Overflow check.
len *= array_size; array_length *= array_size;
} }
int64_t change_in_bytes = -static_cast<int64_t>(len + sizeof(*info)); object->SetIndexedPropertiesToExternalArrayData(NULL, array_type, 0);
int64_t change_in_bytes = -static_cast<int64_t>(array_length + sizeof(*this));
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes); isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
callback_(data, hint_); callback_(static_cast<char*>(array_data), hint_);
info->Dispose(); delete this;
} }
@ -403,7 +348,7 @@ void Alloc(Environment* env,
env->isolate()->AdjustAmountOfExternalAllocatedMemory(length); env->isolate()->AdjustAmountOfExternalAllocatedMemory(length);
size_t size = length / ExternalArraySize(type); size_t size = length / ExternalArraySize(type);
obj->SetIndexedPropertiesToExternalArrayData(data, type, size); obj->SetIndexedPropertiesToExternalArrayData(data, type, size);
CallbackInfo<Free>::New(env->isolate(), obj, Free(data)); CallbackInfo::New(env->isolate(), obj, CallbackInfo::Free);
} }
@ -421,10 +366,8 @@ void AllocDispose(Environment* env, Handle<Object> obj) {
Local<Value> ext_v = obj->GetHiddenValue(env->smalloc_p_string()); Local<Value> ext_v = obj->GetHiddenValue(env->smalloc_p_string());
if (ext_v->IsExternal()) { if (ext_v->IsExternal()) {
Local<External> ext = ext_v.As<External>(); Local<External> ext = ext_v.As<External>();
CallbackInfo<Free>* info = static_cast<CallbackInfo<Free>*>(ext->Value()); CallbackInfo* info = static_cast<CallbackInfo*>(ext->Value());
Local<Object> object = PersistentToLocal(env->isolate(), info->Dispose(env->isolate());
*info->persistent());
info->payload()->WeakCallback(env->isolate(), object, info);
return; return;
} }
} }
@ -484,8 +427,7 @@ void Alloc(Environment* env,
Isolate* isolate = env->isolate(); Isolate* isolate = env->isolate();
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
env->set_using_smalloc_alloc_cb(true); env->set_using_smalloc_alloc_cb(true);
CallbackInfo<Dispose>* info = CallbackInfo* info = CallbackInfo::New(isolate, obj, fn, hint);
CallbackInfo<Dispose>::New(isolate, obj, Dispose(fn, hint));
obj->SetHiddenValue(env->smalloc_p_string(), External::New(isolate, info)); obj->SetHiddenValue(env->smalloc_p_string(), External::New(isolate, info));
isolate->AdjustAmountOfExternalAllocatedMemory(length + sizeof(*info)); isolate->AdjustAmountOfExternalAllocatedMemory(length + sizeof(*info));
size_t size = length / ExternalArraySize(type); size_t size = length / ExternalArraySize(type);

Loading…
Cancel
Save