comparison src/c/urweb.c @ 425:7009b0ac1501

Properly freeing libpq results on errors
author Adam Chlipala <adamc@hcoop.net>
date Fri, 24 Oct 2008 17:30:07 -0400
parents b91480c9a729
children 2a861b56969c
comparison
equal deleted inserted replaced
424:b10132434adc 425:7009b0ac1501
13 13
14 typedef struct regions { 14 typedef struct regions {
15 struct regions *next; 15 struct regions *next;
16 } regions; 16 } regions;
17 17
18 typedef struct {
19 void (*func)(void*);
20 void *arg;
21 } cleanup;
22
18 struct uw_context { 23 struct uw_context {
19 char *page, *page_front, *page_back; 24 char *page, *page_front, *page_back;
20 char *heap, *heap_front, *heap_back; 25 char *heap, *heap_front, *heap_back;
21 char **inputs; 26 char **inputs;
22 27
24 29
25 jmp_buf jmp_buf; 30 jmp_buf jmp_buf;
26 31
27 regions *regions; 32 regions *regions;
28 33
34 cleanup *cleanup, *cleanup_front, *cleanup_back;
35
29 char error_message[ERROR_BUF_LEN]; 36 char error_message[ERROR_BUF_LEN];
30 }; 37 };
31 38
32 extern int uw_inputs_len; 39 extern int uw_inputs_len;
33 40
43 ctx->inputs = calloc(uw_inputs_len, sizeof(char *)); 50 ctx->inputs = calloc(uw_inputs_len, sizeof(char *));
44 51
45 ctx->db = NULL; 52 ctx->db = NULL;
46 53
47 ctx->regions = NULL; 54 ctx->regions = NULL;
55
56 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0);
48 57
49 ctx->error_message[0] = 0; 58 ctx->error_message[0] = 0;
50 59
51 return ctx; 60 return ctx;
52 } 61 }
61 70
62 void uw_free(uw_context ctx) { 71 void uw_free(uw_context ctx) {
63 free(ctx->page); 72 free(ctx->page);
64 free(ctx->heap); 73 free(ctx->heap);
65 free(ctx->inputs); 74 free(ctx->inputs);
75 free(ctx->cleanup);
66 free(ctx); 76 free(ctx);
67 } 77 }
68 78
69 void uw_reset_keep_request(uw_context ctx) { 79 void uw_reset_keep_request(uw_context ctx) {
70 ctx->page_front = ctx->page; 80 ctx->page_front = ctx->page;
71 ctx->heap_front = ctx->heap; 81 ctx->heap_front = ctx->heap;
72 ctx->regions = NULL; 82 ctx->regions = NULL;
83 ctx->cleanup_front = ctx->cleanup;
73 84
74 ctx->error_message[0] = 0; 85 ctx->error_message[0] = 0;
75 } 86 }
76 87
77 void uw_reset_keep_error_message(uw_context ctx) { 88 void uw_reset_keep_error_message(uw_context ctx) {
78 ctx->page_front = ctx->page; 89 ctx->page_front = ctx->page;
79 ctx->heap_front = ctx->heap; 90 ctx->heap_front = ctx->heap;
80 ctx->regions = NULL; 91 ctx->regions = NULL;
92 ctx->cleanup_front = ctx->cleanup;
81 } 93 }
82 94
83 void uw_reset(uw_context ctx) { 95 void uw_reset(uw_context ctx) {
84 uw_reset_keep_request(ctx); 96 uw_reset_keep_request(ctx);
85 memset(ctx->inputs, 0, uw_inputs_len * sizeof(char *)); 97 memset(ctx->inputs, 0, uw_inputs_len * sizeof(char *));
105 117
106 return r; 118 return r;
107 } 119 }
108 120
109 __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) { 121 __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) {
122 cleanup *cl;
123
110 va_list ap; 124 va_list ap;
111 va_start(ap, fmt); 125 va_start(ap, fmt);
112 126
113 vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap); 127 vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap);
114 128
129 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
130 cl->func(cl->arg);
131
132 ctx->cleanup_front = ctx->cleanup;
133
115 longjmp(ctx->jmp_buf, fk); 134 longjmp(ctx->jmp_buf, fk);
135 }
136
137 void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) {
138 if (ctx->cleanup_front >= ctx->cleanup_back) {
139 int len = ctx->cleanup_back - ctx->cleanup, newLen;
140 if (len == 0)
141 newLen = 1;
142 else
143 newLen *= 2;
144 ctx->cleanup = realloc(ctx->cleanup, newLen);
145 ctx->cleanup_front = ctx->cleanup + len;
146 ctx->cleanup_back = ctx->cleanup + newLen;
147 }
148
149 ctx->cleanup_front->func = func;
150 ctx->cleanup_front->arg = arg;
151 ++ctx->cleanup_front;
152 }
153
154 void uw_pop_cleanup(uw_context ctx) {
155 if (ctx->cleanup_front == ctx->cleanup)
156 uw_error(ctx, FATAL, "Attempt to pop from empty cleanup action stack");
157
158 --ctx->cleanup_front;
159 ctx->cleanup_front->func(ctx->cleanup_front->arg);
116 } 160 }
117 161
118 char *uw_error_message(uw_context ctx) { 162 char *uw_error_message(uw_context ctx) {
119 return ctx->error_message; 163 return ctx->error_message;
120 } 164 }