# HG changeset patch # User Adam Chlipala # Date 1224883807 14400 # Node ID 7009b0ac15014598e4292fd818697735150dbe52 # Parent b10132434adc815e60eb3b02ba699348d1f40d27 Properly freeing libpq results on errors diff -r b10132434adc -r 7009b0ac1501 demo/sql.urp --- a/demo/sql.urp Fri Oct 24 16:47:18 2008 -0400 +++ b/demo/sql.urp Fri Oct 24 17:30:07 2008 -0400 @@ -1,3 +1,4 @@ +debug database dbname=test sql sql.sql diff -r b10132434adc -r 7009b0ac1501 include/urweb.h --- a/include/urweb.h Fri Oct 24 16:47:18 2008 -0400 +++ b/include/urweb.h Fri Oct 24 17:30:07 2008 -0400 @@ -19,6 +19,8 @@ __attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *fmt, ...); char *uw_error_message(uw_context); +void uw_push_cleanup(uw_context, void (*func)(void *), void *arg); +void uw_pop_cleanup(uw_context); void *uw_malloc(uw_context, size_t); void uw_begin_region(uw_context); @@ -38,29 +40,28 @@ char *uw_Basis_htmlifyString(uw_context, uw_Basis_string); char *uw_Basis_htmlifyBool(uw_context, uw_Basis_bool); -void uw_Basis_htmlifyInt_w(uw_context, uw_Basis_int); -void uw_Basis_htmlifyFloat_w(uw_context, uw_Basis_float); -void uw_Basis_htmlifyString_w(uw_context, uw_Basis_string); -void uw_Basis_htmlifyBool_w(uw_context, uw_Basis_bool); +uw_unit uw_Basis_htmlifyInt_w(uw_context, uw_Basis_int); +uw_unit uw_Basis_htmlifyFloat_w(uw_context, uw_Basis_float); +uw_unit uw_Basis_htmlifyString_w(uw_context, uw_Basis_string); +uw_unit uw_Basis_htmlifyBool_w(uw_context, uw_Basis_bool); char *uw_Basis_attrifyInt(uw_context, uw_Basis_int); char *uw_Basis_attrifyFloat(uw_context, uw_Basis_float); char *uw_Basis_attrifyString(uw_context, uw_Basis_string); -void uw_Basis_attrifyInt_w(uw_context, uw_Basis_int); -void uw_Basis_attrifyFloat_w(uw_context, uw_Basis_float); -void uw_Basis_attrifyString_w(uw_context, uw_Basis_string); - +uw_unit uw_Basis_attrifyInt_w(uw_context, uw_Basis_int); +uw_unit uw_Basis_attrifyFloat_w(uw_context, uw_Basis_float); +uw_unit uw_Basis_attrifyString_w(uw_context, uw_Basis_string); char *uw_Basis_urlifyInt(uw_context, uw_Basis_int); char *uw_Basis_urlifyFloat(uw_context, uw_Basis_float); char *uw_Basis_urlifyString(uw_context, uw_Basis_string); char *uw_Basis_urlifyBool(uw_context, uw_Basis_bool); -void uw_Basis_urlifyInt_w(uw_context, uw_Basis_int); -void uw_Basis_urlifyFloat_w(uw_context, uw_Basis_float); -void uw_Basis_urlifyString_w(uw_context, uw_Basis_string); -void uw_Basis_urlifyBool_w(uw_context, uw_Basis_bool); +uw_unit uw_Basis_urlifyInt_w(uw_context, uw_Basis_int); +uw_unit uw_Basis_urlifyFloat_w(uw_context, uw_Basis_float); +uw_unit uw_Basis_urlifyString_w(uw_context, uw_Basis_string); +uw_unit uw_Basis_urlifyBool_w(uw_context, uw_Basis_bool); uw_Basis_int uw_Basis_unurlifyInt(uw_context, char **); uw_Basis_float uw_Basis_unurlifyFloat(uw_context, char **); diff -r b10132434adc -r 7009b0ac1501 src/c/urweb.c --- a/src/c/urweb.c Fri Oct 24 16:47:18 2008 -0400 +++ b/src/c/urweb.c Fri Oct 24 17:30:07 2008 -0400 @@ -15,6 +15,11 @@ struct regions *next; } regions; +typedef struct { + void (*func)(void*); + void *arg; +} cleanup; + struct uw_context { char *page, *page_front, *page_back; char *heap, *heap_front, *heap_back; @@ -26,6 +31,8 @@ regions *regions; + cleanup *cleanup, *cleanup_front, *cleanup_back; + char error_message[ERROR_BUF_LEN]; }; @@ -46,6 +53,8 @@ ctx->regions = NULL; + ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0); + ctx->error_message[0] = 0; return ctx; @@ -63,6 +72,7 @@ free(ctx->page); free(ctx->heap); free(ctx->inputs); + free(ctx->cleanup); free(ctx); } @@ -70,6 +80,7 @@ ctx->page_front = ctx->page; ctx->heap_front = ctx->heap; ctx->regions = NULL; + ctx->cleanup_front = ctx->cleanup; ctx->error_message[0] = 0; } @@ -78,6 +89,7 @@ ctx->page_front = ctx->page; ctx->heap_front = ctx->heap; ctx->regions = NULL; + ctx->cleanup_front = ctx->cleanup; } void uw_reset(uw_context ctx) { @@ -107,14 +119,46 @@ } __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) { + cleanup *cl; + va_list ap; va_start(ap, fmt); vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap); + for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl) + cl->func(cl->arg); + + ctx->cleanup_front = ctx->cleanup; + longjmp(ctx->jmp_buf, fk); } +void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) { + if (ctx->cleanup_front >= ctx->cleanup_back) { + int len = ctx->cleanup_back - ctx->cleanup, newLen; + if (len == 0) + newLen = 1; + else + newLen *= 2; + ctx->cleanup = realloc(ctx->cleanup, newLen); + ctx->cleanup_front = ctx->cleanup + len; + ctx->cleanup_back = ctx->cleanup + newLen; + } + + ctx->cleanup_front->func = func; + ctx->cleanup_front->arg = arg; + ++ctx->cleanup_front; +} + +void uw_pop_cleanup(uw_context ctx) { + if (ctx->cleanup_front == ctx->cleanup) + uw_error(ctx, FATAL, "Attempt to pop from empty cleanup action stack"); + + --ctx->cleanup_front; + ctx->cleanup_front->func(ctx->cleanup_front->arg); +} + char *uw_error_message(uw_context ctx) { return ctx->error_message; } diff -r b10132434adc -r 7009b0ac1501 src/cjr_print.sml --- a/src/cjr_print.sml Fri Oct 24 16:47:18 2008 -0400 +++ b/src/cjr_print.sml Fri Oct 24 17:30:07 2008 -0400 @@ -850,6 +850,8 @@ string "uw_end_region(ctx);", newline, + string "uw_push_cleanup(ctx, (void (*)(void *))PQclear, res);", + newline, string "n = PQntuples(res);", newline, string "for (i = 0; i < n; ++i) {", @@ -906,7 +908,7 @@ string "}", newline, newline, - string "PQclear(res);", + string "uw_pop_cleanup(ctx);", newline, if wontLeakAnything then box [string "uw_end_region(ctx);", diff -r b10132434adc -r 7009b0ac1501 tests/aborter2.ur --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/aborter2.ur Fri Oct 24 17:30:07 2008 -0400 @@ -0,0 +1,7 @@ +table t : { X : int } + +fun main () : transaction page = + v <- query (SELECT * FROM t) + (fn r (_ : int) => return (error Shot down!)) + 0; + return Result: {[v]} diff -r b10132434adc -r 7009b0ac1501 tests/aborter2.urp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/aborter2.urp Fri Oct 24 17:30:07 2008 -0400 @@ -0,0 +1,5 @@ +debug +database dbname=aborter +sql aborter2.sql + +aborter2