cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parse_crashdo.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2022 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*ParseCrashDo any of several tests to check that the code can crash */
4 #include "cddefines.h"
5 #include "parser.h"
6 #include "container_classes.h"
7 #include "vectorize.h"
8 
9 #ifdef _MSC_VER
10  /* disable warning about undefined vars being used - one of the tests shall do exactly that */
11 # pragma warning( disable : 4700 )
12  /* disable warning about division by zero */
13 # pragma warning( disable : 4756 )
14  /* disable warning that conditional expression is constant, true or false in if */
15 # pragma warning( disable : 4127 )
16 #endif
17 
18 #ifdef __INTEL_COMPILER
19 # pragma warning( disable : 592 )
20 #endif
21 
22 #ifdef __clang__
23 # pragma clang diagnostic ignored "-Wuninitialized"
24 #endif
25 
26 #ifdef __GNUC_EXCL__
27 # pragma GCC diagnostic ignored "-Wuninitialized"
28 # if ( __GNUC__ > 4 ) || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 7 )
29 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
30 # endif
31 #endif
32 
33 #if __SUNPRO_CC >= 20800
34 # pragma error_messages (off,SEC_UNINITIALIZED_MEM_READ)
35 #endif
36 
37 /* this is size of array used in array bounds exceeded crash test */
38 const int ARR_SIZE = 10;
39 
40 /* static variable used in undefined and bounds tests */
41 static double ar2[ARR_SIZE];
42 
43 // force optimization off; any level of optimization will kill the
44 // functionality of this routine
45 #if defined(_MSC_VER) || defined(__ICC)
46 #pragma optimize("", off)
47 #elif defined(__PGI)
48 #pragma global opt=0
49 #endif
50 
51 /*ParseCrashDo any of several tests to check that the code can crash */
53 {
54  double ar1, br1;
55  bool lgCrash = false;
56 
57  DEBUG_ENTRY( "ParseCrashDo()" );
58 
59  /* div by 0 to get crash as check on FP environment */
60  if( p.nMatch("ZERO") )
61  {
62  fprintf(ioQQQ," I will now div by 0 to get crash. Hold on.\n");
63  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
64  " there are problems.\n");
65  fflush(ioQQQ);
66  ar1 = 1. / ZeroNum;
67  fprintf(ioQQQ," I am still alive - something is wrong, result is %e\n",
68  ar1);
69  lgCrash = true;
70  }
71 
72  /* use some undefined numbers */
73  else if( p.nMatch("UNDE") )
74  {
75  if( p.nMatch("STAT") )
76  {
77  fprintf(ioQQQ," Now I will now use an undefined static variable. Hold on.\n");
78  fprintf(ioQQQ," This should never fail since the compiler should have automatically"
79  " initialized it to zero.\n");
80  fflush(ioQQQ);
81  /*lint -e530 ar2 not initialized */
82  ar2[0] *= 1e-10;
83  /*lint +e530 ar2 not initialized */
84 
85  fprintf(ioQQQ," I am still alive, this is the expected result. The "
86  "result of the multiplication of undefined by 1e-10 is "
87  "%e\n", ar2[0] );
88  fflush(ioQQQ);
89  }
90  else if( p.nMatch("STAC") || p.nMatch("AUTO") )
91  {
92  double A_variable_which_SHOULD_be_used_uninitialized;
93  fprintf(ioQQQ," Now I will now use an undefined variable off the stack. Hold on.\n");
94  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
95  " there are problems.\n");
96  fflush(ioQQQ);
97  /*lint -e530 a not initialized */
98  A_variable_which_SHOULD_be_used_uninitialized *= 1e-10f;
99  /*lint +e530 a not initialized */
100 
101  fprintf(ioQQQ," I am still alive - something is wrong, the result of the multiplication of"
102  " undefined by 1e-10 is %e\n", A_variable_which_SHOULD_be_used_uninitialized );
103  fflush(ioQQQ);
104  }
105  else
106  {
107  double *aa = (double*)MALLOC(3*sizeof(double));
108  fprintf(ioQQQ," I will now use an undefined variable off the heap obtained with malloc."
109  " Hold on.\n");
110  /* MyIsnan is guaranteed not to crash on FPE */
111  if( MyIsnan( aa[1] ) )
112  fprintf(ioQQQ," The malloc'ed memory was set to NaN.\n" );
113  else
114  fprintf(ioQQQ," The malloc'ed memory was NOT initialized by MyMalloc.\n" );
115  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
116  " there are problems.\n");
117  fflush(ioQQQ);
118  /*lint -e530 aa[1] not initialized */
119  aa[1] *= 1e-10;
120  /*lint +e530 aa[1] not initialized */
121  fprintf(ioQQQ," I am still alive - something is wrong, the result of the multiplication"
122  " of undefined by 1e-10 is %e\n", aa[1] );
123  fflush(ioQQQ);
124  free( aa );
125  }
126  lgCrash = true;
127  }
128 
129  /* make overflow to get crash as check on FP environment */
130  else if( p.nMatch("OVER") && p.nMatch("LONG") )
131  {
132  long lng;
133  fprintf(ioQQQ," I will now make long overflow to get crash. Hold on.\n");
134  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
135  " there are problems.\n");
136  fflush(ioQQQ);
137  lng = (long)(double(LONG_MAX)*sqrt(1e6));
138  fprintf(ioQQQ," I am still alive - something is wrong, the result was %li\n",
139  lng);
140  lgCrash = true;
141  }
142 
143  /* make overflow to get crash as check on FP environment */
144  else if( p.nMatch("OVER") )
145  {
146  ar1 = 1e-20;
147  fprintf(ioQQQ," I will now make floating point overflow to get crash. Hold on.\n");
148  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
149  " there are problems.\n");
150  fflush(ioQQQ);
151  br1 = DBL_MAX / ar1;
152  fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
153  br1);
154  lgCrash = true;
155  }
156 
157  /* assert false test to get crash as check on environment */
158  else if( p.nMatch("ASSE") )
159  {
160  fprintf(ioQQQ," I will now assert that a false statement is true to get a crash.\n\n");
161  fprintf(ioQQQ," The correct behavior is for the statement \"PROBLEM DISASTER An assert"
162  " has been thrown, this is bad\" to be printed, followed by lots more scary"
163  " looking messages.\n\n");
164  fprintf(ioQQQ," If the next line says \"I am still alive - the assert macro is not working ....\" then"
165  " there are problems.\n\n");
166  fflush(ioQQQ);
167  ASSERT( DBL_MAX < ZeroNum );
168  fprintf(ioQQQ," I am still alive - the assert macro is not working in this executable.\n");
169  lgCrash = true;
170  }
171 
172  /* assert ratios of zeros (NaN) to get crash as check on environment */
173  else if( p.nMatch(" NAN") )
174  {
175  ar1 = 0.;
176  fprintf(ioQQQ," I will now make invalid operation (div 0 by 0) to get crash. Hold on.\n");
177  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
178  " there are problems.\n");
179  fflush(ioQQQ);
180  br1 = ar1 / ZeroNum;
181  fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
182  br1);
183  lgCrash = true;
184  }
185 
186  /* assert that the set_NaN routine works properly for floats */
187  else if( p.nMatch("SETN") && p.nMatch("FLOA") )
188  {
189  sys_float f;
190  fprintf(ioQQQ," I will now initialize a float to a signaling NaN. This should never crash!\n");
191  set_NaN(f);
192  fprintf(ioQQQ," Initialization finished. I will now perform an operation on this variable."
193  " Hold on.\n");
194  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
195  " there are problems.\n");
196  fflush(ioQQQ);
197  f *= 2.f;
198  fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
199  f);
200  lgCrash = true;
201  }
202 
203  /* assert that the set_NaN routine works properly for doubles */
204  else if( p.nMatch("SETN") )
205  {
206  double d;
207  fprintf(ioQQQ," I will now initialize a double to a signaling NaN. This should never crash!\n");
208  set_NaN(d);
209  fprintf(ioQQQ," Initialization finished. I will now perform an operation on this variable."
210  " Hold on.\n");
211  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then"
212  " there are problems.\n");
213  fflush(ioQQQ);
214  d *= 2.;
215  fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
216  d);
217  lgCrash = true;
218  }
219 
220  /* test what happens with an array index out of bounds
221  * two options, low for [<0] and high for [>limit] */
222  else if( p.nMatch("BOUN") )
223  {
224  double x;
225 
226  /* read offset */
227  x = p.FFmtRead();
228  if( p.lgEOL() && p.nMatch(" LOW" ) )
229  x = -2.;
230  if( p.lgEOL() && p.nMatch("HIGH" ) )
231  x = 2.;
232 
233  /* if x >= 0 (which includes default case where x is not entered)
234  * i will be x beyond the end of the array, or x before the start */
235  long int i = ( x >= 0. ) ? (long)(x+0.5) + ARR_SIZE : (long)(x-0.5);
236 
237  /* must turn off PCLint detection of logical errors in this block */
238  if( p.nMatch("STAT") )
239  {
240  fprintf(ioQQQ," I will now access static array element ar2[%ld]. Hold on.\n", i );
241  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
242  " there are problems.\n");
243  fflush(ioQQQ);
244  ar2[i] = 1e-10;
245 
246  fprintf(ioQQQ," I am still alive - something is wrong\n" );
247  fflush(ioQQQ);
248  }
249  else if( p.nMatch("STAC") || p.nMatch("AUTO") )
250  {
251  double a[ARR_SIZE];
252  fprintf(ioQQQ," I will now access automatic array element a[%ld]. Hold on.\n", i );
253  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
254  " there are problems.\n");
255  fflush(ioQQQ);
256  a[i] = 1e-10;
257 
258  fprintf(ioQQQ," I am still alive - something is wrong, return value was %.2e\n", a[i] );
259  fflush(ioQQQ);
260  }
261  else if( p.nMatch("HEAP") )
262  {
263  int *ibound;
264  ibound = ((int *)MALLOC( ARR_SIZE*sizeof(int) ));
265  fprintf(ioQQQ," I will now access malloced heap array element ibound[%ld]. Hold on.\n", i );
266  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
267  " there are problems.\n");
268  fflush(ioQQQ);
269  ibound[i] = 1;
270  fprintf(ioQQQ," I am still alive - something is wrong, return value is %i\n" , ibound[i] );
271  fflush(ioQQQ);
272  free(ibound);
273  }
274  else if( p.nMatch("VECT") )
275  {
276  vector<int> ibound(ARR_SIZE);
277  fprintf(ioQQQ," I will now access vector array element ibound[%ld]. Hold on.\n", i );
278  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
279  " there are problems.\n");
280  fflush(ioQQQ);
281  ibound[i] = 1;
282  fprintf(ioQQQ," I am still alive - something is wrong, return value is %i\n" , ibound[i] );
283  fflush(ioQQQ);
284  }
285  else if( p.nMatch("MULT") )
286  {
287  /* this tests the multi_arr class testing which occurs if the
288  * macro BOUNDS_CHECK is set at compile time */
290  b.reserve(3);
291  for( int j=0; j < 3; j++ )
292  b.reserve(j,ARR_SIZE+j);
293  b.alloc();
294  if( p.nMatch("ITER") )
295  {
296  fprintf(ioQQQ," I will now access multi_arr array element *b.ptr(0,%ld)."
297  " Hold on.\n", i );
298  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
299  " there are problems.\n\n");
300  fflush(ioQQQ);
301  md2i p = b.ptr(0,i);
302  *p = 2.;
303  fprintf(ioQQQ," I am still alive - something is wrong, return value is %g\n", *p );
304  fflush(ioQQQ);
305  }
306  else
307  {
308  fprintf(ioQQQ," I will now access multi_arr array element b[0][%ld]. Hold on.\n", i );
309  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
310  " there are problems.\n\n");
311  fflush(ioQQQ);
312  b[0][i] = 2.;
313  fprintf(ioQQQ," I am still alive - something is wrong, return value is %g\n", b[0][i] );
314  fflush(ioQQQ);
315  }
316  b.clear();
317  }
318  else if( p.nMatch("AVXP") )
319  {
320  avx_ptr<int> ibound(ARR_SIZE);
321  fprintf(ioQQQ," I will now access avx_ptr element ibound[%ld]. Hold on.\n", i );
322  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
323  " there are problems.\n");
324  fflush(ioQQQ);
325  ibound[i] = 1;
326  fprintf(ioQQQ," I am still alive - something is wrong, return value is %i\n" , ibound[i] );
327  fflush(ioQQQ);
328  }
329  else
330  {
331  fprintf(ioQQQ," The CRASH BOUNDS command has five different tests. One must be specified\n" );
332  fprintf(ioQQQ," The HEAP option tests a malloc/'d array - this tests valgrind or purify.\n");
333  fprintf(ioQQQ," The STATIC option tests a static declared array, and the STACK or AUTO option"
334  " tests an automatic array - these test pgcc and g++.\n");
335  fprintf(ioQQQ," The VECTOR option tests the STL container vector - this tests g++.\n");
336  fprintf(ioQQQ," The MULTI option tests if bounds checking is enabled in the multi_arr class"
337  " (i.e., if the preprocessor macro BOUNDS_CHECK has been set).\n" );
338  fprintf(ioQQQ," The AVXPTR option tests if bounds checking is enabled in the avx_ptr class.\n");
339  fprintf(ioQQQ," All have a number as an optional argument, the array index to be accessed.\n");
340  fflush(ioQQQ);
341  }
342  lgCrash = true;
343  }
344 
345  /* test the isnan function */
346  else if( p.nMatch("ISNA") )
347  {
348  if( p.nMatch("FLOA") )
349  {
350  sys_float ff;
351  fprintf(ioQQQ," I will now set a float to SNaN. This should never crash!\n" );
352  set_NaN( ff );
353  fprintf(ioQQQ," I will now test this variable with the isnan function\n" );
354  fprintf(ioQQQ," The correct behavior is for the statement \"PROBLEM DISASTER An assert"
355  " has been thrown, this is bad\" to be printed, followed by lots more scary"
356  " looking messages.\n\n");
357  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
358  " there are problems.\n");
359  ASSERT( !isnan( ff ) );
360  fprintf(ioQQQ," I am still alive - something is wrong, value is %e\n", ff );
361  }
362  else
363  {
364  double dd;
365  fprintf(ioQQQ," I will now set a double to SNaN. This should never crash!\n" );
366  set_NaN( dd );
367  fprintf(ioQQQ," I will now test this variable with the isnan function\n" );
368  fprintf(ioQQQ," The correct behavior is for the statement \"PROBLEM DISASTER An assert"
369  " has been thrown, this is bad\" to be printed, followed by lots more scary"
370  " looking messages.\n\n");
371  fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then"
372  " there are problems.\n");
373  ASSERT( !isnan( dd ) );
374  fprintf(ioQQQ," I am still alive - something is wrong, value is %e\n", dd );
375  }
376  }
377 
378  /* test if a C++ exception is caught */
379  else if( p.nMatch("EXCE") )
380  {
381  fprintf(ioQQQ," I will now throw a C++ exception of type out_of_range()\n" );
382  fprintf(ioQQQ," The correct behavior is for the statement \"DISASTER - An out_of_range"
383  " exception was caught, what() = Cloudy Test. Bailing out...\" to be printed.\n\n");
384  fprintf(ioQQQ," If you get any other message, the exception was not caught correctly.\n\n");
385  throw out_of_range( "Cloudy Test" );
386  fprintf(ioQQQ," If you see this statement, the exception did not terminate the program.\n" );
387  }
388 
389  /* test if domain errors from vectorized math routines are caught correctly */
390  else if( p.nMatch("DOMA") )
391  {
392 #if __AVX__
393  double x1, x2, y[4];
394  x1 = numeric_limits<double>().infinity();
395  x2 = numeric_limits<double>().quiet_NaN();
396  fprintf(ioQQQ," I will now invoke vhypot() with invalid arguments.\n" );
397  fprintf(ioQQQ," The correct behavior is for the statement \"DISASTER - A vectorized math"
398  " routine threw a domain_error. Bailing out...\" to be printed.\n\n" );
399  fprintf(ioQQQ," If you get any other message, the exception was not caught correctly.\n\n");
400  vhypot(y,0.,0.,-1.,x1,3.,3.,x2,2.);
401  fprintf(ioQQQ," If you see this statement, the exception did not terminate the program.\n" );
402 #else
403  fprintf(ioQQQ," AVX vectorization is not enabled, skipping crash test...\n" );
404 #endif
405  }
406 
407  /* test if TotalInsanity is caught */
408  else if( p.nMatch("INSA") )
409  {
410  fprintf(ioQQQ,
411  " I will now call TotalInsanity(), which is used to report when an internal\n"
412  " inconsistency has been found & the code must exit.\n"
413  " The correct behavior is to print the following statement:\n\n"
414  " \"Something that cannot happen, has happened.\n"
415  " This is TotalInsanity, I live in service.cpp.\"\n\n"
416  " and exit reporting \"PROBLEM DISASTER\".\n"
417  " If the code continues, the TotalInsanity() function is broken.\n\n");
418  fprintf(ioQQQ," Calling TotalInsanity()...\n\n");
419  TotalInsanity();
420  fprintf(ioQQQ," If you see this statement, then TotalInsanity() did not terminate the program.\n" );
421  }
422 
423  else
424  {
425  fprintf(ioQQQ,
426  "Crash option not found - valid options are ZERO, UNDEfined, OVERflow, ASSErt,"
427  " _NAN, SETNan, BOUNds, ISNAn, EXCEption, DOMAin and INSAnity.\nSorry.\n");
428  lgCrash = true;
429  }
430 
431  if( lgCrash )
432  {
434  }
435 }
bool nMatch(const char *chKey) const
Definition: parser.h:150
static double x2[63]
double FFmtRead(void)
Definition: parser.cpp:472
NORETURN void TotalInsanity(void)
Definition: service.cpp:971
static double x1[83]
void set_NaN(sys_float &x)
Definition: cpu.cpp:906
void vhypot(const double x1[], const double x2[], double y[], long nlo, long nhi)
void ParseCrashDo(Parser &p)
iterator ptr(size_type i1, size_type i2)
bool MyIsnan(const sys_float &x)
Definition: cpu.cpp:977
FILE * ioQQQ
Definition: cddefines.cpp:7
Definition: parser.h:43
#define MALLOC(exp)
Definition: cddefines.h:554
const double ZeroNum
Definition: cdinit.cpp:13
#define EXIT_FAILURE
Definition: cddefines.h:168
float sys_float
Definition: cddefines.h:127
#define cdEXIT(FAIL)
Definition: cddefines.h:482
#define ASSERT(exp)
Definition: cddefines.h:613
void reserve(size_type i1)
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
#define isnan
Definition: cddefines.h:659
multi_arr< double, 2 >::iterator md2i
bool lgEOL(void) const
Definition: parser.h:113
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
static double ar2[ARR_SIZE]
const int ARR_SIZE