PIPS
array_bound_check_bottom_up.c
Go to the documentation of this file.
1 /*
2 
3  $Id: array_bound_check_bottom_up.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS 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 General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 /* -----------------------------------------------------------------
28  *
29  * BOTTOM-UP ARRAY BOUND CHECK VERSION
30  *
31  * -----------------------------------------------------------------
32  *
33  * This program takes as input the current module, adds array range checks
34  * (lower and upper bound checks) to every statement that has one or more
35  * array accesses. The output is the module with those tests added.
36 
37  * Assumptions : there is no write effect on the array bound expression.
38  *
39  * There was a test for write effect on bound here but I put it away (in
40  * effect_on_array_bound.c) because it takes time to calculate the effect
41  * but in fact this case is rare.
42  *
43  * NN 20/03/2002: Attention: tests generated for array whose bounds are modified are not correct
44  * See Validation/ArrayBoundCheck/BU_Effect.f
45 
46  * Solution : reput the test effect_on_array_bound, instrument the code with
47  * SUBROUTINE EFFECT(A,N)
48  * REAL A(N)
49  * N_PIPS = N
50  * N = 2*N
51  * DO I =1,N
52  * IF (I. GT. N_PIPS .OR I. LT> 1) STOP
53  * A(I) = I
54  * ENNDO
55  *
56  * Question : other analyses (regions,.. ) are correct ?
57  *
58  *
59  * Version: change the structure of test:
60  * IF (I.LT.lower) THEN STOP "Bound violation ..."
61  * IF (I.GT.upper) THEN STOP "Bound violation ..."
62  * Add statistics
63  * Version : Modify the Implied-DO process
64  */
65 
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include "genC.h"
70 #include "linear.h"
71 #include "ri.h"
72 #include "effects.h"
73 #include "alias_private.h"
74 #include "ri-util.h"
75 #include "prettyprint.h"
76 #include "effects-util.h"
77 #include "text-util.h"
78 #include "database.h"
79 #include "pipsdbm.h"
80 #include "resources.h"
81 #include "misc.h"
82 #include "control.h"
83 #include "properties.h"
84 #include "instrumentation.h"
85 
86 /* As we create checks with stop error message who tell us there are bound
87  * violations for which array, on which dimension, which bound (lower or upper),
88  * the following typedef array_dimension_bound_test permits us to create a
89  * sequence of tests for each statement more easier.
90  *
91  * The functions bottom_up_abc_call,
92  * bottom_up_abc_reference,
93  * bottom_up_abc_expression return results of type
94  * array_dimension_bound_test */
96 {
102 
103 /* Data structure to support abc Implied DO*/
104 typedef struct Index_range
105 {
109 
110 /* context data structure for bottom_up_abc newgen recursion */
111 typedef struct
112 {
115 }
118 
119 #define array_dimension_bound_test_undefined ((array_dimension_bound_test) {NIL,NIL,NIL,NIL} )
120 #define Index_range_undefined ((Index_range) {NIL,NIL})
121 
122 /* Statistic variables: */
123 
127 
129 {
133 }
134 
136 {
137  if (number_of_bound_checks > 0)
138  {
139  user_log("* There are %d array bound checks *\n",
141  }
142  if (number_of_added_checks > 0)
143  user_log("* There %s %d array bound check%s added *\n",
144  number_of_added_checks > 1 ? "are" : "is",
146  number_of_added_checks > 1 ? "s" : "");
147 
149  user_log("* There %s %d bound violation%s *\n",
150  number_of_bound_violations > 1 ? "are" : "is",
152  number_of_bound_violations > 1 ? "s" : "");
153 }
154 
156 {
157  if ((x.arr == NIL) && (x.dim == NIL) && (x.bou == NIL) && (x.exp == NIL))
158  return true;
159  return false;
160 }
161 
162 string int_to_dimension(int i)
163 {
164  switch(i)
165  {
166  case 0 :
167  return "wrt common size";
168  case 1 :
169  return "1st dimension";
170  case 2 :
171  return "2nd dimension";
172  case 3 :
173  return "3rd dimension";
174  case 4 :
175  return "4th dimension";
176  case 5 :
177  return "5th dimension";
178  case 6 :
179  return "6th dimension";
180  case 7 :
181  return "7th dimension";
182  default:
183  return "Over 7!!!";
184  }
185 }
186 
187 /* This function returns true, if the array needs bound checks
188  * false, otherwise.
189  *
190  * If the arrays are not created by user, for example the arrays
191  * of Logical Units : LUNS, END_LUNS, ERR_LUNS, ... in the
192  * IO_EFFECTS_PACKAGE_NAME, we don't have to check array references
193  * for those arrays.
194  * Maybe we have to add other kinds of arrays, not only those in _IO_EFFECTS_ */
195 
197 {
198  const char* s = entity_module_name(e);
199  if (strcmp(s,IO_EFFECTS_PACKAGE_NAME)==0)
200  return false;
201  return true;
202 }
203 
204 
207 {
210  retour.arr = CONS(ENTITY,e,NIL);
211  retour.dim = CONS(INT,i,NIL);
212  retour.bou = CONS(BOOL,low,NIL);
213  retour.exp = CONS(EXPRESSION,exp,NIL);
214  return retour;
215 }
216 
219 {
222  {
223  retour.arr = CONS(ENTITY,e,NIL);
224  retour.dim = CONS(INT,i,NIL);
225  retour.bou = CONS(BOOL,low,NIL);
226  retour.exp = CONS(EXPRESSION,exp,NIL);
227  }
228  return retour;
229 }
230 
234 {
236  {
238  {
239  pips_debug(3, "\n Add bound checks for array: %s",entity_local_name(ENTITY(CAR(temp.arr))));
240  return temp;
241  }
242  /* If in temp.exp, there are expressions that exist
243  in retour.exp, we don't have to add those expressions to retour.exp
244  If temp.exp is a true expression => add to list to debug several real bound violations*/
245  while (!ENDP(temp.exp))
246  {
247  expression exp = EXPRESSION(CAR(temp.exp));
248  pips_debug(3, "\n Add bound checks for array: %s",entity_local_name(ENTITY(CAR(temp.arr))));
250  {
251  retour.arr = gen_nconc(CONS(ENTITY,ENTITY(CAR(temp.arr)),NIL),retour.arr);
252  retour.dim = gen_nconc(CONS(INT,INT(CAR(temp.dim)),NIL),retour.dim);
253  retour.bou = gen_nconc(CONS(BOOL,BOOL(CAR(temp.bou)),NIL),retour.bou);
254  retour.exp = gen_nconc(CONS(EXPRESSION,exp,NIL),retour.exp);
255  }
256  else
258  temp.arr = CDR(temp.arr);
259  temp.dim = CDR(temp.dim);
260  temp.bou = CDR(temp.bou);
261  temp.exp = CDR(temp.exp);
262  }
263  }
264  return retour;
265 }
266 
267 /*****************************************************************************
268  This function computes the subscript value of an array element
269 
270  DIMENSION A(l1:u1,...,ln:un)
271  subscript_value(A(s1,s2,...,sn)) =
272  1+(s1-l1)+(s2-l2)*(u1-l1+1)+...+ (sn-ln)*(u1-l1+1)*...*(u(n-1) -l(n-1)+1)
273 
274 *****************************************************************************/
275 
277 {
278  expression retour = int_to_expression(1);
279  if (!ENDP(l_inds))
280  {
281  variable var = type_variable(entity_type(arr));
283  list l_dims = variable_dimensions(var);
284  int num_dim = gen_length(l_inds),i;
285  for (i=1; i<= num_dim; i++)
286  {
287  dimension dim_i = find_ith_dimension(l_dims,i);
288  expression lower_i = dimension_lower(dim_i);
289  expression sub_i = find_ith_argument(l_inds,i);
290  expression upper_i = dimension_upper(dim_i);
291  expression size_i;
292  if ( expression_constant_p(lower_i) && (expression_to_int(lower_i)==1))
293  size_i = copy_expression(upper_i);
294  else
295  {
296  size_i = binary_intrinsic_expression(MINUS_OPERATOR_NAME,upper_i,lower_i);
299  }
300  if (!same_expression_p(sub_i,lower_i))
301  {
303  sub_i,lower_i);
304  expression elem_i;
305  if (expression_undefined_p(prod))
306  elem_i = copy_expression(sub_low_i);
307  else
309  sub_low_i,prod);
311  retour, elem_i);
312  }
313  if (expression_undefined_p(prod))
314  prod = copy_expression(size_i);
315  else
317  prod,size_i);
318  }
319  }
320  ifdebug(4)
321  {
322  pips_debug(4,"\nSubscript value:");
323  print_expression(retour);
324  }
325  return retour;
326 }
327 
328 
332 
333 /* The test is: 1 <= offset(e) + subscript_value(r) <= area_size(common)*/
335 {
338  entity e = reference_variable(r);
339  list inds = reference_indices(r);
340  ram ra = storage_ram(entity_storage(e));
341  entity sec = ram_section(ra);
343  int off = ram_offset(ra)/SizeOfElements(b); /* divided by the element size */
344  int size = area_size(type_area(entity_type(sec)))/SizeOfElements(b); /* divided by the element size */
345  int i;
346  expression subval = subscript_value(e,inds);
348  ifdebug(3)
349  {
350  pips_debug(3, "\n Lower bound check expression:");
351  print_expression(check);
352  }
353  clean_all_normalized(check);
354  i = trivial_expression_p(check);
355  switch(i){
356  case 1:
357  {
358  user_log("\n Bound violation on lower bound of array %s\n",entity_local_name(e));
359  return make_true_array_dimension_bound_test(e,0,true);
360  }
361  case -1:
362  break;
363  case 0:
364  {
366  temp = make_array_dimension_bound_test(e,0,true,check);
367  retour = add_array_dimension_bound_test(retour,temp);
368  break;
369  }
370  }
371  check = gt_expression(copy_expression(subval),int_to_expression(size-off));
372  ifdebug(3)
373  {
374  pips_debug(3, "\n Upper bound check expression:");
375  print_expression(check);
376  }
377  clean_all_normalized(check);
378  i = trivial_expression_p(check);
379  switch(i){
380  case 1:
381  {
382  user_log("\n Bound violation on upper bound of array %s\n",entity_local_name(e));
383  return make_true_array_dimension_bound_test(e,0,false);
384  }
385  case -1:
386  break;
387  case 0:
388  {
390  temp = make_array_dimension_bound_test(e,0,false,check);
391  retour = add_array_dimension_bound_test(retour,temp);
392  break;
393  }
394  }
395  /*if the ith subscript index is also an array reference, we must check this reference*/
396  for (i=1;i <= (int) gen_length(inds);i++)
397  {
398  expression ith = find_ith_argument(inds,i);
400  temp = bottom_up_abc_expression(ith);
401  retour = add_array_dimension_bound_test(retour,temp);
402  }
403  return retour;
404 }
405 
406 
408 {
410  ifdebug(3)
411  {
412  pips_debug(3, "\n Array bound check for reference:");
413  print_reference(r);
414  }
415  if (array_reference_p(r))
416  {
417  entity e = reference_variable(r);
419  {
420  /* In practice, bound violations often occur with arrays in a common, with the reason that
421  the allocated size of the common is not violated :-)))
422  So this property helps dealing with this kind of bad programming practice*/
423  if (variable_in_common_p(e) && get_bool_property("ARRAY_BOUND_CHECKING_WITH_ALLOCATION_SIZE"))
424  retour = abc_with_allocation_size(r);
425  else
426  {
428  list arrayinds = reference_indices(r);
430  expression ith, check = expression_undefined;
431  int i,k;
433  for (i=1;i <= (int) gen_length(arrayinds);i++)
434  {
436  dimi = find_ith_dimension(arraydims,i);
437  ith = find_ith_argument(arrayinds,i);
439  /* Call the function trivial_expression_p(check)
440  * + If the check expression is always TRUE:
441  * there is certainly bound violation, we return retour
442  * immediately: retour = ({e},{i},{bound},{.TRUE.})
443  * + If the check expression is always false, we don't have to add check to retour.
444  * + Otherwise, we have to add check to retour.*/
445  ifdebug(3)
446  {
447  pips_debug(3, "\n Lower bound check expression:");
448  print_expression(check);
449  }
450  clean_all_normalized(check);
451  k = trivial_expression_p(check);
452  switch(k){
453  case 1:
454  {
455  user_log("\n Bound violation on lower bound of array %s\n",entity_local_name(e));
456  return make_true_array_dimension_bound_test(e,i,true);
457  }
458  case -1:
459  break;
460  case 0:
461  {
463  temp = make_array_dimension_bound_test(e,i,true,check);
464  retour = add_array_dimension_bound_test(retour,temp);
465  break;
466  }
467  }
468  /* If the dimension is unbounded , for example T(*), we cannot check the upper bound*/
469  if (!unbounded_dimension_p(dimi))
470  {
472  ifdebug(3)
473  {
474  pips_debug(3, "\n Upper bound check expression:");
475  print_expression(check);
476  }
477  clean_all_normalized(check);
478  k = trivial_expression_p(check);
479  switch(k){
480  case 1:
481  {
482  user_log("\n Bound violation on upper bound of array %s\n",entity_local_name(e));
483  return make_true_array_dimension_bound_test(e,i,false);
484  }
485  case -1:
486  break;
487  case 0:
488  {
490  temp = make_array_dimension_bound_test(e,i,false,check);
491  retour = add_array_dimension_bound_test(retour,temp);
492  break;
493  }
494  }
495  }
496  /*if the ith subscript index is also an array reference, we must check this reference*/
497  temp = bottom_up_abc_expression(ith);
498  retour = add_array_dimension_bound_test(retour,temp);
499  }
500  }
501  }
502  }
503  return retour;
504 }
505 
508  expression ind,
509  range ran)
510 {
512  entity ent = reference_variable(re);
513  list arrayinds = reference_indices(re);
515  expression low = range_lower(ran);
516  expression up = range_upper(ran);
518  int i;
519  for (i=1;i <= (int) gen_length(arrayinds);i++)
520  {
522  ith = find_ith_argument(arrayinds,i);
523  if (expression_equal_p(ith,ind))
524  {
525  int k;
526  dimension dimi = find_ith_dimension(listdims,i);
529  // make expression e1.LT.lower
530  check = lt_expression(low,dimension_lower(copy_dimension(dimi)));
531  ifdebug(3)
532  {
533  pips_debug(3,"\n Lower bound check expression:");
534  print_expression(check);
535  }
536  clean_all_normalized(check);
537  k = trivial_expression_p(check);
538  switch(k){
539  case 1:
540  {
541  user_log("\n Bound violation on lower bound of array %s\n",entity_local_name(ent));
542  return make_true_array_dimension_bound_test(ent,i,true);
543  }
544  case -1:
545  break;
546  case 0:
547  {
549  temp = make_array_dimension_bound_test(ent,i,true,check);
550  retour = add_array_dimension_bound_test(retour,temp);
551  break;
552  }
553  }
554  if (!unbounded_dimension_p(dimi))
555  {
556  check = gt_expression(up,dimension_upper(copy_dimension(dimi)));
557  ifdebug(3)
558  {
559  pips_debug(3, "Upper bound check expression:");
560  print_expression(check);
561  }
562  clean_all_normalized(check);
563  k = trivial_expression_p(check);
564  switch(k){
565  case 1:
566  {
567  user_log("\n Bound violation on upper bound of array %s\n",entity_local_name(ent));
568  return make_true_array_dimension_bound_test(ent,i,false);
569  }
570  case -1:
571  break;
572  case 0:
573  {
575  temp = make_array_dimension_bound_test(ent,i,false,check);
576  retour = add_array_dimension_bound_test(retour,temp);
577  break;
578  }
579  }
580  }
581  }
582  }
583  return retour;
584 }
585 
588 {
590  syntax s = expression_syntax(e);
591  tag t = syntax_tag(s);
592  switch (t){
593  case is_syntax_range:
594  break;
595  case is_syntax_call:
596  break;
597  case is_syntax_reference:
598  {
599  /* Treat array reference */
600  reference re = syntax_reference(s);
601  if (array_reference_p(re))
602  {
603  entity ent = reference_variable(re);
604  if (array_need_bound_check_p(ent))
605  {
606  /* For example, we have array reference A(I,J)
607  with two indexes I and J and ranges 1:20 and 1:10, respectively*/
608  list list_index = ir.ind, list_range = ir.ran;
609  while (!ENDP(list_index))
610  {
611  expression ind = EXPRESSION(CAR(list_index));
612  range ran = RANGE(CAR(list_range));
614  temp = bottom_up_abc_base_reference_implied_do(re,ind,ran);
615  retour = add_array_dimension_bound_test(retour,temp);
616  list_index = CDR(list_index);
617  list_range = CDR(list_range);
618  }
619  }
620  }
621  break;
622  }
623  }
624  return retour;
625 }
626 
628 
631 {
632  /* An implied-DO is a call to an intrinsic function named IMPLIED-DO;
633  * the first argument is the implied-DO variable (loop index)
634  * the second one is a range
635  * the remaining arguments are expressions to be written or references
636  * to be read or another implied-DO
637  * (dlist, i=e1,e2,e3)
638  *
639  * We treated only the case where e3=1 (or omitted), the bound tests is
640  * IF (e1.LT.lower.OR.e2.GT.upper) STOP Bound violation
641  * for statement READ *,(A(I),I=e1,e2)
642  *
643  * An Implied-DO can be occurred in a DATA statement or an input/output
644  * statement. As DATA statement is in the declaration, not executable,
645  * we do not need to pay attention to it.*/
648  expression arg2 = EXPRESSION(CAR(CDR(args))); /* range e1,e2,e3*/
650  expression one_exp = int_to_expression(1);
651  if (same_expression_p(range_increment(r),one_exp))
652  {
653  /* The increment is 1 */
654  expression arg1 = EXPRESSION(CAR(args)); /* Implied-DO index*/
655  args = CDR(CDR(args));
656  MAP(EXPRESSION, expr,
657  {
659  Index_range new_ir;
660  new_ir.ind = gen_nconc(CONS(EXPRESSION,arg1,NIL),ir.ind);
661  new_ir.ran = gen_nconc(CONS(RANGE,r,NIL),ir.ran);
662  if (expression_implied_do_p(expr))
663  temp = bottom_up_abc_expression_implied_do(expr,new_ir);
664  else
665  /* normal expression */
666  temp = bottom_up_abc_reference_implied_do(expr,new_ir);
667  retour = add_array_dimension_bound_test(retour,temp);
668  },args);
669  }
670  else
671  {
672  /* increment <> 1, we have to put a dynamic test function such as :
673  * WRITE *, A(checkA(I), e1,e2,e3)
674  * where checkA is a function that does the range checking for array A.
675  * because it is not integer, the bound tests :
676  *
677  * if (e3.GT.0).AND.(e1.LT.lower.OR.e1+e3x[e2-e1/e3].GT.upper)
678  * STOP Bound violation
679  * if (e3.LT.0).AND.(e1.GT.upper.OR.e1+e3x[e1-e2/e3].LT.lower)
680  * STOP Bound violation */
681  }
682  return retour;
683 }
684 
686 {
687  /* the syntax of an expression can be a reference, a range or a call*/
691  else
692  {
693  syntax s = expression_syntax(e);
694  tag t = syntax_tag(s);
695  switch (t){
696  case is_syntax_call:
697  {
698  retour = bottom_up_abc_call(syntax_call(s));
699  break;
700  }
701  case is_syntax_reference:
702  {
704  break;
705  }
706  case is_syntax_range:
707  /* There is nothing to check here*/
708  break;
709  }
710  }
711  return retour;
712 }
713 
715 {
716  MAP(EXPRESSION, exp,
717  {
719  tag t = syntax_tag(s);
720  switch (t){
721  case is_syntax_call:
722  {
723  /* We have to consider only the case of Implied DO
724  * if e is in the lower or upper bound of implied DO's range or not */
726  {
727  call c = syntax_call(s);
728  list cargs = call_arguments(c);
729  expression arg2 = EXPRESSION(CAR(CDR(cargs))); /* range e1,e2,e3*/
731  expression e1 = range_lower(r);
732  expression e2 = range_upper(r);
733  expression e3 = range_increment(r);
734  ifdebug(3)
735  {
736  fprintf(stderr,"\n Implied DO expression:\n");
738  }
739  if (same_expression_p(e,e1)||same_expression_p(e,e2)||same_expression_p(e,e3))
740  return true;
741  }
742  break;
743  }
744  case is_syntax_reference:
745  {
747  if (array_reference_p(ref))
748  {
749  list arrayinds = reference_indices(ref);
750  if (same_expression_in_list_p(e,arrayinds))
751  return true;
752  }
753  break;
754  }
755  case is_syntax_range:
756  break;
757  }
758  },args);
759  return false;
760 }
761 
763 {
764  entity func = call_function(c);
765  if (strcmp(entity_local_name(func),READ_FUNCTION_NAME)==0)
766  {
767  list args = call_arguments(c);
768  while (!ENDP(args))
769  {
770  expression exp = EXPRESSION(CAR(args));
771  args = CDR(args);
773  return true;
774  }
775  }
776  return false;
777 }
778 
780 {
781  list args = call_arguments(cal);
783  /* We must check a special case:
784  * The call is a READ statement with array reference whose index is
785  * read in the same statement.
786  *
787  * Example : READ *,N, A(N) or READ *,N,(A(I),I=1,N) (implied DO expression)
788  *
789  * In these case, we have to put a dynamic check function such as :
790  * READ *,N,(A(abc_check(I,1,10)),I=1,N),M
791  * where abc_check is a function that does the range checking by using its parameters */
792 
794  user_log("\n Warning : READ statement with write effect on array subscript. \n This case has not been treated yet :-( \n");
795  else
796  MAP(EXPRESSION, e,
797  {
799  retour = add_array_dimension_bound_test(retour,temp);
800  },args);
801  return retour;
802 }
803 
805 {
806  syntax s = expression_syntax(e);
807  tag t = syntax_tag(s);
808  string retour = "";
809  switch (t){
810  case is_syntax_range:
811  break;
812  case is_syntax_call:
813  {
814  call c = syntax_call(s);
815  list args = call_arguments(c);
817  {
818  retour = strdup(concatenate(retour,print_variables(exp),NULL));
819  },args);
820  break;
821  }
822  case is_syntax_reference:
823  {
825  retour = strdup(concatenate(retour,", \', ",reference_to_string(ref)," =\',",
826  reference_to_string(ref),NULL));
827  break;
828  }
829  default:
830  {
831  pips_internal_error("Unexpected expression tag %d ", t );
832  break;
833  }
834  }
835  return retour;
836 }
837 statement emit_message_and_stop(string stop_message)
838 {
840 
842  //return make_stop_statement(message);
843  smt = make_stop_statement(stop_message);
844  }
845  else {
846  /* Must be the C version */
847  smt = make_exit_statement(1, stop_message);
848  }
849  return smt;
850 }
851 
853 {
854  list la = adt.arr,ld = adt.dim,lb = adt.bou,le = adt.exp;
856  string string_delimiter =
858  "\'" : "\"";
859  while (!ENDP(la))
860  {
861  entity a = ENTITY(CAR(la));
862  int d = INT(CAR(ld));
863  bool b = BOOL(CAR(lb));
864  expression e = EXPRESSION(CAR(le));
865  string stop_message =
866  strdup(concatenate(string_delimiter,
867  "Bound violation: array \"",
868  entity_user_name(a),"\", ",
870  string_delimiter, NULL));
871  string print_message =
872  strdup(concatenate(string_delimiter,
873  "BV array \"",entity_user_name(a),"\", ",
874  int_to_dimension(d),bool_to_bound(b),"with ",
876  string_delimiter,
877  print_variables(e), NULL));
879  if (true_expression_p(e))
880  {
882  /* There is a bound violation, we can return a stop statement immediately,
883  but for debugging purpose, it is better to display all bound violations */
884  if (get_bool_property("PROGRAM_VERIFICATION_WITH_PRINT_MESSAGE"))
885  //return make_print_statement(message);
886  smt = make_any_print_statement(print_message);
887  else {
888  smt = emit_message_and_stop(stop_message);
889  }
890  }
891  else
892  {
893  if (get_bool_property("PROGRAM_VERIFICATION_WITH_PRINT_MESSAGE"))
894  smt = test_to_statement(make_test(e, make_print_statement(print_message),
896  else
897  smt = test_to_statement(make_test(e, emit_message_and_stop(stop_message),
899  }
900  if (statement_undefined_p(retour))
901  retour = copy_statement(smt);
902  else
903  // always structured case
904  insert_statement(retour,copy_statement(smt),false);
905  la = CDR(la);
906  ld = CDR(ld);
907  lb = CDR(lb);
908  le = CDR(le);
909  }
910  ifdebug(2)
911  {
912  pips_debug(2,"\n With array bound checks:");
913  print_statement(retour);
914  }
915  return retour;
916 }
917 
920 {
921  /* If s is in an unstructured instruction, we must pay attention
922  when inserting s1 before s. */
924  {
925  /* take the control that has s as its statement */
927  if (stack_size(context->uns)>0)
928  {
929  /* take the unstructured correspond to the control c */
931  control newc;
932  ifdebug(5)
933  {
934  pips_debug(5,"Unstructured case: \n");
935  print_statement(s);
936  }
937  /* for a consistent unstructured, a test must have 2 successors,
938  so if s1 is a test, we transform it into sequence in order
939  to avoid this constraint.
940  Then we create a new control for it, with the predecessors
941  are those of c and the only one successor is c.
942  The new predecessors of c are only the new control*/
943  if (statement_test_p(s1))
944  {
945  list seq = CONS(STATEMENT,s1,NIL);
947  make_sequence(seq)));
948  ifdebug(5)
949  {
950  pips_debug(5, "Unstructured case, insert a test:\n");
952  print_statement(s2);
953  }
954  newc = make_control(s2, control_predecessors(c), CONS(CONTROL, c, NIL));
955  }
956  else
958  // replace c by newc as successor of each predecessor of c
959  MAP(CONTROL, co,
960  {
961  MAPL(lc,
962  {
963  if (CONTROL(CAR(lc))==c) CONTROL_(CAR(lc)) = newc;
964  }, control_successors(co));
965  },control_predecessors(c));
967  /* if c is the entry node of the correspond unstructured u,
968  the newc will become the new entry node of u */
969  if (unstructured_entry(u)==c)
970  unstructured_entry(u) = newc;
971  }
972  else
973  // there is no unstructured (?)
974  insert_statement(s,s1,true);
975  }
976  else
977  // structured case
978  insert_statement(s,s1,true);
979 }
980 
981 /* forward declaration */
983 
985  statement s,
987 {
989  tag t = instruction_tag(i);
990  statement stmt2;
991 
992  ifdebug(2)
993  {
994  pips_debug(2, "\n Current statement");
995  print_statement(s);
996  }
997  switch(t)
998  {
999  case is_instruction_call:
1000  {
1001  call cal = instruction_call(i);
1003 
1004  if ((stmt2 = cstr_args_check(s)) != statement_undefined) {
1005  printf("Insertion d'un statement ---->\n");
1007  }
1008 
1009  adt = bottom_up_abc_call(cal);
1011  {
1014  }
1015  break;
1016  }
1018  {
1020  // array bound check of while loop condition
1024  {
1027  }
1028  break;
1029  }
1030  case is_instruction_test:
1031  {
1032  test it = instruction_test(i);
1033  // array bound check of the test condition
1034  expression e1 = test_condition(it);
1037  {
1040  }
1041  break;
1042  }
1044  case is_instruction_loop:
1045  // suppose that there are not array references in loop's range in norm
1047  // suppose that there are not array references in loop's range in norm
1049  /* because we use gen_recurse with statement domain,
1050  * we don't have to check unstructured instruction here*/
1051  break;
1052  default:
1053  pips_internal_error("Unexpected instruction tag %d ", t );
1054  break;
1055  }
1056 }
1057 
1059 {
1061  control_statement(c), c);
1062  return true;
1063 }
1064 
1066 {
1067  stack_push((char *) u, context->uns);
1068  return true;
1069 }
1070 
1072 {
1073  pips_assert("true", u==u && context==context);
1074  stack_pop(context->uns);
1075 }
1076 
1078 {
1082 
1087  NULL);
1088 
1090  stack_free(&context.uns);
1091 }
1092 
1094 {
1097  /* Begin the dynamic array bound checking phase.
1098  * Get the code from dbm (true resource) */
1102  debug_on("ARRAY_BOUND_CHECK_BOTTOM_UP_DEBUG_LEVEL");
1103  ifdebug(1)
1104  {
1105  debug(1, "Array bound check","Begin for %s\n", module_name);
1106  pips_assert("Statement is consistent ...", statement_consistent_p(module_statement));
1107  }
1111  /* Reorder the module, because the bound checks have been added */
1113  ifdebug(1)
1114  {
1115  pips_assert("Statement is consistent ...", statement_consistent_p(module_statement));
1116  debug(1, "array bound check","End for %s\n", module_name);
1117  }
1118  debug_off();
1123  return true;
1124 }
1125 
1126 /*
1127  * Insert checks for C string manipulation functions (str*).
1128  */
1129 
1130 #define cf_ge_expression(e1, e2) \
1131  ( 1 ? binary_intrinsic_expression(">=", e1, e2) : ge_expression(e1, e2) )
1132 
1133 #define cf_gt_expression(e1, e2) \
1134  ( 1 ? binary_intrinsic_expression(">", e1, e2) : gt_expression(e1, e2) )
1135 
1136 #define cf_lt_expression(e1, e2) \
1137  ( 1 ? binary_intrinsic_expression("<", e1, e2) : lt_expression(e1, e2) )
1138 
1139 #define cf_and_expression(e1, e2) \
1140  ( 1 ? binary_intrinsic_expression("&&", e1, e2) : and_expression(e1, e2) )
1141 
1142 #define cf_or_expression(e1, e2) \
1143  ( 1 ? binary_intrinsic_expression("||", e1, e2) : or_expression(e1, e2) )
1144 
1145 static expression
1147 {
1148  entity add_ent = gen_find_entity(name);
1149 
1150  return make_call_expression(add_ent,
1151  CONS(EXPRESSION, e1, CONS(EXPRESSION, e2, NIL)));
1152 }
1153 
1154 #define make_add_expression(e1, e2) make_bin_expression("TOP-LEVEL:+", e1, e2)
1155 #define make_sub_expression(e1, e2) make_bin_expression("TOP-LEVEL:-", e1, e2)
1156 #define make_mul_expression(e1, e2) make_bin_expression("TOP-LEVEL:*", e1, e2)
1157 
1158 static expression
1160 {
1161  entity strlen_ent;
1162 
1163  strlen_ent = FindOrCreateTopLevelEntity("strlen");
1164  return make_call_expression(strlen_ent, CONS(EXPRESSION, arg, NIL));
1165 }
1166 
1167 static statement
1168 make_c_stop_statement(int abort_program)
1169 {
1170  pips_assert("true", abort_program==abort_program);
1171  /*
1172  * XXX 'entity_intrinsic' not verified ...
1173  * Pourtant exit() et abort() sont dï¿œclarï¿œs ds bootstrap.c
1174  */
1175 #if 0
1176  list l = NIL;
1177  string stop_func;
1178 
1179  if (abort_program)
1180  stop_func = "TOP-LEVEL:abort";
1181  else
1182  stop_func = "TOP-LEVEL:exit";
1183 
1184  l = CONS(STATEMENT, make_call_statement(stop_func,
1186  entity_undefined, ""),
1187  l);
1188 
1189  /*
1190  if (get_bool_property("PROGRAM_VERIFICATION_WITH_PRINT_MESSAGE")) {
1191  l = CONS(STATEMENT, make_call_statement("TOP-LEVEL:printf",
1192  CONS(EXPRESSION, string_to_expression(), NIL)
1193  entity_undefined, ""),
1194  l);
1195  }
1196  */
1197 
1198  return make_block_statement(l);
1199 #endif
1200  return emit_message_and_stop("Buffer overflow!");
1201 }
1202 
1203 
1204 /*
1205  * entity_constant_string_size:
1206  *
1207  * If the given entity is representing a constant string, this
1208  * function will return it's length as a positive integer, else
1209  * -1 will be returned.
1210  */
1211 static int
1213 {
1214  basic b;
1215  type t, result;
1216  value v;
1217  constant c;
1218 
1219  t = entity_type(e);
1220  if (type_functional_p(t)
1222  && basic_string_p((b = variable_basic(type_variable(result))))
1223  && value_constant_p((v = basic_string(b)))
1224  && constant_int_p((c = value_constant(v))))
1225  return constant_int(c);
1226  return -1;
1227 }
1228 
1229 /*
1230  * entity_size_uname:
1231  *
1232  * Return a string usable as a unique global variable name for
1233  * the given entity.
1234  */
1235 static string
1237 {
1238  static const char prefix []= "PIPS_size_";
1239  string name = entity_name(e);
1240  string uname;
1241  int i, len = strlen(name);
1242 
1243  if ((uname = malloc(len + 1 + sizeof(prefix))) == NULL) {
1244  perror("malloc");
1245  exit(1);
1246  }
1247  sprintf(uname, "%s%s",prefix, name);
1248  len = strlen(uname);
1249  for (i = 0; i < len; i++) {
1250  if (uname[i] == ':' || uname[i] == '-') {
1251  uname[i] = '_';
1252  }
1253  }
1254  return uname;
1255 }
1256 
1257 /*
1258  * expression_try_find_size:
1259  *
1260  * Try to find the storage size available for the given expression.
1261  */
1262 static expression
1264 {
1265  syntax syn = expression_syntax(expr);
1266 
1267  /*
1268  * Case of a reference.
1269  *
1270  * Try to find the size of the corresponding buffer.
1271  */
1272  if (expression_reference_p(expr)) {
1275  int s;
1276 
1277  if (type_variable_p(entity_type(e))) {
1279  entity size_holder;
1280  string e_uname;
1281  list dims = variable_dimensions(var);
1282  list acc = reference_indices(ref);
1283 
1284  while (1) {
1285  if (ENDP(acc) && !ENDP(dims)) {
1286  /*
1287  * We found the upper bound of the given
1288  * expression, we need to add one to get the
1289  * size of the buffer
1290  */
1291  expression upper_bound =
1292  dimension_upper(DIMENSION(CAR(dims)));
1293 
1294  if (expression_constant_p(upper_bound)) {
1295  return int_to_expression(1
1296  + expression_to_int(upper_bound));
1297  } else
1298  return make_add_expression(upper_bound,
1299  int_to_expression(1));
1300  } else if (!ENDP(acc) && !ENDP(dims)) {
1301  acc = CDR(acc);
1302  dims = CDR(dims);
1303  }
1304  else
1305  break;
1306  }
1307  /*
1308  * The memory pointed by the variable was probably
1309  * allocated by malloc() (or a similar function).
1310  */
1311  e_uname = entity_size_uname(e);
1312  size_holder = FindOrCreateEntity("main",e_uname);
1313 
1314  free(e_uname);
1315  if (size_holder == entity_undefined)
1316  return expression_undefined;
1317  else
1318  return make_entity_expression(size_holder, NIL);
1319  }
1320  /* The expression is a string constant */
1321  else if ((s = entity_constant_string_size(e)) >= 0)
1322  return int_to_expression(s);
1323  }
1324 
1325  /*
1326  * The expression is a function call.
1327  *
1328  * Only two forms are acceptable here: base + x, or base - y.
1329  */
1330  else if (expression_call_p(expr)) {
1331  call cal = syntax_call(syn);
1332  entity fun = call_function(cal);
1333  string fun_name = entity_name(fun);
1334  list args = call_arguments(cal);
1335  expression base, base_size, x;
1336 
1337  if (strcmp(fun_name, "TOP-LEVEL:+C") == 0) {
1338  base = EXPRESSION(CAR(args));
1339  x = EXPRESSION(CAR(CDR(args)));
1340  base_size = expression_try_find_size(base);
1341  if (base_size == expression_undefined)
1342  return expression_undefined;
1343  else
1344  return make_sub_expression(base_size, x);
1345  } else // XXX traiter le cas de fonctions imbriquï¿œes !
1346  return expression_undefined;
1347  }
1348 
1349  return expression_undefined;
1350 }
1351 
1352 /*
1353  * expression_try_find_string_size:
1354  *
1355  * Try to find the size of the string pointed by the given
1356  * expression. The function will return an expression holding
1357  * the length of the string in the case of a constant string or
1358  * a call to the strlen() function in the other cases.
1359  *
1360  * The size returned does not include the trailing NUL
1361  * character.
1362  */
1363 static expression
1365 {
1366  entity e;
1367  int s;
1368 
1370  if (e != entity_undefined && (s = entity_constant_string_size(e)) >= 0)
1371  return int_to_expression(s);
1372  else
1373  return make_strlen_expression(expr);
1374 }
1375 
1376 static expression
1378 {
1379  reference ref;
1380  entity e;
1381  variable var;
1382  list dims, acc;
1383  expression check = expression_undefined, checktmp, indice;
1384 
1385  if (!expression_reference_p(expr))
1386  return expression_undefined;
1387  else {
1389  e = reference_variable(ref);
1390  if (!type_variable_p(entity_type(e)))
1391  return expression_undefined;
1392  }
1393  var = type_variable(entity_type(e));
1394  dims = variable_dimensions(var);
1395  acc = reference_indices(ref);
1396 
1397  while (1) {
1398  if (!ENDP(acc) && !ENDP(dims)) {
1399  /*
1400  * We found the upper bound of the given
1401  * expression, we need to add one to get the
1402  * size of the buffer
1403  */
1404  expression upper_bound =
1405  dimension_upper(DIMENSION(CAR(dims)));
1406 
1407  if (expression_constant_p(upper_bound)) {
1408  upper_bound = int_to_expression(1
1409  + expression_to_int(upper_bound));
1410  } else
1411  upper_bound = make_add_expression(upper_bound,
1412  int_to_expression(1));
1413 
1414  /*
1415  * Create the check for the current dimension (checktmp):
1416  * indice < upper_bound
1417  * Add it to the global check:
1418  * check := check && checktmp
1419  */
1420  indice = EXPRESSION(CAR(acc));
1421  checktmp = cf_lt_expression(indice, upper_bound);
1422  if (check == expression_undefined)
1423  check = checktmp;
1424  else
1425  check = cf_and_expression(check, checktmp);
1426 
1427  acc = CDR(acc);
1428  dims = CDR(dims);
1429  } else
1430  break;
1431  }
1432  return check;
1433 }
1434 
1435 static expression
1437 {
1438  expression check;
1439 
1440  if ((check = array_indices_check(array_expr)) == expression_undefined)
1441  return expr;
1442  else
1443  return cf_and_expression(check, expr);
1444 }
1445 
1446 #define CHECK_NARGS(n) if (nargs != (n)) return expression_undefined
1447 
1448 /*
1449  * Check for memcpy(dst, src, n):
1450  *
1451  * n > size(src) || n > size(dst)
1452  */
1453 static expression
1455 {
1456  expression arg0_size_expr, arg1_size_expr;
1457  CHECK_NARGS(3);
1458 
1459  arg0_size_expr = expression_try_find_size(args[0]);
1460  arg1_size_expr = expression_try_find_size(args[1]);
1461  if (arg0_size_expr == expression_undefined
1462  || arg1_size_expr == expression_undefined)
1463  return expression_undefined;
1464 
1465  return cf_or_expression(
1466  cf_gt_expression(args[2], arg1_size_expr),
1467  cf_gt_expression(args[2], arg0_size_expr));
1468 }
1469 
1470 /*
1471  * Check for bcopy(src, dst, n):
1472  *
1473  * n > size(src) || n > size(dst) => same as memcpy()
1474  */
1475 static expression
1477 {
1478  CHECK_NARGS(3);
1479  // The arguments order (for the two first) doesn't matter
1480  return memcpy_check_expression(args, nargs);
1481 }
1482 
1483 /*
1484  * Check for bcmp(b1, b2, n):
1485  *
1486  * n > size(b1) || n > size(b2) => same as memcpy()
1487  */
1488 static expression
1490 {
1491  CHECK_NARGS(3);
1492  return memcpy_check_expression(args, nargs);
1493 }
1494 
1495 /*
1496  * Check for bzero(dst, n):
1497  *
1498  * n > size(dst)
1499  */
1500 static expression
1502 {
1503  expression arg0_size_expr;
1504 
1505  CHECK_NARGS(2);
1506 
1507  arg0_size_expr = expression_try_find_size(args[0]);
1508  if (arg0_size_expr == expression_undefined)
1509  return expression_undefined;
1510 
1511  return cf_gt_expression(args[1], arg0_size_expr);
1512 }
1513 
1514 /*
1515  * Check for memcmp(b1, b2, n):
1516  *
1517  * n > size(b1) || n > size(b2) => same as memcpy()
1518  */
1519 static expression
1521 {
1522  CHECK_NARGS(3);
1523  return memcpy_check_expression(args, nargs);
1524 }
1525 
1526 /*
1527  * Check for memmove(dst, src, n):
1528  *
1529  * n > size(src) || n > size(dst) || abs(dst - src) < n
1530  * => same as bcopy(src, dst, n)
1531  */
1532 static expression
1534 {
1535  expression tmp;
1536  CHECK_NARGS(3);
1537 
1538  /* Convert memmove(dst, src, n) -> bcopy(src, dest, n) */
1539  tmp = args[0];
1540  args[0] = args[1];
1541  args[1] = tmp;
1542  return bcopy_check_expression(args, nargs);
1543 }
1544 
1545 /*
1546  * Check for memset(dst, val, n):
1547  *
1548  * n > size(dst) => same as bzero().
1549  */
1550 static expression
1552 {
1553  CHECK_NARGS(3);
1554 
1555  /* Convert memset(dst, b, n) -> bzero(dst, n) */
1556  args[1] = args[2];
1557  return bzero_check_expression(args, 2);
1558 }
1559 
1560 /*
1561  * Check for strcpy(dst, src):
1562  *
1563  * strlen(src) >= size(dst)
1564  */
1565 static expression
1567 {
1568  //statement smt;
1569  expression arg1_size_expr ;
1570 
1571  CHECK_NARGS(2);
1572 
1573  arg1_size_expr = expression_try_find_size(args[0]);
1574  if (arg1_size_expr == expression_undefined)
1575  return expression_undefined;
1576  /*
1577  expression arg2_size_expr;
1578  int arg2size;
1579  entity arg2ent;
1580  arg2ent = reference_variable(expression_reference(args[1]));
1581 
1582  if ((arg2size = entity_constant_string_size(arg2ent)) >= 0)
1583  arg2_size_expr = int_to_expression(arg2size);
1584  else
1585  arg2_size_expr = make_strlen_expression(args[1]);
1586  */
1587 
1588  return cf_ge_expression(expression_try_find_string_size(args[1]), arg1_size_expr);
1589 }
1590 
1591 /*
1592  * Check for strncpy(dst, src, n):
1593  *
1594  * n >= size(dst)
1595  */
1596 static expression
1598 {
1599  expression arg1_size_expr;
1600 
1601  CHECK_NARGS(3);
1602 
1603  arg1_size_expr = expression_try_find_size(args[0]);
1604  if (arg1_size_expr == expression_undefined)
1605  return expression_undefined;
1606 
1607  return cf_ge_expression(args[2], arg1_size_expr);
1608 }
1609 
1610 /*
1611  * Check for strcat(dst, src):
1612  *
1613  * strlen(dst) + strlen(src) >= size(dst)
1614  */
1615 static expression
1617 {
1618  expression dst_size;
1619 
1620  CHECK_NARGS(2);
1621 
1622  dst_size = expression_try_find_size(args[0]);
1623  if (dst_size == expression_undefined)
1624  return expression_undefined;
1625 
1626  return cf_ge_expression(
1629  dst_size);
1630 }
1631 
1632 /*
1633  * Check for strncat(dst, src, n):
1634  *
1635  * n >= size(dst) - strlen(dst)
1636  */
1637 static expression
1639 {
1640  expression dst_size;
1641 
1642  CHECK_NARGS(3);
1643 
1644  dst_size = expression_try_find_size(args[0]);
1645  if (dst_size == expression_undefined)
1646  return expression_undefined;
1647  return cf_ge_expression(args[2], make_sub_expression(dst_size,
1649 }
1650 
1651 /*
1652  * Check for sprintf(dst, fmt, ...):
1653  *
1654  * snprintf(PIPS_tmpbuf, 1, fmt, ...) > size(dst)
1655  *
1656  * (snprintf return the size that would have been written in the
1657  * case of an infinite buffer).
1658  */
1659 static expression
1661 {
1662  int k;
1663  list snprintf_args = NIL;
1664  expression dst_size=expression_undefined, tmpbuf_expr;
1665  entity snprintf_ent, tmpbuf_ent;
1666 
1667  if (nargs < 2)
1668  return expression_undefined;
1669 
1670  if ((snprintf_ent = FindEntity(TOP_LEVEL_MODULE_NAME,"snprintf"))
1671  == entity_undefined)
1672  return expression_undefined;
1673 
1674  if ((tmpbuf_ent = FindEntity("main","PIPS_tmpbuf")) == entity_undefined)
1675  // XXX module "main" non correct
1676  tmpbuf_ent = make_scalar_entity("PIPS_tmpbuf", "main",
1677  make_basic_int(1));
1678  // XXX Il faut &PIPS_tmpbuf
1679  tmpbuf_expr = make_entity_expression(tmpbuf_ent, NIL);
1680 
1681  for (k = nargs - 1; k >= 2; k--)
1682  snprintf_args = CONS(EXPRESSION, args[k], snprintf_args);
1683  snprintf_args = CONS(EXPRESSION, tmpbuf_expr,
1684  CONS(EXPRESSION, int_to_expression(1), snprintf_args));
1685 
1686  return cf_gt_expression(make_call_expression(snprintf_ent, snprintf_args),
1687  dst_size);
1688 }
1689 
1690 /*
1691  * Check for snprintf(dst, n, fmt, ...):
1692  *
1693  * n >= size(dst) => same as strncpy(dst, src, n)
1694  */
1695 static expression
1697 {
1698  if (nargs < 3)
1699  return expression_undefined;
1700  args[2] = args[1];
1701 
1702  return strncpy_check_expression(args, 3);
1703 }
1704 
1705 #undef CHECK_NARGS
1706 
1707 static struct checkfn {
1708  string function;
1710 } checkfns[] = {
1711  { "bcopy", bcopy_check_expression },
1712  { "bcmp", bcmp_check_expression },
1713  { "bzero", bzero_check_expression },
1714  { "memcmp", memcmp_check_expression },
1715  { "memcpy", memcpy_check_expression },
1716  { "memmove", memmove_check_expression },
1717  { "memset", memset_check_expression },
1718  { "strcpy", strcpy_check_expression },
1719  { "strncpy", strncpy_check_expression },
1720  { "strcat", strcat_check_expression },
1721  { "strncat", strncat_check_expression },
1722  { "sprintf", sprintf_check_expression },
1723  { "snprintf", snprintf_check_expression },
1724  { NULL, NULL }
1725 };
1726 
1727 /*
1728  * Add instrumentation to memory allocation instructions:
1729  *
1730  * m = malloc(n); => m = malloc(n);
1731  * PIPS_size_m = n;
1732  *
1733  * The relevant functions are:
1734  * malloc(), calloc(), memalign(), realloc()
1735  */
1736 static statement
1738 {
1739  expression size_expr, size_holder;
1740  entity ptr, size_holder_ent;
1741  string func_name, size_holder_name;
1742  call func_call;
1743  list func_args;
1744  reference ref;
1745  int func_nargs;
1746 
1747  if (nargs != 2) {
1748  return statement_undefined;
1749  }
1750 
1751  if (!expression_reference_p(args[0]) || !expression_call_p(args[1]))
1752  return statement_undefined;
1753 
1755  ptr = reference_variable(ref);
1756 
1757  /*
1758  * Don't try to instrument if the pointer is an array access.
1759  */
1760  if (reference_indices(ref) != NIL)
1761  return statement_undefined;
1762 
1763  func_call = syntax_call(expression_syntax(args[1]));
1764  func_name = entity_name(call_function(func_call));
1765  func_args = call_arguments(func_call);
1766  func_nargs = gen_length(func_args);
1767 
1768  if (strcmp(func_name, "TOP-LEVEL:malloc") == 0) {
1769  if (func_nargs != 1)
1770  return statement_undefined;
1771  size_expr = EXPRESSION(CAR(func_args));
1772  } else if (strcmp(func_name, "TOP-LEVEL:realloc") == 0
1773  || strcmp(func_name, "TOP-LEVEL:memalign") == 0) {
1774  if (func_nargs != 2)
1775  return statement_undefined;
1776  size_expr = EXPRESSION(CAR(CDR(func_args)));
1777  } else if (strcmp(func_name, "TOP-LEVEL:calloc") == 0) {
1778  if (func_nargs != 2)
1779  return statement_undefined;
1781  func_args);
1782  } else
1783  return statement_undefined;
1784 
1785  /*
1786  * Create a new variable to hold the size of the allocated
1787  * memory.
1788  */
1789  size_holder_name = entity_size_uname(ptr);
1790  size_holder_ent = FindEntity("main",
1791  size_holder_name);
1792  if (size_holder_ent == entity_undefined) {
1793  size_holder_ent =
1794  make_scalar_entity(size_holder_name,
1795  // XXX ?? marche pas ...
1796  //STATIC_AREA_LOCAL_NAME, make_basic_int(4));
1797  "main", make_basic_int(4));
1798  }
1799  size_holder = make_entity_expression(size_holder_ent, NIL);
1800 
1801  return make_assign_statement(size_holder, size_expr);
1802 }
1803 
1804 static statement
1806 {
1808  statement astmt;
1809  expression expr, *argstab;
1810  call cal;
1811  list args;
1812  string func_name;
1813  int nargs = 0, k;
1814  struct checkfn *p;
1815 
1816  pips_assert("Statement is a call statmt.",
1818 
1819  cal = instruction_call(i);
1820  func_name = entity_name(call_function(cal));
1821  pips_debug(1, "FONCTION: %s\n", func_name);
1822 
1823  /* Convert the arguments list into an array */
1824  args = call_arguments(cal);
1825  nargs = gen_length(args);
1826  argstab = malloc(sizeof(expression) * nargs);
1827  for (k = 0; k < nargs; k++) {
1828  argstab[k] = EXPRESSION(CAR(args));
1829  args = CDR(args);
1830  }
1831 
1832  /* Add malloc(), free(), etc. instrumentation */
1833  if (strcmp(func_name, "TOP-LEVEL:=") == 0
1834  && (astmt = alloc_instrumentation(argstab, nargs)) != statement_undefined) {
1835  free(argstab);
1836  return astmt;
1837  /*
1838  * free(m); => PIPS_size_m = 0;
1839  * free(m);
1840  */
1841  } else if (strcmp(func_name, "TOP-LEVEL:free") == 0) {
1842  entity arg_ent, size_holder;
1843  string e_uname;
1844 
1845  free(argstab);
1846 
1847  if (!expression_reference_p(argstab[0]))
1848  return statement_undefined;
1849  else {
1851  expression_syntax(argstab[0])));
1852  if (!type_variable_p(entity_type(arg_ent)))
1853  return statement_undefined;
1854  }
1855  e_uname = entity_size_uname(arg_ent);
1856  size_holder = FindEntity("main", e_uname);
1857  free(e_uname);
1858  if (size_holder == entity_undefined)
1859  return statement_undefined;
1860  return make_assign_statement(make_entity_expression(size_holder, NIL),
1861  int_to_expression(0));
1862  }
1863 
1864  if (strncmp(func_name, "TOP-LEVEL:", 10) != 0) {
1865  free(argstab);
1866  return statement_undefined;
1867  }
1868 
1869  expr = expression_undefined;
1870  for (p = checkfns; p->function != NULL; p++) {
1871  if (strcmp(p->function, func_name + 10) == 0) {
1872  expr = (p->check_statement)(argstab, nargs);
1873  break;
1874  }
1875  }
1876 
1877  free(argstab);
1878 
1879  if (expr == expression_undefined) {
1880  /* The target languague is unknown: C or Fortran, NL at the
1881  end or not? It will be up to the prettyprinter (FI).
1882  FI+LD 21-Oct-2009 : added NL, apparently needed in Fortran too.
1883  */
1884  put_a_comment_on_a_statement(s, strdup("CHECK WAS NOT CREATED\n"));
1885  return statement_undefined;
1886  }
1887 
1888  /*
1889  * Add checks for array indices when necessary.
1890  */
1891  for (k = 0; k < nargs; k++)
1892  expr = array_check_add(argstab[k], expr);
1893  return test_to_statement(make_test(expr,
1896 }
1897 
void user_log(const char *format,...)
Definition: message.c:234
persistant_statement_to_control make_persistant_statement_to_control(void)
Definition: ri.c:1594
entity gen_find_entity(char *s)
Definition: ri.c:2551
basic make_basic_int(intptr_t _field_)
Definition: ri.c:158
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
statement copy_statement(statement p)
STATEMENT.
Definition: ri.c:2186
bool statement_consistent_p(statement p)
Definition: ri.c:2195
test make_test(expression a1, statement a2, statement a3)
Definition: ri.c:2607
dimension copy_dimension(dimension p)
DIMENSION.
Definition: ri.c:529
control apply_persistant_statement_to_control(persistant_statement_to_control f, statement k)
Definition: ri.c:1597
instruction make_instruction(enum instruction_utype tag, void *val)
Definition: ri.c:1166
bool bound_persistant_statement_to_control_p(persistant_statement_to_control f, statement k)
Definition: ri.c:1609
sequence make_sequence(list a)
Definition: ri.c:2125
control make_control(statement a1, list a2, list a3)
Definition: ri.c:523
void extend_persistant_statement_to_control(persistant_statement_to_control f, statement k, control v)
Definition: ri.c:1603
void free_persistant_statement_to_control(persistant_statement_to_control p)
Definition: ri.c:1561
static reference ref
Current stmt (an integer)
Definition: adg_read_paf.c:163
static statement module_statement
Definition: alias_check.c:125
struct _newgen_struct_expression_ * expression
Definition: alias_private.h:21
void const char const char const int
static expression expression_try_find_size(expression expr)
static expression sprintf_check_expression(expression args[], int nargs)
expression subscript_value(entity arr, list l_inds)
static expression bcmp_check_expression(expression args[], int nargs)
static bool push_uns(unstructured u, bottom_up_abc_context_p context)
static expression snprintf_check_expression(expression args[], int nargs)
struct bottom_up_abc_context_t * bottom_up_abc_context_p
static int entity_constant_string_size(entity e)
bool array_bound_check_bottom_up(const char *module_name)
static expression make_bin_expression(string name, expression e1, expression e2)
static array_dimension_bound_test make_array_dimension_bound_test(entity e, int i, bool low, expression exp)
static statement alloc_instrumentation(expression args[], int nargs)
static expression memcmp_check_expression(expression args[], int nargs)
#define Index_range_undefined
#define cf_or_expression(e1, e2)
static expression array_check_add(expression array_expr, expression expr)
static array_dimension_bound_test make_true_array_dimension_bound_test(entity e, int i, bool low)
static array_dimension_bound_test add_array_dimension_bound_test(array_dimension_bound_test retour, array_dimension_bound_test temp)
static bool expression_in_array_subscript(expression e, list args)
static statement make_bottom_up_abc_tests(array_dimension_bound_test adt)
static array_dimension_bound_test bottom_up_abc_base_reference_implied_do(reference re, expression ind, range ran)
#define cf_and_expression(e1, e2)
static bool store_mapping(control c, bottom_up_abc_context_p context)
static expression make_strlen_expression(expression arg)
static statement make_c_stop_statement(int abort_program)
#define make_sub_expression(e1, e2)
static array_dimension_bound_test bottom_up_abc_expression_implied_do(expression e, Index_range ir)
static array_dimension_bound_test bottom_up_abc_expression(expression e)
static array_dimension_bound_test abc_with_allocation_size(reference r)
The test is: 1 <= offset(e) + subscript_value(r) <= area_size(common)
static expression strncat_check_expression(expression args[], int nargs)
static int number_of_added_checks
static expression expression_try_find_string_size(expression expr)
static int number_of_bound_checks
Statistic variables:
static expression array_indices_check(expression expr)
struct Index_range Index_range
Data structure to support abc Implied DO.
static array_dimension_bound_test bottom_up_abc_reference_implied_do(expression e, Index_range ir)
static array_dimension_bound_test bottom_up_abc_reference(reference r)
statement emit_message_and_stop(string stop_message)
static bool read_statement_with_write_effect_on_array_subscript(call c)
static bool array_dimension_bound_test_undefined_p(array_dimension_bound_test x)
static struct checkfn checkfns[]
#define array_dimension_bound_test_undefined
static array_dimension_bound_test bottom_up_abc_call(call cal)
static void bottom_up_abc_statement_rwt(statement s, bottom_up_abc_context_p context)
static void initialize_bottom_up_abc_statistics()
static int number_of_bound_violations
static expression memmove_check_expression(expression args[], int nargs)
bool array_need_bound_check_p(entity e)
This function returns true, if the array needs bound checks false, otherwise.
#define cf_lt_expression(e1, e2)
static void bottom_up_abc_insert_before_statement(statement s, statement s1, bottom_up_abc_context_p context)
#define cf_ge_expression(e1, e2)
#define make_add_expression(e1, e2)
static statement cstr_args_check(statement)
forward declaration
static expression memcpy_check_expression(expression args[], int nargs)
#define cf_gt_expression(e1, e2)
static expression bcopy_check_expression(expression args[], int nargs)
static void display_bottom_up_abc_statistics()
#define CHECK_NARGS(n)
static void pop_uns(unstructured u, bottom_up_abc_context_p context)
static expression strncpy_check_expression(expression args[], int nargs)
static expression strcpy_check_expression(expression args[], int nargs)
string print_variables(expression e)
static expression bzero_check_expression(expression args[], int nargs)
static void bottom_up_abc_statement(statement module_statement)
static expression memset_check_expression(expression args[], int nargs)
string int_to_dimension(int i)
Warning! Do not modify this file that is automatically generated!
struct array_dimension_bound_test array_dimension_bound_test
As we create checks with stop error message who tell us there are bound violations for which array,...
static string entity_size_uname(entity e)
static expression strcat_check_expression(expression args[], int nargs)
string bool_to_bound(bool b)
array_bound_check_top_down.c
@ INT
Definition: atomic.c:48
bdt base
Current expression.
Definition: bdt_read_paf.c:100
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define BOOL(x)
Definition: genC.h:83
void * malloc(YYSIZE_T)
void free(void *)
statement make_block_statement(list)
Make a block statement from a list of statement.
Definition: statement.c:616
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
#define MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
#define MAP(_map_CASTER, _map_item, _map_code, _map_list)
Apply/map an instruction block on all the elements of a list (old fashioned)
Definition: newgen_list.h:226
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
bool statement_test_p(statement)
Definition: statement.c:343
statement make_any_print_statement(string)
Generate a print of a constant character string on stderr for C or on stdout for Fortran.
Definition: statement.c:893
statement make_assign_statement(expression, expression)
Definition: statement.c:583
void put_a_comment_on_a_statement(statement, string)
Similar to try_to_put_a_comment_on_a_statement() but insert a CONTINUE to put the comment on it if th...
Definition: statement.c:1863
statement make_print_statement(string)
Make a Fortran print statement.
Definition: statement.c:835
statement make_stop_statement(string)
This function returns a Fortran stop statement with an error message.
Definition: statement.c:908
statement make_call_statement(string, list, entity, string)
This function is limited to intrinsics calls...
Definition: statement.c:1274
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
statement make_exit_statement(int, string)
This function returns a statement ending with a C exit statement.
Definition: statement.c:926
bool expression_constant_p(expression)
HPFC module by Fabien COELHO.
Definition: expression.c:2453
#define debug_on(env)
Definition: misc-local.h:157
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
#define exit(code)
Definition: misc-local.h:54
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
#define TOP_LEVEL_MODULE_NAME
Module containing the global variables in Fortran and C.
Definition: naming-local.h:101
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
void * stack_head(const stack)
returns the item on top of stack s
Definition: stack.c:420
int stack_size(const stack)
observers
void stack_push(void *, stack)
stack use
Definition: stack.c:373
void stack_free(stack *)
type, bucket_size, policy
Definition: stack.c:292
stack stack_make(int, int, int)
allocation
Definition: stack.c:246
void * stack_pop(stack)
POPs one item from stack s.
Definition: stack.c:399
int tag
TAG.
Definition: newgen_types.h:92
hash_table set_ordering_to_statement(statement s)
To be used instead of initialize_ordering_to_statement() to make sure that the hash table ots is in s...
Definition: ordering.c:172
void reset_ordering_to_statement(void)
Reset the mapping from ordering to statement.
Definition: ordering.c:185
string reference_to_string(reference r)
Definition: expression.c:87
void print_expression(expression e)
no file descriptor is passed to make is easier to use in a debugging stage.
Definition: expression.c:58
string expression_to_string(expression e)
Definition: expression.c:77
void print_reference(reference r)
Definition: expression.c:142
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
static const char * prefix
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define READ_FUNCTION_NAME
#define IO_EFFECTS_PACKAGE_NAME
Implicit variables to handle IO effetcs.
#define MINUS_OPERATOR_NAME
#define PLUS_OPERATOR_NAME
#define gt_expression(e1, e2)
#define test_to_statement(t)
#define binary_intrinsic_expression(name, e1, e2)
#define MULTIPLY_OPERATOR_NAME
#define lt_expression(e1, e2)
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
entity FindEntity(const char *package, const char *name)
Retrieve an entity from its package/module name and its local name.
Definition: entity.c:1503
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
entity FindOrCreateEntity(const char *package, const char *local_name)
Problem: A functional global entity may be referenced without parenthesis or CALL keyword in a functi...
Definition: entity.c:1586
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
entity FindOrCreateTopLevelEntity(const char *name)
Return a top-level entity.
Definition: entity.c:1603
bool fortran_module_p(entity m)
Test if a module is in Fortran.
Definition: entity.c:2799
const char * entity_module_name(entity e)
See comments about module_name().
Definition: entity.c:1092
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
expression make_entity_expression(entity e, cons *inds)
Definition: expression.c:176
void clean_all_normalized(expression e)
Definition: expression.c:4102
bool same_expression_in_list_p(expression e, list le)
This function returns true, if there exists a same expression in the list false, otherwise.
Definition: expression.c:557
bool expression_call_p(expression e)
Definition: expression.c:415
int expression_to_int(expression exp)
================================================================
Definition: expression.c:2205
int trivial_expression_p(expression e)
This function returns:
Definition: expression.c:679
bool true_expression_p(expression e)
Definition: expression.c:1113
expression make_call_expression(entity e, list l)
Build an expression that call an function entity with an argument list.
Definition: expression.c:321
bool expression_equal_p(expression e1, expression e2)
Syntactic equality e1==e2.
Definition: expression.c:1347
expression int_to_expression(_int i)
transform an int into an expression and generate the corresponding entity if necessary; it is not cle...
Definition: expression.c:1188
expression find_ith_argument(list args, int n)
Definition: expression.c:1147
bool unbounded_dimension_p(dimension dim)
bool unbounded_dimension_p(dim) input : a dimension of an array entity.
Definition: expression.c:1130
bool array_reference_p(reference r)
predicates on references
Definition: expression.c:1861
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
reference expression_reference(expression e)
Short cut, meaningful only if expression_reference_p(e) holds.
Definition: expression.c:1832
bool expression_implied_do_p(e)
Definition: expression.c:817
bool same_expression_p(expression e1, expression e2)
this is slightly different from expression_equal_p, as it will return true for a+b vs b+a
Definition: expression.c:1426
expression make_true_expression()
Definition: expression.c:1103
dimension find_ith_dimension(list, int)
This function returns the ith dimension of a list of dimensions.
Definition: type.c:5621
entity make_scalar_entity(const char *, const char *, basic)
entity make_scalar_entity(name, module_name, base)
Definition: variable.c:331
bool variable_in_common_p(entity)
true if v is in a common.
Definition: variable.c:1570
_int SizeOfElements(basic)
This function returns the length in bytes of the Fortran or C type represented by a basic,...
Definition: size.c:297
#define type_functional_p(x)
Definition: ri.h:2950
#define functional_result(x)
Definition: ri.h:1444
#define unstructured_domain
newgen_type_domain_defined
Definition: ri.h:442
#define area_size(x)
Definition: ri.h:544
#define value_constant(x)
Definition: ri.h:3073
#define CONTROL_(x)
Definition: ri.h:913
#define syntax_reference(x)
Definition: ri.h:2730
#define syntax_tag(x)
Definition: ri.h:2727
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define control_predecessors(x)
Definition: ri.h:943
#define range_upper(x)
Definition: ri.h:2290
struct _newgen_struct_unstructured_ * unstructured
Definition: ri.h:447
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define constant_int(x)
Definition: ri.h:850
#define type_functional(x)
Definition: ri.h:2952
#define dimension_lower(x)
Definition: ri.h:980
#define type_variable(x)
Definition: ri.h:2949
#define entity_storage(x)
Definition: ri.h:2794
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define control_domain
newgen_controlmap_domain_defined
Definition: ri.h:98
#define syntax_range(x)
Definition: ri.h:2733
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
@ is_syntax_range
Definition: ri.h:2692
@ is_syntax_call
Definition: ri.h:2693
@ is_syntax_reference
Definition: ri.h:2691
#define range_increment(x)
Definition: ri.h:2292
#define value_constant_p(x)
Definition: ri.h:3071
#define ram_section(x)
Definition: ri.h:2249
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define entity_undefined
Definition: ri.h:2761
#define constant_int_p(x)
Definition: ri.h:848
#define expression_undefined
Definition: ri.h:1223
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_sequence
Definition: ri.h:1469
@ is_instruction_forloop
Definition: ri.h:1477
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define RANGE(x)
RANGE.
Definition: ri.h:2257
#define entity_name(x)
Definition: ri.h:2790
#define dimension_upper(x)
Definition: ri.h:982
#define reference_indices(x)
Definition: ri.h:2328
#define syntax_call(x)
Definition: ri.h:2736
#define control_successors(x)
Definition: ri.h:945
#define dimension_undefined
Definition: ri.h:955
#define type_area(x)
Definition: ri.h:2946
#define expression_undefined_p(x)
Definition: ri.h:1224
#define test_condition(x)
Definition: ri.h:2833
#define instruction_whileloop(x)
Definition: ri.h:1523
#define unstructured_entry(x)
Definition: ri.h:3004
#define range_lower(x)
Definition: ri.h:2288
#define variable_dimensions(x)
Definition: ri.h:3122
#define statement_instruction(x)
Definition: ri.h:2458
#define storage_ram(x)
Definition: ri.h:2521
#define instruction_call(x)
Definition: ri.h:1529
#define call_arguments(x)
Definition: ri.h:711
#define control_statement(x)
Definition: ri.h:941
#define instruction_test(x)
Definition: ri.h:1517
#define statement_undefined_p(x)
Definition: ri.h:2420
#define whileloop_condition(x)
Definition: ri.h:3160
#define basic_string_p(x)
Definition: ri.h:629
#define entity_type(x)
Definition: ri.h:2792
#define expression_syntax(x)
Definition: ri.h:1247
#define type_variable_p(x)
Definition: ri.h:2947
#define variable_basic(x)
Definition: ri.h:3120
#define statement_undefined
Definition: ri.h:2419
#define basic_string(x)
Definition: ri.h:631
#define ram_offset(x)
Definition: ri.h:2251
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
int printf()
s1
Definition: set.c:247
#define ifdebug(n)
Definition: sg.c:47
static char * x
Definition: split_file.c:159
Data structure to support abc Implied DO.
the stack head
Definition: stack.c:62
As we create checks with stop error message who tell us there are bound violations for which array,...
context data structure for bottom_up_abc newgen recursion
persistant_statement_to_control map
expression(* check_statement)(expression *, int)
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: delay.c:253
#define exp
Avoid some warnings from "gcc -Wshadow".
Definition: vasnprintf.c:207