Skip to content

Commit 711000e

Browse files
committed
fix(value): handle transfer-full, in arguments properly
This is done by making V8ToGIArgument() accept the transfer status and react accordingly. I does not make the new argument optional; this forces me into thinking about the appropriate value to put in for various callsites of this function. The make the test added in the previous commit passes.
1 parent a4216d5 commit 711000e

File tree

5 files changed

+60
-25
lines changed

5 files changed

+60
-25
lines changed

src/callback.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,16 @@ void Callback::Execute (GIArgument *result, GIArgument **args, Callback *callbac
192192
}
193193
}
194194

195+
GITypeInfo ret_info;
196+
g_callable_info_load_return_type(callback->info, &ret_info);
197+
GITransfer transfer = g_arg_info_get_ownership_transfer (&ret_info);
198+
195199
success = V8ToGIArgument(
196200
&return_type_info,
197201
result,
198202
jsRealReturnValue,
199-
g_callable_info_may_return_null (callback->info));
203+
g_callable_info_may_return_null (callback->info),
204+
transfer);
200205

201206
if (!success) {
202207
Throw::InvalidReturnValue (&return_type_info, jsReturnValue);

src/function.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ static void FillArgument(GIArgInfo *arg_info, GIArgument *argument, Local<Value>
3131
GITypeInfo type_info;
3232
bool may_be_null = g_arg_info_may_be_null (arg_info);
3333
g_arg_info_load_type (arg_info, &type_info);
34-
V8ToGIArgument(&type_info, argument, value, may_be_null);
34+
GITransfer transfer = g_arg_info_get_ownership_transfer(arg_info);
35+
V8ToGIArgument(&type_info, argument, value, may_be_null, transfer);
3536
}
3637

3738
static int GetV8ArrayLength (Local<Value> value) {
@@ -331,7 +332,7 @@ Local<Value> FunctionCall (
331332

332333
if (func->is_method) {
333334
GIBaseInfo *container = g_base_info_get_container (gi_info);
334-
V8ToGIArgument(container, &total_arg_values[0], info.This());
335+
V8ToGIArgument(container, &total_arg_values[0], info.This(), GI_TRANSFER_NOTHING);
335336
callable_arg_values = &total_arg_values[1];
336337
} else {
337338
callable_arg_values = &total_arg_values[0];

src/gi.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ NAN_METHOD(StructFieldSetter) {
223223

224224
GIArgument arg;
225225

226-
if (!GNodeJS::V8ToGIArgument(field_type, &arg, value, true)) {
226+
if (!GNodeJS::V8ToGIArgument(field_type, &arg, value, true, GI_TRANSFER_NOTHING)) {
227227
char *message = g_strdup_printf("Couldn't convert value for field '%s'",
228228
g_base_info_get_name(field));
229229
Nan::ThrowTypeError (message);

src/value.cc

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ long GIArgumentToLength(GITypeInfo *type_info, GIArgument *arg, bool is_pointer)
354354
}
355355

356356

357-
GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value) {
357+
GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value, GITransfer transfer) {
358358
GArray* g_array = NULL;
359359
bool zero_terminated = g_type_info_is_zero_terminated(type_info);
360360

@@ -382,8 +382,10 @@ GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value) {
382382
for (int i = 0; i < length; i++) {
383383
auto value = Nan::Get(array, i).ToLocalChecked();
384384
GIArgument arg;
385+
GITransfer inner_transfer =
386+
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer);
385387

386-
if (V8ToGIArgument(element_info, &arg, value, true)) {
388+
if (V8ToGIArgument(element_info, &arg, value, true, inner_transfer)) {
387389
g_array_append_val (g_array, arg);
388390
} else {
389391
g_warning("V8ToGArray: couldnt convert value: %s",
@@ -399,7 +401,7 @@ GArray * V8ToGArray(GITypeInfo *type_info, Local<Value> value) {
399401
return g_array;
400402
}
401403

402-
static void *V8ArrayToCArray(GITypeInfo *type_info, Local<Value> value) {
404+
static void *V8ArrayToCArray(GITypeInfo *type_info, Local<Value> value, GITransfer transfer) {
403405
auto array = Local<Array>::Cast (TO_OBJECT (value));
404406
int length = array->Length();
405407

@@ -413,8 +415,10 @@ static void *V8ArrayToCArray(GITypeInfo *type_info, Local<Value> value) {
413415
auto value = Nan::Get(array, i).ToLocalChecked();
414416

415417
GIArgument arg;
418+
GITransfer inner_transfer =
419+
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer);
416420

417-
if (V8ToGIArgument(element_info, &arg, value, true)) {
421+
if (V8ToGIArgument(element_info, &arg, value, true, inner_transfer)) {
418422
void* pointer = (void*)((ulong)result + i * element_size);
419423
memcpy(pointer, &arg, element_size);
420424
} else {
@@ -453,15 +457,15 @@ static void *V8TypedArrayToCArray(GITypeInfo *type_info, Local<Value> value) {
453457
return result;
454458
}
455459

456-
void *V8ToCArray(GITypeInfo *type_info, Local<Value> value) {
460+
void *V8ToCArray(GITypeInfo *type_info, Local<Value> value, GITransfer transfer) {
457461
if (value->IsString()) {
458462
Local<String> string = TO_STRING (value);
459463
const char *utf8_data = *Nan::Utf8String(string);
460464
return g_strdup(utf8_data);
461465
}
462466

463467
if (value->IsArray()) {
464-
return V8ArrayToCArray(type_info, value);
468+
return V8ArrayToCArray(type_info, value, transfer);
465469
}
466470

467471
if (value->IsTypedArray()) {
@@ -473,7 +477,7 @@ void *V8ToCArray(GITypeInfo *type_info, Local<Value> value) {
473477
return NULL;
474478
}
475479

476-
gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value) {
480+
gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value, GITransfer transfer) {
477481

478482
// FIXME can @value be null?
479483
if (!value->IsArray()) {
@@ -504,7 +508,10 @@ gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value) {
504508
GIArgument arg;
505509
Local<Value> value = Nan::Get(array, i).ToLocalChecked();
506510

507-
if (!V8ToGIArgument(element_info, &arg, value, false)) {
511+
GITransfer inner_transfer =
512+
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer);
513+
514+
if (!V8ToGIArgument(element_info, &arg, value, false, inner_transfer)) {
508515
g_warning("V8ToGList: couldnt convert value #%i to GIArgument", i);
509516
continue;
510517
}
@@ -526,7 +533,7 @@ gpointer V8ToGList (GITypeInfo *type_info, Local<Value> value) {
526533
return list;
527534
}
528535

529-
gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) {
536+
gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value, GITransfer transfer) {
530537

531538
if (!value->IsObject()) {
532539
Nan::ThrowTypeError("Expected object");
@@ -587,21 +594,24 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) {
587594
auto object = TO_OBJECT (value);
588595
auto keys = Nan::GetOwnPropertyNames(object).ToLocalChecked();
589596

597+
GITransfer inner_transfer =
598+
(transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer);
599+
590600
for (uint32_t i = 0; i < keys->Length(); i++) {
591601
auto key = Nan::Get(keys, i).ToLocalChecked();
592602
auto value = Nan::Get(object, key).ToLocalChecked();
593603

594604
GIArgument key_arg;
595605
GIArgument value_arg;
596606

597-
if (!V8ToGIArgument(key_type_info, &key_arg, key, false)) {
607+
if (!V8ToGIArgument(key_type_info, &key_arg, key, false, inner_transfer)) {
598608
char* message = g_strdup_printf("Couldn't convert key '%s'", *Nan::Utf8String(key));
599609
Nan::ThrowError(message);
600610
free(message);
601611
goto item_error;
602612
}
603613

604-
if (!V8ToGIArgument(value_type_info, &value_arg, value, false)) {
614+
if (!V8ToGIArgument(value_type_info, &value_arg, value, false, inner_transfer)) {
605615
char* message = g_strdup_printf("Couldn't convert value for key '%s'", *Nan::Utf8String(key));
606616
Nan::ThrowError(message);
607617
free(message);
@@ -614,7 +624,7 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) {
614624

615625
item_error:
616626
/* Free everything we have converted so far. */
617-
FreeGIArgument(type_info, (GIArgument *) &hash_table, GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
627+
FreeGIArgument(type_info, (GIArgument *) &hash_table, transfer, GI_DIRECTION_IN);
618628
hash_table = NULL;
619629
break;
620630
}
@@ -625,14 +635,30 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local<Value> value) {
625635
return hash_table;
626636
}
627637

628-
bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value) {
638+
bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value, GITransfer transfer) {
629639
GIInfoType type = g_base_info_get_type (gi_info);
630640

631641
switch (type) {
632642
case GI_INFO_TYPE_BOXED:
633643
case GI_INFO_TYPE_STRUCT:
634644
case GI_INFO_TYPE_UNION:
635645
arg->v_pointer = PointerFromWrapper(value);
646+
if (transfer == GI_TRANSFER_EVERYTHING) {
647+
GType gtype = g_registered_type_info_get_g_type (gi_info);
648+
size_t size;
649+
650+
if (gtype != G_TYPE_NONE) {
651+
arg->v_pointer = g_boxed_copy (gtype, arg->v_pointer);
652+
} else if ((size = Boxed::GetSize(gi_info)) != 0) {
653+
void *boxedCopy = malloc(size);
654+
memcpy(boxedCopy, arg->v_pointer, size);
655+
arg->v_pointer = boxedCopy;
656+
} else {
657+
// XXX what else can we do? Should we just abort?
658+
WARN("Cannot copy a boxed object of type '%s'; memory corruption might occur.",
659+
g_base_info_get_name(gi_info));
660+
}
661+
}
636662
break;
637663

638664
case GI_INFO_TYPE_FLAGS:
@@ -652,6 +678,8 @@ bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value) {
652678
}
653679
case GI_INFO_TYPE_INTERFACE:
654680
arg->v_pointer = GObjectFromWrapper(value);
681+
if (transfer == GI_TRANSFER_EVERYTHING)
682+
g_object_ref(arg->v_pointer);
655683
break;
656684

657685
case GI_INFO_TYPE_CALLBACK:
@@ -662,7 +690,7 @@ bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local<Value> value) {
662690
return true;
663691
}
664692

665-
bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, bool may_be_null) {
693+
bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, bool may_be_null, GITransfer transfer) {
666694
GITypeTag type_tag = g_type_info_get_tag (type_info);
667695

668696
if (value->IsUndefined () || value->IsNull ()) {
@@ -680,6 +708,7 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value,
680708
case GI_TYPE_TAG_VOID:
681709
if (g_type_info_is_pointer(type_info)) {
682710
arg->v_pointer = PointerFromWrapper(value);
711+
// XXX what to do with GI_TRANSFER_EVERYTHING
683712
break;
684713
}
685714
arg->v_pointer = NULL;
@@ -744,11 +773,11 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value,
744773

745774
switch (array_type) {
746775
case GI_ARRAY_TYPE_C:
747-
arg->v_pointer = V8ToCArray(type_info, value);
776+
arg->v_pointer = V8ToCArray(type_info, value, transfer);
748777
break;
749778
case GI_ARRAY_TYPE_ARRAY:
750779
case GI_ARRAY_TYPE_BYTE_ARRAY:
751-
arg->v_pointer = V8ToGArray(type_info, value);
780+
arg->v_pointer = V8ToGArray(type_info, value, transfer);
752781
break;
753782
case GI_ARRAY_TYPE_PTR_ARRAY:
754783
default:
@@ -761,21 +790,21 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value,
761790
case GI_TYPE_TAG_INTERFACE:
762791
{
763792
GIBaseInfo *interface_info = g_type_info_get_interface (type_info);
764-
V8ToGIArgument (interface_info, arg, value);
793+
V8ToGIArgument (interface_info, arg, value, transfer);
765794
g_base_info_unref(interface_info);
766795
}
767796
break;
768797

769798
case GI_TYPE_TAG_GLIST:
770799
case GI_TYPE_TAG_GSLIST:
771800
{
772-
arg->v_pointer = V8ToGList(type_info, value);
801+
arg->v_pointer = V8ToGList(type_info, value, transfer);
773802
}
774803
break;
775804

776805
case GI_TYPE_TAG_GHASH:
777806
{
778-
arg->v_pointer = V8ToGHash(type_info, value);
807+
arg->v_pointer = V8ToGHash(type_info, value, transfer);
779808
}
780809
break;
781810

src/value.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ Local<Value> GErrorToV8 (GITypeInfo *type_info, GError *err);
1919
Local<Value> GIArgumentToV8 (GITypeInfo *type_info, GIArgument *argument, long length = -1, bool mustCopy = false);
2020
long GIArgumentToLength(GITypeInfo *type_info, GIArgument *arg, bool is_pointer);
2121

22-
bool V8ToGIArgument (GITypeInfo *type_info, GIArgument *argument, Local<Value> value);
23-
bool V8ToGIArgument (GITypeInfo *type_info, GIArgument *argument, Local<Value> value, bool may_be_null);
22+
bool V8ToGIArgument (GITypeInfo *type_info, GIArgument *argument, Local<Value> value, GITransfer transfer);
23+
bool V8ToGIArgument (GITypeInfo *type_info, GIArgument *argument, Local<Value> value, bool may_be_null, GITransfer transfer);
2424
bool V8ToOutGIArgument(GITypeInfo *type_info, GIArgument *arg, Local<Value> value, bool may_be_null);
2525
void FreeGIArgument (GITypeInfo *type_info, GIArgument *argument, GITransfer transfer = GI_TRANSFER_EVERYTHING, GIDirection direction = GI_DIRECTION_OUT);
2626
void FreeGIArgumentArray (GITypeInfo *type_info, GIArgument *arg, GITransfer transfer = GI_TRANSFER_EVERYTHING, GIDirection direction = GI_DIRECTION_OUT, long length = -1);

0 commit comments

Comments
 (0)