PIPS
errors.c
Go to the documentation of this file.
1 /*
2 
3  $Id: errors.c 1671 2019-06-26 19:14:11Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of Linear/C3 Library.
8 
9  Linear/C3 Library is free software: you can redistribute it and/or modify it
10  under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  Linear/C3 Library is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with Linear/C3 Library. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 /*
26  Exception management. See "arithmetic_errors.h".
27 */
28 
29 #ifdef HAVE_CONFIG_H
30  #include "config.h"
31 #endif
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 
36 #include "boolean.h"
37 #include "arithmetique.h"
38 
39 // forward declaration...
40 static int timeout_index;
41 
42 // global variable to please the compiler
44 
45 /* This can be overrided in the PolyLib. And seems to be according to
46  gdb who cannot find the corresponding source code. */
47 char const * __attribute__ ((weak))
49 {
50  if (exception==overflow_error)
51  return "overflow_error exception";
52  if (exception==simplex_arithmetic_error)
53  return "simplex_arithmetic_error exception";
54  if (exception==user_exception_error)
55  return "user_exception_error exception";
56  if (exception==parser_exception_error)
57  return "parser_exception_error exception";
58  if (exception==timeout_error)
59  return "timeout_error exception";
60  if (exception==any_exception_error)
61  return "all exceptions mask";
62 
63  return "unknown or mixed exception";
64 }
65 
66 /********************************************************* EXCEPTION COUNTS */
67 
68 static unsigned int
72 
73 /* reset linear counters
74  */
76 {
79  misc_error_count = 0;
80 }
81 
82 /* return number of linear errors
83  * may be used as a test after a reset to know whether new errors occured.
84  */
85 unsigned int linear_error_count(void)
86 {
88 }
89 
90 /* return various errors counts through unsigned int pointer
91  * overflow, simplex & misc (aka others)
92  * NULL pointers are ignored
93  */
95  unsigned int *poe, unsigned int * pse, unsigned int *pme)
96 {
97  if (poe) *poe = overflow_error_count;
98  if (pse) *pse = simplex_error_count;
99  if (pme) *pme = misc_error_count;
100 }
101 
102 static void linear_record_exception(const linear_exception_t exception)
103 {
104  if (exception==overflow_error)
106  else if (exception==simplex_arithmetic_error)
108  else if (exception==user_exception_error ||
109  exception==parser_exception_error ||
110  exception==timeout_error)
111  misc_error_count ++;
112 }
113 
114 /* keep track of last thrown exception for RETHROW()
115  */
116 /* This can be overrided in the PolyLib */
118 
119 /* whether to run in debug mode (that is to trace catch/uncatch/throw)
120  */
121 static bool linear_exception_debug_mode = false;
122 static unsigned int linear_exception_verbose = 1 | 2 | 16 ;
123 
124 /* A structure for the exception stack.
125  */
126 typedef struct
127 {
128  // exception type.
129  int what;
130 
131  // where to jump to.
132  jmp_buf where;
133 
134  // location of the CATCH to be matched against the UNCATCH.
135  char const * function;
136  char const * file;
137  int line;
138 
139  // timeout synchronisation
140  int timeout;
141 }
143 
144 /* exception stack.
145  maximum extension.
146 - current index (next available bucket)
147  */
148 #define MAX_STACKED_CONTEXTS 64
150 static int exception_index = 0;
151 
152 /* callbacks...
153  */
156 
157 /* This can be overrided in the PolyLib */
158 void __attribute__ ((weak))
162 {
163  if (push_callback!=NULL || pop_callback!=NULL)
164  {
165  fprintf(stderr, "exception callbacks already defined! (%p, %p)\n",
167  abort();
168  }
169 
171  pop_callback = pop;
172 }
173 
174 /* total number of exceptions thrown, for statistics.
175  */
176 /* This can be overrided in the PolyLib */
178 
179 /* dump stack
180  */
181 /* This can be overrided in the PolyLib */
182 void __attribute__ ((weak))
184 {
185  int i;
186  fprintf(f, "[dump_exception_stack_to_file] size=%d\n", exception_index);
187  for (i=0; i<exception_index; i++)
188  {
189  fprintf(f,
190  "%d: [%s:%d in %s (%d)]\n",
191  i,
192  exception_stack[i].file,
194  exception_stack[i].function,
195  exception_stack[i].what);
196  }
197  fprintf(f, "\n");
198 }
199 
200 /* This can be overrided in the PolyLib */
201 void __attribute__ ((weak))
203 {
205 }
206 
207 #define exception_debug_message(type) \
208  fprintf(stderr, "%s[%s:%d %s (%d)/%d]\n", \
209  type, file, line, function, what, exception_index)
210 
211 #define exception_debug_trace(type) \
212  if (linear_exception_debug_mode) \
213  exception_debug_message(type);
214 
215 #ifdef push_exception_on_stack
216 #undef push_exception_on_stack
217 #endif // push_exception_on_stack
218 
219 /* push a what exception on stack.
220  */
221 /* This can be overrided in the PolyLib */
222 jmp_buf * __attribute__ ((weak))
224  const int what,
225  const char * function,
226  const char * file,
227  const int line)
228 {
229  exception_debug_trace("PUSH ");
230 
232  {
233  exception_debug_message("push");
234  fprintf(stderr, "exception stack overflow\n");
236  abort();
237  }
238 
239  if (push_callback != NULL)
240  push_callback(file, function, line);
241 
243 
249 
251 }
252 
253 jmp_buf * __attribute__ ((weak))
255  const int what,
256  const char * function,
257  const char * file,
258  const int line)
259 {
260  return linear_push_exception_on_stack(what, function, file, line);
261 }
262 
263 
264 #if !defined(same_string_p)
265 #define same_string_p(s1, s2) (strcmp((s1),(s2))==0)
266 #endif
267 
268 #ifdef pop_exception_from_stack
269 #undef pop_exception_from_stack
270 #endif // pop_exception_from_stack
271 
272 /* pop a what exception.
273  check for any mismatch!
274  */
275 /* This can be overrided in the PolyLib */
276 void __attribute__ ((weak))
278  const int what,
279  const char * function,
280  const char * file,
281  const int line)
282 {
283  exception_debug_trace("POP ");
284 
285  if (exception_index==0)
286  {
288  fprintf(stderr, "exception stack underflow\n");
290  abort();
291  }
292 
293  if (pop_callback) pop_callback(file, function, line);
294 
295  exception_index--;
297 
298  if ((exception_stack[exception_index].what != what) ||
300  !same_string_p(exception_stack[exception_index].function, function))
301  {
302  // internal error, UNCATCH without CATCH
304  fprintf(stderr,
305  "exception stack mismatch at depth=%d:\n"
306  " CATCH: %s:%d in %s (%d)\n"
307  " UNCATCH: %s:%d in %s (%d)\n",
313  file, line, function, what);
315  abort();
316  }
317 }
318 
319 void __attribute__ ((weak))
321  const int what,
322  const char * function,
323  const char * file,
324  const int line)
325 {
326  linear_pop_exception_from_stack(what, function, file, line);
327 }
328 
329 #ifdef throw_exception
330 #undef throw_exception
331 #endif
332 
333 /* throws an exception of a given type by searching for
334  the specified 'what' in the current exception stack.
335 */
336 /* This can be overridden in the PolyLib */
337 void __attribute__ ((weak, noreturn))
339  const int what,
340  // exception location:
341  const char * function,
342  const char * file,
343  const int line)
344 {
345  int i;
346 
347  exception_debug_trace("THROW");
348 
349  the_last_just_thrown_exception = what; // for rethrow
351 
352  for (i=exception_index-1; i>=0; i--)
353  {
354  if (pop_callback)
355  // call pop callback with push parameters
357  exception_stack[i].function,
358  exception_stack[i].line);
359 
360  if (exception_stack[i].what & what)
361  {
362  exception_index = i;
364 
366  fprintf(stderr, "---->[%s:%d %s (%d)/%d]\n",
367  exception_stack[i].file,
369  exception_stack[i].function,
370  exception_stack[i].what,
371  i);
372 
373  // trace some exceptions...
374  if (linear_exception_verbose & what)
375  fprintf(stderr, "exception %d/%d: %s(%s:%d) -> %s(%s:%d)\n",
376  what, exception_stack[i].what,
377  function, file, line,
378  exception_stack[i].function,
379  exception_stack[i].file,
380  exception_stack[i].line);
381 
382  // pop timeouts
383  while (timeout_index > exception_stack[i].timeout)
384  POP_TIMEOUT();
385 
386  longjmp(exception_stack[i].where, 0);
387  }
388  }
389 
390  // internal error, THROW without matching CATCH
391  exception_debug_message("throw");
392  fprintf(stderr,
393  "exception not found in stack:\n"
394  "an exception was THROWN without a matching CATCH\n");
396 
397  // timeout triggers an exception which may be intentionnaly not caught
398  if (what == timeout_error)
399  exit(203);
400  else
401  abort();
402 }
403 
404 void __attribute__ ((weak, noreturn))
406  const int what,
407  const char * function,
408  const char * file,
409  const int line)
410 {
411  linear_throw_exception(what, function, file, line);
412 }
413 
414 // restart substitution
415 #define throw_exception linear_throw_exception
416 
417 /* This can be overridden in the PolyLib */
418 void __attribute__ ((weak))
420  unsigned int verbose_exceptions,
423 {
424  linear_exception_verbose = verbose_exceptions;
426 }
427 
428 
429 /*********************************************************************** GMP */
430 
431 static bool warned_if_inconsistent_gmp = false;
432 
433 /* whether linear can use gmp (i.e. compiled in)
434  */
435 bool linear_with_gmp(void)
436 {
437 #ifdef HAVE_GMP_H
438  return true;
439 #else
440  return false;
441 #endif // HAVE_GMP_H
442 }
443 
444 /* whether linear is asked to use gmp if possible (env variable)
445  */
447 {
448  char* env = getenv("LINEAR_USE_GMP");
449  return env && atoi(env) != 0;
450 }
451 
452 /* whether linear is to use gmp
453  */
454 bool linear_use_gmp(void)
455 {
456  bool
457  with_gmp = linear_with_gmp(),
458  req_gmp = linear_require_gmp();
459 
460  if (req_gmp && !with_gmp && !warned_if_inconsistent_gmp)
461  {
462  fprintf(stderr, "linear was compiled without GMP support\n");
464  }
465 
466  return with_gmp && req_gmp;
467 }
468 
469 /******************************************************** TIMEOUT MANAGEMENT */
470 
471 /* a stack of timeouts is kept.
472  * this may make sense to deal with local timeouts within linear
473  * but still keeping a global outside timeout for pips.
474  * on timeouts, the corresponding exception is raised... what to do
475  * about it is unclear... probably the idea is to stop more or less cleanly.
476  */
477 
478 #include <time.h>
479 #include <signal.h>
480 #include <unistd.h>
481 #include "linear_assert.h"
482 
484 
486 {
488 }
489 
490 /* hold a timeout prescription
491  */
492 typedef struct
493 {
494  // when
495  time_t start;
496  time_t end;
497  unsigned int delay;
498  const char * env;
499 
500  // where it was set
501  const char * funcname;
502  const char * filename;
503  int lineno;
504 
505 } timeout_t;
506 
507 #define TIMEOUT_MAX_STACK_SIZE 10
508 
510 static int timeout_index = 0;
511 
512 static void __attribute__((noreturn)) timeout_handler(int sig)
513 {
514  int toidx = timeout_index - 1;
515 
516  assert(sig == SIGALRM);
517  assert(toidx >= 0);
518 
519  // always say something... even if redundant with callback
520  fprintf(stderr, "timeout[%d] after %ds from %s (\"%s\":%d)\n", toidx,
521  timeouts[toidx].delay,
522  timeouts[toidx].funcname,
523  timeouts[toidx].filename,
524  timeouts[toidx].lineno);
525  fflush(stderr);
526 
527  // note: the timeout may not return
528  if (timeout_callback != NULL)
529  (*timeout_callback)(timeouts[toidx].delay,
530  timeouts[toidx].funcname,
531  timeouts[toidx].filename,
532  timeouts[toidx].lineno);
533 
534  // may try to go on, although it is probably not a good idea
535  POP_TIMEOUT();
537 }
538 
540  const unsigned int delay,
541  const char * funcname,
542  const char * filename,
543  const int lineno)
544 {
545  time_t now = time(NULL);
546 
548 
550  timeouts[timeout_index].delay = delay;
551  timeouts[timeout_index].env = NULL;
553  timeouts[timeout_index].funcname = funcname;
554  timeouts[timeout_index].filename = filename;
555  timeouts[timeout_index].lineno = lineno;
556 
557  timeout_index++;
558 
559  signal(SIGALRM, timeout_handler);
560  alarm(delay);
561 }
562 
563 static int env2int(const char * env)
564 {
565  char * val = getenv(env);
566  if (val != NULL)
567  {
568  int i = atoi(val);
569  if (i >= 0)
570  return i;
571  }
572  return -1;
573 }
574 
576  const char * env,
577  const char * funcname,
578  const char * filename,
579  const int lineno)
580 {
581  int delay = env2int(env);
582  if (delay > 0)
583  {
584  push_timeout(delay, funcname, filename, lineno);
586  return true;
587  }
588  return false;
589 }
590 
592  __attribute__((unused)) const char * funcname,
593  __attribute__((unused)) const char * filename,
594  __attribute__((unused)) const int lineno)
595 {
596  time_t now = time(NULL);
597 
598  assert(timeout_index > 0);
599 
600  // cleanup
601  alarm(0);
602  signal(SIGALRM, SIG_DFL);
603 
604  timeout_index--;
605 
606  // reset to previous delay
607  if (timeout_index > 0)
608  {
609  int delay = timeouts[timeout_index - 1].end - now;
610 
611  if (delay <= 0)
612  timeout_handler(SIGALRM);
613 
614  signal(SIGALRM, timeout_handler);
615  alarm(delay);
616  }
617 }
618 
620  const char * env,
621  const char * funcname,
622  const char * filename,
623  const int lineno)
624 {
625  int delay = env2int(env);
626  if (delay > 0)
627  pop_timeout(funcname, filename, lineno);
628 }
static void push(list l)
it is pushed in reverse order to preserve the depth first view.
Definition: graph.c:303
linear_exception_t
Global constants to designate exceptions.
@ overflow_error
@ simplex_arithmetic_error
@ user_exception_error
@ timeout_error
@ any_exception_error
catch all
@ parser_exception_error
#define THROW(what)
void(* exception_callback_t)(char const *, char const *, int const)
void(* timeout_callback_f)(int, const char *, const char *, int)
callback for timeout expecting: delay, function, file, lineno
#define POP_TIMEOUT()
linear_exception_t the_last_just_thrown_exception
void set_exception_callbacks(exception_callback_t, exception_callback_t)
int linear_number_of_exception_thrown
void linear_initialize_exception_stack(unsigned int, exception_callback_t, exception_callback_t)
jmp_buf * linear_push_exception_on_stack(const int, const char *, const char *, const int)
jmp_buf * push_exception_on_stack(const int, const char *, const char *, const int)
void dump_exception_stack(void)
void pop_exception_from_stack(const int, const char *, const char *, const int)
void dump_exception_stack_to_file(FILE *)
void linear_throw_exception(const int, const char *, const char *, const int)
char const * get_exception_name(const linear_exception_t)
void linear_pop_exception_from_stack(const int, const char *, const char *, const int)
static pipsmake_callback_handler_type callback
Definition: callback.c:39
void linear_get_error_counts(unsigned int *poe, unsigned int *pse, unsigned int *pme)
return various errors counts through unsigned int pointer overflow, simplex & misc (aka others) NULL ...
Definition: errors.c:94
static unsigned int misc_error_count
Definition: errors.c:71
void linear_reset_error_counters(void)
reset linear counters
Definition: errors.c:75
static timeout_t timeouts[TIMEOUT_MAX_STACK_SIZE]
Definition: errors.c:509
static unsigned int simplex_error_count
Definition: errors.c:70
static bool linear_exception_debug_mode
whether to run in debug mode (that is to trace catch/uncatch/throw)
Definition: errors.c:121
bool linear_require_gmp(void)
whether linear is asked to use gmp if possible (env variable)
Definition: errors.c:446
void pop_timeout_env(const char *env, const char *funcname, const char *filename, const int lineno)
Definition: errors.c:619
static unsigned int linear_exception_verbose
Definition: errors.c:122
#define throw_exception
Definition: errors.c:415
static unsigned int overflow_error_count
Definition: errors.c:69
static exception_callback_t pop_callback
Definition: errors.c:155
static int timeout_index
Definition: errors.c:40
static void linear_record_exception(const linear_exception_t exception)
Definition: errors.c:102
#define exception_debug_trace(type)
Definition: errors.c:211
bool push_timeout_env(const char *env, const char *funcname, const char *filename, const int lineno)
Definition: errors.c:575
static bool warned_if_inconsistent_gmp
Definition: errors.c:431
char const * __attribute__((weak))
This can be overrided in the PolyLib.
Definition: errors.c:47
int linear_assertion_result
errors.c
Definition: errors.c:43
#define exception_debug_message(type)
Definition: errors.c:207
bool linear_use_gmp(void)
whether linear is to use gmp
Definition: errors.c:454
static exception_callback_t push_callback
callbacks...
Definition: errors.c:154
void push_timeout(const unsigned int delay, const char *funcname, const char *filename, const int lineno)
Definition: errors.c:539
#define MAX_STACKED_CONTEXTS
exception stack.
Definition: errors.c:148
static timeout_callback_f timeout_callback
a stack of timeouts is kept.
Definition: errors.c:483
#define same_string_p(s1, s2)
Definition: errors.c:265
void set_timeout_callback(timeout_callback_f callback)
Definition: errors.c:485
static int exception_index
Definition: errors.c:150
#define TIMEOUT_MAX_STACK_SIZE
Definition: errors.c:507
unsigned int linear_error_count(void)
return number of linear errors may be used as a test after a reset to know whether new errors occured...
Definition: errors.c:85
void pop_timeout(__attribute__((unused)) const char *funcname, __attribute__((unused)) const char *filename, __attribute__((unused)) const int lineno)
Definition: errors.c:591
static linear_exception_holder exception_stack[MAX_STACKED_CONTEXTS]
Definition: errors.c:149
static int env2int(const char *env)
Definition: errors.c:563
bool linear_with_gmp(void)
whether linear can use gmp (i.e.
Definition: errors.c:435
static jmp_buf env
Definition: genClib.c:2473
#define exit(code)
Definition: misc-local.h:54
#define abort()
Definition: misc-local.h:53
#define assert(ex)
Definition: newgen_assert.h:41
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
static int line
FLEX_SCANNER.
Definition: scanner.c:852
A structure for the exception stack.
Definition: errors.c:127
char const * function
Definition: errors.c:135
char const * file
Definition: errors.c:136
hold a timeout prescription
Definition: errors.c:493
time_t end
Definition: errors.c:496
unsigned int delay
Definition: errors.c:497
const char * env
Definition: errors.c:498
time_t start
Definition: errors.c:495
const char * funcname
Definition: errors.c:501
const char * filename
Definition: errors.c:502
int lineno
Definition: errors.c:503