Skip to content

Commit b6054ce

Browse files
committed
Improve C loader with more types and issues.
1 parent abf2351 commit b6054ce

File tree

4 files changed

+203
-11
lines changed

4 files changed

+203
-11
lines changed

source/loaders/c_loader/source/c_loader_impl.cpp

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ namespace fs = std::experimental::filesystem;
5555
#include <string>
5656
#include <vector>
5757

58+
#include <cassert>
5859
#include <cstring>
5960

6061
/* LibFFI */
@@ -633,10 +634,18 @@ ffi_type *c_loader_impl_ffi_type(type_id id)
633634
return &ffi_type_float;
634635
case TYPE_DOUBLE:
635636
return &ffi_type_double;
637+
case TYPE_STRING:
638+
return &ffi_type_pointer;
639+
case TYPE_BUFFER:
640+
return &ffi_type_pointer;
641+
case TYPE_ARRAY:
642+
return &ffi_type_pointer;
636643
case TYPE_PTR:
637644
return &ffi_type_pointer;
638645
case TYPE_FUNCTION:
639646
return &ffi_type_pointer;
647+
case TYPE_NULL:
648+
return &ffi_type_void;
640649
}
641650

642651
return &ffi_type_void;
@@ -648,8 +657,7 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
648657

649658
if (args_size != signature_count(s))
650659
{
651-
log_write("metacall", LOG_LEVEL_ERROR, "Invalid number of arguments when calling %s (canceling call in order to avoid a segfault)", function_name(func));
652-
return NULL;
660+
return metacall_error_throw("C Loader Error", 0, "", "Invalid number of arguments when calling %s (canceling call in order to avoid a segfault)", function_name(func));
653661
}
654662

655663
loader_impl_c_function c_function = static_cast<loader_impl_c_function>(impl);
@@ -663,7 +671,7 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
663671

664672
if (id != value_id)
665673
{
666-
log_write("metacall", LOG_LEVEL_ERROR,
674+
return metacall_error_throw("C Loader Error", 0, "",
667675
"Type mismatch in when calling %s in argument number %" PRIuS
668676
" (expected %s of type %s and received %s)."
669677
" Canceling call in order to avoid a segfault.",
@@ -672,7 +680,6 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
672680
type_name(t),
673681
type_id_name(id),
674682
type_id_name(value_id));
675-
return NULL;
676683
}
677684

678685
if (id == TYPE_FUNCTION)
@@ -683,19 +690,39 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
683690

684691
closures.push_back(closure);
685692
}
686-
else
693+
else if (id == TYPE_STRING || id == TYPE_BUFFER || id == TYPE_ARRAY || id == TYPE_PTR)
687694
{
695+
/*
696+
String, buffer requires to be pointer to a string
697+
Array requires to be pointer to a array
698+
Pointer requires to be pointer to pointer
699+
*/
700+
701+
/* In order to work, this must be true */
702+
assert(args[args_count] == value_data(args[args_count]));
703+
704+
c_function->values[args_count] = (void *)&args[args_count];
705+
}
706+
else if (type_id_integer(id) == 0 || type_id_decimal(id) == 0)
707+
{
708+
/* Primitive types already have the pointer indirection */
688709
c_function->values[args_count] = value_data((value)args[args_count]);
689710
}
711+
else
712+
{
713+
return metacall_error_throw("C Loader Error", 0, "",
714+
"Type %s in argument number %" PRIuS " of function %s is not supported.",
715+
type_id_name(id),
716+
args_count,
717+
function_name(func));
718+
}
690719
}
691720

692721
type_id ret_id = type_index(signature_get_return(s));
693722
size_t ret_size = value_type_id_size(ret_id);
694723
void *ret = NULL;
695724

696-
/* TODO: This if is not correct because the sizes of strings, objects, etc are
697-
relative to the pointer, not the value contents, we should review this */
698-
if (ret_size <= sizeof(ffi_arg))
725+
if (ret_size <= sizeof(ffi_arg) && (type_id_integer(ret_id) == 0 || type_id_decimal(ret_id) == 0))
699726
{
700727
ffi_arg result;
701728

@@ -705,9 +732,50 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
705732
}
706733
else
707734
{
708-
ret = value_type_create(NULL, ret_size, ret_id);
735+
void *result = NULL;
736+
void *result_ptr = &result;
737+
738+
if (ret_id == TYPE_NULL)
739+
{
740+
ret = value_create_null();
741+
result_ptr = NULL;
742+
}
743+
else if (ret_id != TYPE_STRING && ret_id != TYPE_BUFFER && ret_id != TYPE_ARRAY && ret_id != TYPE_PTR)
744+
{
745+
/* TODO: This is not tested and we do not know how to handle it */
746+
/* TODO: result = ret = value_type_create(NULL, ret_size, ret_id); */
747+
748+
return metacall_error_throw("C Loader Error", 0, "",
749+
"Return type %s in of function %s is not supported.",
750+
type_id_name(ret_id),
751+
function_name(func));
752+
}
709753

710-
ffi_call(&c_function->cif, FFI_FN(c_function->address), value_data(ret), c_function->values);
754+
ffi_call(&c_function->cif, FFI_FN(c_function->address), result_ptr, c_function->values);
755+
756+
if (ret_id == TYPE_STRING)
757+
{
758+
char *str = (char *)result;
759+
ret = value_create_string(str, strlen(str));
760+
}
761+
else if (ret_id == TYPE_BUFFER)
762+
{
763+
return metacall_error_throw("C Loader Error", 0, "",
764+
"Return type %s in of function %s is not supported, buffer is unsafe to be returned because there is no way to reconstruct it without overflowing as there is no null character nor size information.",
765+
type_id_name(ret_id),
766+
function_name(func));
767+
}
768+
else if (ret_id == TYPE_ARRAY)
769+
{
770+
return metacall_error_throw("C Loader Error", 0, "",
771+
"Return type %s in of function %s is not supported, array is unsafe to be returned because there is no way to reconstruct it without overflowing as there is no null character nor size information.",
772+
type_id_name(ret_id),
773+
function_name(func));
774+
}
775+
else if (ret_id == TYPE_PTR)
776+
{
777+
ret = value_create_ptr(result);
778+
}
711779
}
712780

713781
/* Clear allocated closures if any */
@@ -800,6 +868,7 @@ int c_loader_impl_initialize_types(loader_impl impl)
800868
{ TYPE_BOOL, "bool" },
801869

802870
{ TYPE_CHAR, "char" },
871+
{ TYPE_CHAR, "unsigned char" },
803872
{ TYPE_CHAR, "int8_t" },
804873
{ TYPE_CHAR, "uint8_t" },
805874
{ TYPE_CHAR, "int_least8_t" },
@@ -808,6 +877,7 @@ int c_loader_impl_initialize_types(loader_impl impl)
808877
{ TYPE_CHAR, "uint_fast8_t" },
809878

810879
{ TYPE_SHORT, "short" },
880+
{ TYPE_SHORT, "unsigned short" },
811881
{ TYPE_SHORT, "int16_t" },
812882
{ TYPE_SHORT, "uint16_t" },
813883
{ TYPE_SHORT, "int_least16_t" },
@@ -816,6 +886,7 @@ int c_loader_impl_initialize_types(loader_impl impl)
816886
{ TYPE_SHORT, "uint_fast16_t" },
817887

818888
{ TYPE_INT, "int" },
889+
{ TYPE_INT, "unsigned int" },
819890
{ TYPE_INT, "uint32_t" },
820891
{ TYPE_INT, "int32_t" },
821892
{ TYPE_INT, "int_least32_t" },
@@ -824,7 +895,9 @@ int c_loader_impl_initialize_types(loader_impl impl)
824895
{ TYPE_INT, "uint_fast32_t" },
825896

826897
{ TYPE_LONG, "long" },
898+
{ TYPE_LONG, "unsigned long" },
827899
{ TYPE_LONG, "long long" },
900+
{ TYPE_LONG, "unsigned long long" },
828901
{ TYPE_LONG, "uint64_t" },
829902
{ TYPE_LONG, "int64_t" },
830903
{ TYPE_LONG, "int_least64_t" },
@@ -838,6 +911,11 @@ int c_loader_impl_initialize_types(loader_impl impl)
838911
{ TYPE_FLOAT, "float" },
839912
{ TYPE_DOUBLE, "double" },
840913

914+
{ TYPE_STRING, "unsigned char *" },
915+
{ TYPE_STRING, "char *" },
916+
{ TYPE_STRING, "const unsigned char *" },
917+
{ TYPE_STRING, "const char *" },
918+
841919
{ TYPE_NULL, "void" }
842920

843921
/* TODO: Do more types */
@@ -932,6 +1010,10 @@ static type_id c_loader_impl_clang_type(loader_impl impl, CXCursor cursor, CXTyp
9321010
return TYPE_PTR;
9331011
}
9341012

1013+
case CXType_ConstantArray:
1014+
case CXType_IncompleteArray:
1015+
return TYPE_ARRAY;
1016+
9351017
case CXType_FunctionProto:
9361018
case CXType_FunctionNoProto: {
9371019
c_loader_closure_type *closure_type = new c_loader_closure_type(impl);
@@ -964,7 +1046,12 @@ static type_id c_loader_impl_clang_type(loader_impl impl, CXCursor cursor, CXTyp
9641046
case CXType_Bool:
9651047
return TYPE_BOOL;
9661048

1049+
case CXType_Short:
1050+
case CXType_UShort:
1051+
return TYPE_SHORT;
1052+
9671053
case CXType_Int:
1054+
case CXType_UInt:
9681055
return TYPE_INT;
9691056

9701057
case CXType_Void:

source/scripts/c/compiled/source/compiled.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
#include <assert.h>
12
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <string.h>
25

36
void compiled_print(int a, double b)
47
{
@@ -9,3 +12,101 @@ long compiled_sum(long a, long b)
912
{
1013
return a + b;
1114
}
15+
16+
char *return_text(void)
17+
{
18+
static char input[] = "hello";
19+
return input;
20+
}
21+
22+
void process_text(char *input)
23+
{
24+
printf("inside of compiled script '%s'\n", input);
25+
assert(strcmp(input, "test_test") == 0);
26+
}
27+
28+
typedef struct data_t
29+
{
30+
int value;
31+
} * data_ptr_t;
32+
33+
data_ptr_t alloc_data(void)
34+
{
35+
data_ptr_t ptr = malloc(sizeof(struct data_t));
36+
37+
ptr->value = 0;
38+
39+
printf("alloc_data %p\n", ptr);
40+
41+
return ptr;
42+
}
43+
44+
void alloc_data_args(data_ptr_t *ptr)
45+
{
46+
*ptr = malloc(sizeof(struct data_t));
47+
48+
(*ptr)->value = 0;
49+
50+
printf("alloc_data_args %p\n", *ptr);
51+
printf("alloc_data_args ref %p\n", ptr);
52+
}
53+
54+
int compare_data_value(data_ptr_t left, data_ptr_t right)
55+
{
56+
printf("left %p\n", left);
57+
printf("right %p\n", right);
58+
assert(left == right);
59+
return left == right;
60+
}
61+
62+
void set_data_value(data_ptr_t ptr, int value)
63+
{
64+
printf("set_data_value %p\n", ptr);
65+
ptr->value = value;
66+
}
67+
68+
int get_data_value(data_ptr_t ptr)
69+
{
70+
printf("get_data_value %p\n", ptr);
71+
return ptr->value;
72+
}
73+
74+
void free_data(data_ptr_t ptr)
75+
{
76+
printf("free_data %p\n", ptr);
77+
free(ptr);
78+
}
79+
80+
// TODO: When calling from NodeJS it does not work,
81+
// NodeJS emmits double as a call, and this expects long, it needs a casting
82+
void modify_int_ptr(long *l)
83+
{
84+
printf("l %p\n", l);
85+
printf("value %d\n", *l);
86+
assert(*l == 324444L);
87+
*l = 111L;
88+
}
89+
90+
void modify_double_ptr(double *d)
91+
{
92+
printf("d %p\n", d);
93+
printf("value %f\n", *d);
94+
assert(*d == 324444.0);
95+
*d = 111.0;
96+
}
97+
98+
void modify_str_ptr(char **str_ptr)
99+
{
100+
static char new_str[] = "yeet";
101+
printf("(C) pointer %p\n", str_ptr);
102+
printf("(C) string %p\n", (*str_ptr));
103+
printf("(C) string value %s\n", *str_ptr);
104+
fflush(stdout);
105+
assert(strcmp("asd", *str_ptr) == 0);
106+
*str_ptr = new_str;
107+
printf("(C) pointer %p\n", str_ptr);
108+
printf("(C) string %p\n", (*str_ptr));
109+
printf("(C) string value %s\n", *str_ptr);
110+
fflush(stdout);
111+
assert(strcmp("yeet", *str_ptr) == 0);
112+
}

source/scripts/c/loadtest/source/loadtest.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "loadtest.h"
2+
#include <iostream>
23
#include <vector>
34

45
long call_cpp_func(void)
@@ -23,6 +24,9 @@ int pair_list_init(pair_list **t)
2324
(*t)->pairs[i].d = (double)(((double)i) * 1.0);
2425
}
2526

27+
std::cout << "pair_list_init: " << t << std::endl;
28+
std::cout << "pair_list_init: *(" << *t << ")" << std::endl;
29+
2630
return 0;
2731
}
2832

source/scripts/c/loadtest/source/loadtest.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
extern "C" {
1212
#endif
1313

14-
#include <cstdint>
14+
#include <stdint.h>
1515

1616
typedef struct
1717
{

0 commit comments

Comments
 (0)