Changeset: 85fc1cd7c486 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=85fc1cd7c486
Modified Files:
sql/backends/monet5/UDF/capi/capi.c
Branch: Mar2018
Log Message:
Make mprotect and longjmp on malloc failure optional in CUDFs.
If mprotect is disabled (default), input columns are always copied instead of
protected from writing, allowing the user to safely write to them.
If longjmp on malloc failure is disabled (default), mallocs must be manually
checked inside the CUDF.
diffs (252 lines):
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
@@ -23,6 +23,11 @@
#pragma GCC diagnostic ignored "-Wclobbered"
#endif
+const char *mprotect_enableflag = "enable_mprotect";
+static bool option_enable_mprotect = false;
+const char *longjmp_enableflag = "enable_longjmp";
+static bool option_enable_longjmp = false;
+
struct _allocated_region;
typedef struct _allocated_region {
struct _allocated_region *next;
@@ -80,6 +85,8 @@ str CUDFprelude(void *ret)
if (!cudf_initialized) {
MT_lock_init(&cache_lock, "cache_lock");
cudf_initialized = true;
+ option_enable_mprotect = GDKgetenv_istrue(mprotect_enableflag)
|| GDKgetenv_isyes(mprotect_enableflag);
+ option_enable_longjmp = GDKgetenv_istrue(longjmp_enableflag) ||
GDKgetenv_isyes(longjmp_enableflag);
}
return MAL_SUCCEED;
}
@@ -107,6 +114,7 @@ static void handler(int sig, siginfo_t *
}
static bool can_mprotect_region(void* addr) {
+ if (!option_enable_mprotect) return false;
int pagesize = getpagesize();
void* page_begin = (void *)((size_t)addr - (size_t)addr % pagesize);
return page_begin == addr;
@@ -160,7 +168,7 @@ static char *clear_mprotect(void *addr,
static void *jump_GDK_malloc(size_t size)
{
void *ptr = GDKmalloc(size);
- if (!ptr) {
+ if (!ptr && option_enable_longjmp) {
longjmp(jump_buffer[THRgettid()], 2);
}
return ptr;
@@ -211,7 +219,8 @@ static void *wrapped_GDK_zalloc_nojump(s
}
\
b = COLnew(0, TYPE_##tpename, count, TRANSIENT);
\
if (!b) {
\
- longjmp(jump_buffer[THRgettid()], 2);
\
+ if (option_enable_longjmp)
longjmp(jump_buffer[THRgettid()], 2); \
+ else return;
\
}
\
self->bat = (void*) b;
\
self->count = count;
\
@@ -444,12 +453,14 @@ static str CUDFeval(Client cntxt, MalBlk
// the input data
// we remove them from the pthread_sigmask
- (void)sigemptyset(&signal_set);
- (void)sigaddset(&signal_set, SIGSEGV);
- (void)sigaddset(&signal_set, SIGBUS);
- (void)pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
+ if (option_enable_mprotect) {
+ (void)sigemptyset(&signal_set);
+ (void)sigaddset(&signal_set, SIGSEGV);
+ (void)sigaddset(&signal_set, SIGBUS);
+ (void)pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
- memset(&sa, 0, sizeof(sa));
+ memset(&sa, 0, sizeof(sa));
+ }
if (!grouped) {
sql_subfunc *sqlmorefun =
@@ -1216,75 +1227,79 @@ static str CUDFeval(Client cntxt, MalBlk
// set up a longjmp point
// this longjmp point is used for some error handling in the C function
// such as failed mallocs
- ret = setjmp(jump_buffer[tid]);
- if (ret < 0) {
- // error value
- msg = createException(MAL, "cudf.eval", "Failed setjmp: %s",
- strerror(errno));
- errno = 0;
- goto wrapup;
- } else if (ret > 0) {
- if (ret == 1) {
- msg = createException(MAL, "cudf.eval", "Attempting to
write to "
-
"the input or triggered a "
-
"segfault/bus error");
- } else if (ret == 2) {
- msg = createException(MAL, "cudf.eval",
- "Malloc
failure in internal function!");
- } else {
- // we jumped here
- msg = createException(MAL, "cudf.eval", "We longjumped
here "
-
"because of an error, but "
-
"we don't know which!");
+ if (option_enable_longjmp) {
+ ret = setjmp(jump_buffer[tid]);
+ if (ret < 0) {
+ // error value
+ msg = createException(MAL, "cudf.eval", "Failed setjmp:
%s",
+
strerror(errno));
+ errno = 0;
+ goto wrapup;
+ } else if (ret > 0) {
+ if (ret == 1) {
+ msg = createException(MAL, "cudf.eval",
"Attempting to write to "
+
"the input or triggered a "
+
"segfault/bus error");
+ } else if (ret == 2) {
+ msg = createException(MAL, "cudf.eval",
+
"Malloc failure in internal function!");
+ } else {
+ // we jumped here
+ msg = createException(MAL, "cudf.eval", "We
longjumped here "
+
"because of an error, but "
+
"we don't know which!");
+ }
+ goto wrapup;
}
- goto wrapup;
}
// set up the signal handler for catching segfaults
- memset(&sa, 0, sizeof(sa));
- sa.sa_flags = SA_SIGINFO;
- sigfillset(&sa.sa_mask);
- sa.sa_sigaction = handler;
- if (sigaction(SIGSEGV, &sa, &oldsa) == -1 ||
- sigaction(SIGBUS, &sa, &oldsb) == -1) {
- msg = createException(MAL, "cudf.eval",
- "Failed to set signal
handler: %s",
- strerror(errno));
- errno = 0;
- goto wrapup;
- }
-
- // actually mprotect the regions now that the signal handlers are set
- region_iter = regions;
- while (region_iter) {
- if (mprotect(region_iter->addr, region_iter->len, PROT_READ) <
0) {
+ if (option_enable_mprotect) {
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_flags = SA_SIGINFO;
+ sigfillset(&sa.sa_mask);
+ sa.sa_sigaction = handler;
+ if (sigaction(SIGSEGV, &sa, &oldsa) == -1 ||
+ sigaction(SIGBUS, &sa, &oldsb) == -1) {
+ msg = createException(MAL, "cudf.eval",
+ "Failed to
set signal handler: %s",
+
strerror(errno));
+ errno = 0;
goto wrapup;
}
- region_iter = region_iter->next;
+ // actually mprotect the regions now that the signal handlers
are set
+ region_iter = regions;
+ while (region_iter) {
+ if (mprotect(region_iter->addr, region_iter->len,
PROT_READ) < 0) {
+ goto wrapup;
+ }
+ region_iter = region_iter->next;
+ }
}
-
// call the actual jitted function
msg = func(inputs, outputs, wrapped_GDK_malloc);
- // clear any mprotected regions
- while (regions) {
- mprotected_region *next = regions->next;
- clear_mprotect(regions->addr, regions->len);
- GDKfree(regions);
- regions = next;
+
+ if (option_enable_mprotect) {
+ // clear any mprotected regions
+ while (regions) {
+ mprotected_region *next = regions->next;
+ clear_mprotect(regions->addr, regions->len);
+ GDKfree(regions);
+ regions = next;
+ }
+ // clear the signal handlers
+ if (sigaction(SIGSEGV, &oldsa, NULL) == -1 ||
+ sigaction(SIGBUS, &oldsb, NULL) == -1) {
+ msg = createException(MAL, "cudf.eval",
+ "Failed to
unset signal handler: %s",
+
strerror(errno));
+ errno = 0;
+ goto wrapup;
+ }
+ memset(&sa, 0, sizeof(sa));
}
- // clear the signal handlers
- if (sigaction(SIGSEGV, &oldsa, NULL) == -1 ||
- sigaction(SIGBUS, &oldsb, NULL) == -1) {
- msg = createException(MAL, "cudf.eval",
- "Failed to unset
signal handler: %s",
- strerror(errno));
- errno = 0;
- goto wrapup;
- }
- memset(&sa, 0, sizeof(sa));
-
if (msg) {
// failure in function
msg = createException(MAL, "cudf.eval", "%s", msg);
@@ -1472,26 +1487,30 @@ static str CUDFeval(Client cntxt, MalBlk
wrapup:
// cleanup
// remove the signal handler, if any was set
- if (sa.sa_sigaction) {
- sigaction(SIGSEGV, &oldsa, NULL);
- sigaction(SIGBUS, &oldsb, NULL);
+ if (option_enable_mprotect) {
+ if (sa.sa_sigaction) {
+ sigaction(SIGSEGV, &oldsa, NULL);
+ sigaction(SIGBUS, &oldsb, NULL);
- memset(&sa, 0, sizeof(sa));
- }
- // clear any mprotected regions
- while (regions) {
- mprotected_region *next = regions->next;
- clear_mprotect(regions->addr, regions->len);
- GDKfree(regions);
- regions = next;
+ memset(&sa, 0, sizeof(sa));
+ }
+ // clear any mprotected regions
+ while (regions) {
+ mprotected_region *next = regions->next;
+ clear_mprotect(regions->addr, regions->len);
+ GDKfree(regions);
+ regions = next;
+ }
}
while (allocated_regions[tid]) {
allocated_region *next = allocated_regions[tid]->next;
GDKfree(allocated_regions[tid]);
allocated_regions[tid] = next;
}
- // block segfaults and bus errors again after we exit
- (void)pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
+ if (option_enable_mprotect) {
+ // block segfaults and bus errors again after we exit
+ (void)pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
+ }
// argument names (input)
if (args) {
for (i = 0; i < (size_t)pci->argc; i++) {
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list