Changeset: dce7fa42e62a for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=dce7fa42e62a Modified Files: sql/backends/monet5/UDF/capi/Tests/capi04.sql sql/backends/monet5/UDF/capi/Tests/capi04.stable.out sql/backends/monet5/UDF/capi/capi.c Branch: jitudf Log Message:
Automatically clean up any mallocs performed in the jitted function. diffs (190 lines): diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.sql b/sql/backends/monet5/UDF/capi/Tests/capi04.sql --- a/sql/backends/monet5/UDF/capi/Tests/capi04.sql +++ b/sql/backends/monet5/UDF/capi/Tests/capi04.sql @@ -10,8 +10,6 @@ CREATE FUNCTION capi04(inp STRING) RETUR if (inp.is_null(inp.data[i])) { result->data[i] = result->null_value; } else { - // the contract says we must use "malloc" to allocate for the result strings - // "malloc" is a function pointer that actually points to GDKmalloc result->data[i] = malloc(strlen(inp.data[i]) + 2); strcpy(result->data[i] + 1, inp.data[i]); result->data[i][0] = 'H'; @@ -35,8 +33,28 @@ CREATE FUNCTION capi04(inp STRING) RETUR }; SELECT capi04(i) FROM strings; +ROLLBACK; + +START TRANSACTION; +# return constant strings, instead of allocated strings +CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { +#include <string.h> + + result->initialize(result, inp.count); + for(size_t i = 0; i < inp.count; i++) { + if (inp.is_null(inp.data[i])) { + result->data[i] = result->null_value; + } else { + result->data[i] = malloc(strlen(inp.data[i]) + 2); + strcpy(result->data[i] + 1, inp.data[i]); + result->data[i] = "hello"; + } + } +}; + +CREATE TABLE strings(i STRING); +INSERT INTO strings VALUES ('ello'), ('ow'), (NULL), ('onestly?'), ('annes'); + +SELECT capi04(i) FROM strings; ROLLBACK; - - - diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out --- a/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out +++ b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out @@ -54,14 +54,10 @@ Ready. # loading sql script: 90_generator.sql # loading sql script: 90_generator_hge.sql # loading sql script: 99_system.sql -Hello -How -Honestly? -Hannes -# 15:50:30 > -# 15:50:30 > "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" "--host=/var/tmp/mtest-20003" "--port=32751" -# 15:50:30 > +# 12:56:26 > +# 12:56:26 > "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" "--host=/var/tmp/mtest-37150" "--port=31836" +# 12:56:26 > #START TRANSACTION; #CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { @@ -98,6 +94,35 @@ Hannes # } #}; #ROLLBACK; +#START TRANSACTION; +#CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { +##include <string.h> +# +# result->initialize(result, inp.count); +# for(size_t i = 0; i < inp.count; i++) { +# if (inp.is_null(inp.data[i])) { +# result->data[i] = result->null_value; +# } else { +# result->data[i] = malloc(strlen(inp.data[i]) + 2); +# strcpy(result->data[i] + 1, inp.data[i]); +# result->data[i] = "hello"; +# } +# } +#}; +#CREATE TABLE strings(i STRING); +#INSERT INTO strings VALUES ('ello'), ('ow'), (NULL), ('onestly?'), ('annes'); +[ 5 ] +#SELECT capi04(i) FROM strings; +% sys.L2 # table_name +% L2 # name +% clob # type +% 5 # length +[ "hello" ] +[ "hello" ] +[ NULL ] +[ "hello" ] +[ "hello" ] +#ROLLBACK; # 15:50:31 > # 15:50:31 > "Done." diff --git a/sql/backends/monet5/UDF/capi/capi.c b/sql/backends/monet5/UDF/capi/capi.c --- a/sql/backends/monet5/UDF/capi/capi.c +++ b/sql/backends/monet5/UDF/capi/capi.c @@ -22,6 +22,13 @@ #include <unistd.h> #include <string.h> +struct _allocated_region; +typedef struct _allocated_region { + struct _allocated_region* next; +} allocated_region; + + +static __thread allocated_region* allocated_regions; static __thread jmp_buf jump_buffer; static str @@ -125,7 +132,7 @@ clear_mprotect(void* addr, size_t len) { } -static void* wrapped_GDK_malloc(size_t size) { +static void* jump_GDK_malloc(size_t size) { void* ptr = GDKmalloc(size); if (!ptr) { longjmp(jump_buffer, 2); @@ -133,11 +140,21 @@ static void* wrapped_GDK_malloc(size_t s return ptr; } +static void* wrapped_GDK_malloc(size_t size) { + allocated_region* region; + void* ptr = jump_GDK_malloc(size + sizeof(allocated_region)); + region = (allocated_region*)ptr; + region->next = allocated_regions; + allocated_regions = region; + + return ptr + sizeof(allocated_region); +} + #define GENERATE_BASE_HEADERS(type, tpename) \ static int tpename##_is_null(type value); \ static void tpename##_initialize(struct cudf_data_struct_##tpename* self, size_t count) { \ self->count = count; \ - self->data = wrapped_GDK_malloc(count * sizeof(self->null_value)); \ + self->data = jump_GDK_malloc(count * sizeof(self->null_value)); \ } #define GENERATE_BASE_FUNCTIONS(tpe, tpename) \ @@ -278,6 +295,8 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal (void) cntxt; + allocated_regions = NULL; + // we need to be able to catch segfaults and bus errors // so we can work with mprotect to prevent UDFs from changing // the input data @@ -781,7 +800,7 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal goto wrapup; } else { // we jumped here - msg = createException(MAL, "cudf.eval", "We longjumped here because of an error!."); + msg = createException(MAL, "cudf.eval", "We longjumped here because of an error, but we don't know which!"); goto wrapup; } } @@ -903,9 +922,6 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal msg = createException(MAL, "cudf.eval", MAL_MALLOC_FAIL); goto wrapup; } - if (ptr != str_nil) { - GDKfree(source_base[j]); - } } GDKfree(data); } else { @@ -940,6 +956,11 @@ wrapup: GDKfree(regions); regions = next; } + while(allocated_regions) { + allocated_region* next = allocated_regions->next; + GDKfree(allocated_regions); + allocated_regions = next; + } // block segfaults and bus errors again after we exit (void) pthread_sigmask(SIG_BLOCK, &signal_set, NULL); // argument names (input) _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list