prevent an unsigned overflow in FT1 has_chars() implementation
[imager.git] / error.c
CommitLineData
606237f9
TC
1/*
2=head1 NAME
3
4error.c - error reporting code for Imager
5
6=head1 SYNOPSIS
7
8 // user code:
9 int new_fatal; // non-zero if errors are fatal
10 int old_fatal = i_set_failure_fatal(new_fatal);
11 i_set_argv0("name of your program");
12 extern void error_cb(char const *);
13 i_error_cb old_ecb;
14 old_ecb = i_set_error_cb(error_cb);
15 i_failed_cb old_fcb;
16 extern void failed_cb(char **errors);
17 old_fcb = i_set_failed_cb(failed_cb);
18 if (!i_something(...)) {
19 char **errors = i_errors();
20 }
21
22 // imager code:
23 undef_int i_something(...) {
24 i_clear_error();
25 if (!some_lower_func(...)) {
26 return i_failed("could not something");
27 }
28 return 1;
29 }
30 undef_int some_lower_func(...) {
31 if (somethingelse_failed()) {
32 i_push_error("could not somethingelse");
33 return 0;
34 }
35 return 1;
36 }
37
38=head1 DESCRIPTION
39
40This module provides the C level error handling functionality for
41Imager.
42
c5cf7614
TC
43A few functions return or pass in an i_errmsg *, this is list of error
44structures, terminated by an entry with a NULL msg value, each of
45which contains a msg and an error code. Even though these aren't
46passed as i_errmsg const * pointers, don't modify the strings
47or the pointers.
606237f9
TC
48
49The interface as currently defined isn't thread safe, unfortunately.
50
51This code uses Imager's mymalloc() for memory allocation, so out of
52memory errors are I<always> fatal.
53
54=head1 INTERFACE
55
56These functions form the interface that a user of Imager sees (from
57C). The Perl level won't use all of this.
58
59=over
60
61=cut
62*/
63
74315ca9 64#include "imageri.h"
606237f9
TC
65#include <stdio.h>
66#include <stdlib.h>
67
d03fd5a4 68/*
8b30e240
TC
69=item im_errors(ctx)
70=synopsis i_errmsg *errors = im_errors(aIMCTX);
71=synopsis i_errmsg *errors = i_errors();
606237f9
TC
72
73Returns a pointer to the first element of an array of error messages,
74terminated by a NULL pointer. The highest level message is first.
75
8b30e240
TC
76Also callable as C<i_errors()>.
77
606237f9
TC
78=cut
79*/
74315ca9
TC
80i_errmsg *im_errors(im_context_t ctx) {
81 return ctx->error_stack + ctx->error_sp;
82}
83
606237f9
TC
84/*
85=back
86
87=head1 INTERNAL FUNCTIONS
88
89These functions are called by Imager to report errors through the
90above interface.
91
92It may be desirable to have functions to mark the stack and reset to
93the mark.
94
95=over
96
abffffed
TC
97=item im_clear_error(ctx)
98X<im_clear_error API>X<i_clear_error API>
99=synopsis im_clear_error(aIMCTX);
6cfee9d1 100=synopsis i_clear_error();
92bda632
TC
101=category Error handling
102
103Clears the error stack.
104
5715f7c3 105Called by any Imager function before doing any other processing.
606237f9 106
abffffed
TC
107Also callable as C<i_clear_error()>.
108
92bda632
TC
109=cut
110*/
74315ca9
TC
111
112void
113im_clear_error(im_context_t ctx) {
cd4b0b20
TC
114#ifdef IMAGER_DEBUG_MALLOC
115 int i;
116
74315ca9
TC
117 for (i = 0; i < IM_ERROR_COUNT; ++i) {
118 if (ctx->error_space[i]) {
119 myfree(ctx->error_stack[i].msg);
120 ctx->error_stack[i].msg = NULL;
121 ctx->error_space[i] = 0;
cd4b0b20
TC
122 }
123 }
124#endif
74315ca9
TC
125 ctx->error_sp = IM_ERROR_COUNT-1;
126}
127
606237f9 128/*
abffffed
TC
129=item im_push_error(ctx, code, message)
130X<im_push_error API>X<i_push_error API>
6cfee9d1
TC
131=synopsis i_push_error(0, "Yep, it's broken");
132=synopsis i_push_error(errno, "Error writing");
abffffed 133=synopsis im_push_error(aIMCTX, 0, "Something is wrong");
92bda632
TC
134=category Error handling
135
6cfee9d1 136Called by an Imager function to push an error message onto the stack.
606237f9
TC
137
138No message is pushed if the stack is full (since this means someone
139forgot to call i_clear_error(), or that a function that doesn't do
140error handling is calling function that does.).
141
142=cut
143*/
74315ca9
TC
144void
145im_push_error(im_context_t ctx, int code, char const *msg) {
8d14daab 146 size_t size = strlen(msg)+1;
606237f9 147
74315ca9 148 if (ctx->error_sp <= 0)
606237f9
TC
149 /* bad, bad programmer */
150 return;
151
74315ca9
TC
152 --ctx->error_sp;
153 if (ctx->error_alloc[ctx->error_sp] < size) {
154 if (ctx->error_stack[ctx->error_sp].msg)
155 myfree(ctx->error_stack[ctx->error_sp].msg);
f0960b14 156 /* memory allocated on the following line is only ever released when
606237f9 157 we need a bigger string */
f0960b14
TC
158 /* size is size (len+1) of an existing string, overflow would mean
159 the system is broken anyway */
74315ca9
TC
160 ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
161 ctx->error_alloc[ctx->error_sp] = size;
606237f9 162 }
74315ca9
TC
163 strcpy(ctx->error_stack[ctx->error_sp].msg, msg);
164 ctx->error_stack[ctx->error_sp].code = code;
165}
d03fd5a4 166
c5cf7614 167/*
abffffed
TC
168=item im_push_errorvf(ctx, code, format, args)
169X<im_push_error_vf API>X<i_push_errorvf API>
170=synopsis va_args args;
171=synopsis va_start(args, lastarg);
172=synopsis im_push_errorvf(ctx, code, format, args);
92bda632
TC
173=category Error handling
174
c5cf7614
TC
175Intended for use by higher level functions, takes a varargs pointer
176and a format to produce the finally pushed error message.
177
6cfee9d1
TC
178Does not support perl specific format codes.
179
abffffed
TC
180Also callable as C<i_push_errorvf(code, format, args)>
181
c5cf7614
TC
182=cut
183*/
74315ca9
TC
184void
185im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) {
c5cf7614 186 char buf[1024];
86c8d19a
TC
187#if defined(IMAGER_VSNPRINTF)
188 vsnprintf(buf, sizeof(buf), fmt, ap);
189#elif defined(_MSC_VER)
c5cf7614
TC
190 _vsnprintf(buf, sizeof(buf), fmt, ap);
191#else
192 /* is there a way to detect vsnprintf()?
193 for this and other functions we need some mechanism to handle
194 detection (like perl's Configure, or autoconf)
195 */
196 vsprintf(buf, fmt, ap);
197#endif
74315ca9
TC
198 im_push_error(ctx, code, buf);
199}
200
c5cf7614
TC
201/*
202=item i_push_errorf(int code, char const *fmt, ...)
6cfee9d1 203=synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
92bda632
TC
204=category Error handling
205
5715f7c3 206A version of i_push_error() that does printf() like formatting.
c5cf7614 207
6cfee9d1
TC
208Does not support perl specific format codes.
209
c5cf7614
TC
210=cut
211*/
74315ca9
TC
212void
213i_push_errorf(int code, char const *fmt, ...) {
c5cf7614
TC
214 va_list ap;
215 va_start(ap, fmt);
216 i_push_errorvf(code, fmt, ap);
217 va_end(ap);
606237f9
TC
218}
219
abffffed
TC
220/*
221=item im_push_errorf(ctx, code, char const *fmt, ...)
222=synopsis im_push_errorf(aIMCTX, errno, "Cannot open file %s: %d", filename, errno);
223=category Error handling
224
225A version of im_push_error() that does printf() like formatting.
226
227Does not support perl specific format codes.
228
229=cut
230*/
74315ca9
TC
231void
232im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) {
233 va_list ap;
234 va_start(ap, fmt);
235 im_push_errorvf(ctx, code, fmt, ap);
236 va_end(ap);
237}
238
f0960b14
TC
239#ifdef IMAGER_I_FAILED
240#error "This isn't used and is untested"
241
606237f9
TC
242/*
243=item i_failed(char const *msg)
244
245Called by Imager code to indicate that a top-level has failed.
246
c5cf7614 247msg can be NULL, in which case no error is pushed.
606237f9
TC
248
249Calls the current failed callback, if any.
250
251Aborts the program with an error, if failures have been set to be fatal.
252
253Returns zero if it does not abort.
254
255=cut
256*/
c5cf7614 257int i_failed(int code, char const *msg) {
606237f9 258 if (msg)
c5cf7614 259 i_push_error(code, msg);
606237f9
TC
260 if (failed_cb)
261 failed_cb(error_stack + error_sp);
262 if (failures_fatal) {
c5cf7614 263 int sp;
8d14daab 264 size_t total; /* total length of error messages */
c5cf7614 265 char *full; /* full message for logging */
606237f9
TC
266 if (argv0)
267 fprintf(stderr, "%s: ", argv0);
268 fputs("error:\n", stderr);
c5cf7614
TC
269 sp = error_sp;
270 while (error_stack[sp].msg) {
a743c0a6 271 fprintf(stderr, " %s\n", error_stack[sp].msg);
c5cf7614
TC
272 ++sp;
273 }
274 /* we want to log the error too, build an error message to hand to
b1e96952 275 i_fatal() */
c5cf7614
TC
276 total = 1; /* remember the NUL */
277 for (sp = error_sp; error_stack[sp].msg; ++sp) {
8d14daab
TC
278 size_t new_total += strlen(error_stack[sp].msg) + 2;
279 if (new_total < total) {
280 /* overflow, somehow */
281 break;
282 }
c5cf7614 283 }
a6c47345 284 full = mymalloc(total);
c5cf7614
TC
285 if (!full) {
286 /* just quit, at least it's on stderr */
287 exit(EXIT_FAILURE);
288 }
289 *full = 0;
290 for (sp = error_sp; error_stack[sp].msg; ++sp) {
291 strcat(full, error_stack[sp].msg);
292 strcat(full, ": ");
606237f9 293 }
c5cf7614
TC
294 /* lose the extra ": " */
295 full[strlen(full)-2] = '\0';
b1e96952 296 i_fatal(EXIT_FAILURE, "%s", full);
606237f9
TC
297 }
298
299 return 0;
300}
301
f0960b14
TC
302#endif
303
81b6f499
TC
304#ifdef IM_ASSERT
305
b3afeed5
TC
306/*
307=item im_assert_fail(file, line, message)
308
309Called when an im_assert() assertion fails.
310
81b6f499
TC
311Only available when Imager is built with assertions.
312
b3afeed5
TC
313=cut
314*/
315
316void
317im_assert_fail(char const *file, int line, char const *message) {
318 fprintf(stderr, "Assertion failed line %d file %s: %s\n",
319 line, file, message);
74315ca9 320 abort();
b3afeed5
TC
321}
322
81b6f499
TC
323#endif
324
606237f9
TC
325/*
326=back
327
328=head1 BUGS
329
330This interface isn't thread safe.
331
332=head1 AUTHOR
333
334Tony Cook <tony@develop-help.com>
335
336Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>
337
338=cut
339*/