-
Notifications
You must be signed in to change notification settings - Fork 41
fix(value): handle transfer-full, in arguments properly #303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -354,7 +354,7 @@ long GIArgumentToLength(GITypeInfo *type_info, GIArgument *arg, bool is_pointer) | |
} | ||
|
||
|
||
GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value) { | ||
GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value, GITransfer transfer) { | ||
GArray* g_array = NULL; | ||
bool zero_terminated = g_type_info_is_zero_terminated(type_info); | ||
|
||
|
@@ -382,8 +382,10 @@ GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value) { | |
for (int i = 0; i < length; i++) { | ||
auto value = Nan::Get(array, i).ToLocalChecked(); | ||
GIArgument arg; | ||
GITransfer inner_transfer = | ||
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer); | ||
|
||
if (V8ToGIArgument(element_info, &arg, value, true)) { | ||
if (V8ToGIArgument(element_info, &arg, value, true, inner_transfer)) { | ||
g_array_append_val (g_array, arg); | ||
} else { | ||
g_warning("V8ToGArray: couldnt convert value: %s", | ||
|
@@ -399,7 +401,7 @@ GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value) { | |
return g_array; | ||
} | ||
|
||
static void *V8ArrayToCArray(GITypeInfo *type_info, Local<Value> value) { | ||
static void *V8ArrayToCArray(GITypeInfo *type_info, Local<Value> value, GITransfer transfer) { | ||
auto array = Local<Array>::Cast (TO_OBJECT (value)); | ||
int length = array->Length(); | ||
|
||
|
@@ -413,8 +415,10 @@ static void *V8ArrayToCArray(GITypeInfo *type_info, Local<Value> value) { | |
auto value = Nan::Get(array, i).ToLocalChecked(); | ||
|
||
GIArgument arg; | ||
GITransfer inner_transfer = | ||
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer); | ||
|
||
if (V8ToGIArgument(element_info, &arg, value, true)) { | ||
if (V8ToGIArgument(element_info, &arg, value, true, inner_transfer)) { | ||
void* pointer = (void*)((ulong)result + i * element_size); | ||
memcpy(pointer, &arg, element_size); | ||
} else { | ||
|
@@ -453,15 +457,15 @@ static void *V8TypedArrayToCArray(GITypeInfo *type_info, Local<Value> value) { | |
return result; | ||
} | ||
|
||
void *V8ToCArray(GITypeInfo *type_info, Local<Value> value) { | ||
void *V8ToCArray(GITypeInfo *type_info, Local<Value> value, GITransfer transfer) { | ||
if (value->IsString()) { | ||
Local<String> string = TO_STRING (value); | ||
const char *utf8_data = *Nan::Utf8String(string); | ||
return g_strdup(utf8_data); | ||
} | ||
|
||
if (value->IsArray()) { | ||
return V8ArrayToCArray(type_info, value); | ||
return V8ArrayToCArray(type_info, value, transfer); | ||
} | ||
|
||
if (value->IsTypedArray()) { | ||
|
@@ -473,7 +477,7 @@ void *V8ToCArray(GITypeInfo *type_info, Local<Value> value) { | |
return NULL; | ||
} | ||
|
||
gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value) { | ||
gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value, GITransfer transfer) { | ||
|
||
// FIXME can @value be null? | ||
if (!value->IsArray()) { | ||
|
@@ -504,7 +508,10 @@ gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value) { | |
GIArgument arg; | ||
Local<Value> value = Nan::Get(array, i).ToLocalChecked(); | ||
|
||
if (!V8ToGIArgument(element_info, &arg, value, false)) { | ||
GITransfer inner_transfer = | ||
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer); | ||
|
||
if (!V8ToGIArgument(element_info, &arg, value, false, inner_transfer)) { | ||
g_warning("V8ToGList: couldnt convert value #%i to GIArgument", i); | ||
continue; | ||
} | ||
|
@@ -526,7 +533,7 @@ gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value) { | |
return list; | ||
} | ||
|
||
gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) { | ||
gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value, GITransfer transfer) { | ||
|
||
if (!value->IsObject()) { | ||
Nan::ThrowTypeError("Expected object"); | ||
|
@@ -587,21 +594,24 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) { | |
auto object = TO_OBJECT (value); | ||
auto keys = Nan::GetOwnPropertyNames(object).ToLocalChecked(); | ||
|
||
GITransfer inner_transfer = | ||
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer); | ||
|
||
for (uint32_t i = 0; i < keys->Length(); i++) { | ||
auto key = Nan::Get(keys, i).ToLocalChecked(); | ||
auto value = Nan::Get(object, key).ToLocalChecked(); | ||
|
||
GIArgument key_arg; | ||
GIArgument value_arg; | ||
|
||
if (!V8ToGIArgument(key_type_info, &key_arg, key, false)) { | ||
if (!V8ToGIArgument(key_type_info, &key_arg, key, false, inner_transfer)) { | ||
char* message = g_strdup_printf("Couldn't convert key '%s'", *Nan::Utf8String(key)); | ||
Nan::ThrowError(message); | ||
free(message); | ||
goto item_error; | ||
} | ||
|
||
if (!V8ToGIArgument(value_type_info, &value_arg, value, false)) { | ||
if (!V8ToGIArgument(value_type_info, &value_arg, value, false, inner_transfer)) { | ||
char* message = g_strdup_printf("Couldn't convert value for key '%s'", *Nan::Utf8String(key)); | ||
Nan::ThrowError(message); | ||
free(message); | ||
|
@@ -613,7 +623,11 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) { | |
continue; | ||
|
||
item_error: | ||
/* Free everything we have converted so far. */ | ||
/* | ||
* Free everything we have converted so far. | ||
* Uses TRANSFER_NOTHING, DIRECTION_IN, as if the function doesn't take | ||
* ownership, instead of passed in `transfer`. | ||
*/ | ||
FreeGIArgument(type_info, (GIArgument *) &hash_table, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); | ||
hash_table = NULL; | ||
break; | ||
|
@@ -625,14 +639,19 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) { | |
return hash_table; | ||
} | ||
|
||
bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value) { | ||
bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value, GITransfer transfer) { | ||
GIInfoType type = g_base_info_get_type (gi_info); | ||
|
||
switch (type) { | ||
case GI_INFO_TYPE_BOXED: | ||
case GI_INFO_TYPE_STRUCT: | ||
case GI_INFO_TYPE_UNION: | ||
arg->v_pointer = PointerFromWrapper(value); | ||
if (transfer == GI_TRANSFER_EVERYTHING) { | ||
arg->v_pointer = CopyBoxed(gi_info, arg->v_pointer); | ||
if (!arg->v_pointer) | ||
return false; | ||
} | ||
break; | ||
|
||
case GI_INFO_TYPE_FLAGS: | ||
|
@@ -652,6 +671,8 @@ bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value) { | |
} | ||
case GI_INFO_TYPE_INTERFACE: | ||
arg->v_pointer = GObjectFromWrapper(value); | ||
if (transfer == GI_TRANSFER_EVERYTHING) | ||
g_object_ref(arg->v_pointer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this one isn't going to leak anything? Is this case the one tested by the test down here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I suppose no. The new reference should be taken by the callee, by the definition of
Similar, but of different type. The added test is for [1] specifically There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But maybe here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whatever the function's transfer say, we cannot transfer the JS wrapper to the C world. That means the JS wrapper will have to stay, and so does the wrapper's object reference. If we don't increase a reference here, the JS wrapper's reference will (metaphorically) be transferred to the function. And if such function un-reference this reference, it can leave the JS wrapper dangling. Maybe you intend to leave the JS wrapper dangling after a call to transfer-full function. However, that doesn't work either. Every reference to this object in the JS world shares single JS wrapper, and thus have single GObject reference. If the JS wrapper becomes dangling, so does every refernce in the JS world. |
||
break; | ||
|
||
case GI_INFO_TYPE_CALLBACK: | ||
|
@@ -662,7 +683,7 @@ bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value) { | |
return true; | ||
} | ||
|
||
bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, bool may_be_null) { | ||
bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, bool may_be_null, GITransfer transfer) { | ||
GITypeTag type_tag = g_type_info_get_tag (type_info); | ||
|
||
if (value->IsUndefined () || value->IsNull ()) { | ||
|
@@ -680,6 +701,10 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, | |
case GI_TYPE_TAG_VOID: | ||
if (g_type_info_is_pointer(type_info)) { | ||
arg->v_pointer = PointerFromWrapper(value); | ||
if (transfer == GI_TRANSFER_EVERYTHING) { | ||
ERROR("Case should not be reached. Please report this to " | ||
"https://github.com/romgrk/node-gtk/issues"); | ||
} | ||
break; | ||
} | ||
arg->v_pointer = NULL; | ||
|
@@ -744,11 +769,11 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, | |
|
||
switch (array_type) { | ||
case GI_ARRAY_TYPE_C: | ||
arg->v_pointer = V8ToCArray(type_info, value); | ||
arg->v_pointer = V8ToCArray(type_info, value, transfer); | ||
break; | ||
case GI_ARRAY_TYPE_ARRAY: | ||
case GI_ARRAY_TYPE_BYTE_ARRAY: | ||
arg->v_pointer = V8ToGArray(type_info, value); | ||
arg->v_pointer = V8ToGArray(type_info, value, transfer); | ||
break; | ||
case GI_ARRAY_TYPE_PTR_ARRAY: | ||
default: | ||
|
@@ -761,21 +786,21 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, | |
case GI_TYPE_TAG_INTERFACE: | ||
{ | ||
GIBaseInfo *interface_info = g_type_info_get_interface (type_info); | ||
V8ToGIArgument (interface_info, arg, value); | ||
V8ToGIArgument (interface_info, arg, value, transfer); | ||
g_base_info_unref(interface_info); | ||
} | ||
break; | ||
|
||
case GI_TYPE_TAG_GLIST: | ||
case GI_TYPE_TAG_GSLIST: | ||
{ | ||
arg->v_pointer = V8ToGList(type_info, value); | ||
arg->v_pointer = V8ToGList(type_info, value, transfer); | ||
} | ||
break; | ||
|
||
case GI_TYPE_TAG_GHASH: | ||
{ | ||
arg->v_pointer = V8ToGHash(type_info, value); | ||
arg->v_pointer = V8ToGHash(type_info, value, transfer); | ||
} | ||
break; | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.