changeset 425:7009b0ac1501

Properly freeing libpq results on errors
author Adam Chlipala <adamc@hcoop.net>
date Fri, 24 Oct 2008 17:30:07 -0400
parents b10132434adc
children 2a861b56969c
files demo/sql.urp include/urweb.h src/c/urweb.c src/cjr_print.sml tests/aborter2.ur tests/aborter2.urp
diffstat 6 files changed, 73 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- 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
 
--- 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 **);
--- 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;
 }
--- 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);",
--- /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 <xml>Shot down!</xml>))
+         0;
+    return <xml>Result: {[v]}</xml>
--- /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