PIPS
expression.c
Go to the documentation of this file.
1 /*
2 
3  $Id: expression.c 23415 2017-08-14 22:02:20Z irigoin $
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 
25 /*
26  * This file contains functions used to compute points-to sets at
27  * expression level.
28  *
29  * The argument pt_in is always modified by side-effects and returned.
30  */
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 
35 #include "genC.h"
36 #include "linear.h"
37 
38 #include "ri.h"
39 #include "effects.h"
40 
41 #include "ri-util.h"
42 #include "effects-util.h"
43 
44 #include "misc.h"
45 #include "properties.h"
46 
47 #include "text-util.h" // ??? pips_user_error?
48 #include "prettyprint.h" // for debugging
49 
50 #include "points-to.h"
51 
52 #include "semantics.h" // for semantics_user_warning()
53 
54 /* FI: what is this function supposed to do? Just update "pt_in" to
55  make sure that "r" can be dereferenced? And then recursively, with
56  the different subscripts? */
58 {
59  if(!ENDP(sl)) {
61  if(pointer_type_p(rt)) {
62  //type pt = type_to_pointed_type(rt);
63  //list cl = reference_to_points_to_sinks(r, pt, pt_in, false, true);
64  list cl = reference_to_points_to_sinks(r, rt, pt_in, true, true);
65  // FI: the arc between "r" and NULL should be removed...
67  FOREACH(CELL, c, cl) {
68  if(!ENDP(CDR(sl))) {
69  expression fs = EXPRESSION(CAR(sl));
70  /* FI: we have to find the right location for the subscript
71  * to update. Some dimensions are due to the dimension of
72  * the source in pt_in, one dimension is due to the fact
73  * that we are dealing with a pointer, some dimensions are
74  * due to the fact that an array is pointed. The dimension
75  * to update may be the first one, the last one, or one in
76  * the middle.
77  *
78  * This also depends on strict typing...
79  *
80  * See for instance, Pointers/pointer20.c
81  */
84  list osl = reference_indices(or);
85  if(ENDP(osl)) {
88  NIL);
89  }
90  else {
92  }
95  }
96  else
97  pips_internal_error("reference could not be updated.\n");
98  }
99  }
100  }
101  else if(array_of_pointers_type_p(rt)) {
102  pips_internal_error("Not implemented yet.\n");
103  }
104  else
105  pips_internal_error("Meaningless call.\n");
106  }
107 }
108 ␌
109 /* Update pt_in and pt_out according to expression e.
110  *
111  * Ignore side effects due to pointer arithmetic and assignment and
112  * function calls if side_effet_p is not set. This may be useful when
113  * conditions are evaluated twice, once for true and once for false.
114  */
115 pt_map expression_to_points_to(expression e, pt_map pt_in, bool side_effect_p)
116 {
117  pt_map pt_out = pt_in;
118  if(!points_to_graph_bottom(pt_in)) {
119  syntax s = expression_syntax(e);
120  tag t = syntax_tag(s);
121 
122  switch(t) {
123  case is_syntax_reference: {
125  list sl = reference_indices(r);
126  entity v = reference_variable(r);
128  // FI: call16.c shows that the C parser does not generate the
129  // right construct, a subscript, when a scalar pointer is indexed
130  if(!ENDP(sl)) {
131  if(pointer_type_p(vt)) {
132  // expression tmp = entity_to_expression(v);
133  // pt_out = dereferencing_to_points_to(tmp, pt_in);
134  // pt_out = expressions_to_points_to(sl, pt_out, side_effect_p);
135  // free_expression(tmp);
136  reference nr = make_reference(v, NIL);
137  subscripted_reference_to_points_to(nr, sl, pt_in);
138  }
139  else if(array_of_pointers_type_p(vt)) {
140  int td = type_depth(vt);
141  int sn = (int) gen_length(sl);
142  if(sn<=td) {
143  ; // Nothing to do: a standard array subscript list
144  }
145  else
146  pips_internal_error("Not implemented yet.\n");
147  }
148  }
149  pt_out = reference_to_points_to(r, pt_in, side_effect_p);
150  break;
151  }
152  case is_syntax_range: {
153  range r = syntax_range(s);
154  pt_out = range_to_points_to(r, pt_in, side_effect_p);
155  break;
156  }
157  case is_syntax_call: {
158  call c = syntax_call(s);
159  /* Some idea, but points-to information should rather be used
160  *
161  * list el = expression_to_proper_constant_path_effects(e);
162  *
163  * Also, this would be computed before we know if it is useful
164  * because we need an expression and not a call to have a function
165  * to compute effects. And we do not know if we want an inter or
166  * an intraprocedural points-to analysis.
167  *
168  * The alternative is too always compute points-to information
169  * interprocedurally, which makes sense as it is done for for
170  * memory effects and since points-to information is at a lower
171  * level than memory effects...
172  */
173  // Now, "el" is a useless parameter
174  list el = NIL;
175  pt_out = call_to_points_to(c, pt_in, el, side_effect_p);
176  gen_full_free_list(el);
177  break;
178  }
179  case is_syntax_cast: {
180  cast c = syntax_cast(s);
181  expression ce = cast_expression(c);
182  pt_out = expression_to_points_to(ce, pt_in, side_effect_p);
183  break;
184  }
187  if(sizeofexpression_type_p(soe))
188  ; // pt_in is not modified
189  else {
190  // expression ne = sizeofexpression_expression(soe);
191  // FI: we have a problem because sizeof(*p) does not imply that
192  // *p is evaluated...
193  // pt_out = expression_to_points_to(ne, pt_in);
194  ;
195  }
196  break;
197  }
198  case is_syntax_subscript: {
199  subscript sub = syntax_subscript(s);
200  expression a = subscript_array(sub);
201  list sel = subscript_indices(sub);
202  /* a cannot evaluate to null or undefined */
203  /* FI: we may need a special case for stubs... */
204  pt_out = dereferencing_to_points_to(a, pt_in);
205  pt_out = expression_to_points_to(a, pt_out, side_effect_p);
206  pt_out = expressions_to_points_to(sel, pt_out, side_effect_p);
207  break;
208  }
209  case is_syntax_application: {
211  pt_out = application_to_points_to(a, pt_out, side_effect_p);
212  break;
213  }
214  case is_syntax_va_arg: {
215  // The call to va_arg() does not create a points-to per se
216  list soel = syntax_va_arg(s);
217  sizeofexpression soe1 = SIZEOFEXPRESSION(CAR(soel));
218  //sizeofexpression soe2 = SIZEOFEXPRESSION(CAR(CDR(soel)));
220  // type t = sizeofexpression_type(soe2);
221  pt_out = expression_to_points_to(se, pt_out, side_effect_p);
222  break;
223  }
224  default:
225  ;
226  }
227  }
228  pips_assert("pt_out is consistent and defined",
230  && !points_to_graph_undefined_p(pt_out));
231  return pt_out;
232 }
233 
234 /* Compute the points-to information pt_out that results from the
235  * evaluation of a possibly empty list of expression. A new data
236  * structure is allocated.
237  *
238  * Ignore side-effects unless side_effect_p is set to true.
239  *
240  * The result is correct only if you are sure that all expressions in
241  * "el" are always evaluated.
242  */
243 pt_map expressions_to_points_to(list el, pt_map pt_in, bool side_effect_p)
244 {
245  pt_map pt_out = pt_in;
246  FOREACH(EXPRESSION, e, el) {
247  if(points_to_graph_bottom(pt_out))
248  break;
249  pt_out = expression_to_points_to(e, pt_out, side_effect_p);
250  }
251 
252  return pt_out;
253 }
254 
255 /* The subscript expressions may impact the points-to
256  * information. E.g. a[*(p++)]
257  *
258  * FI: I'm surprised that pointers can be indexed instead of being
259  * subscripted... This is linked to the parser in
260  * expression_to_points_to().
261  */
262 pt_map reference_to_points_to(reference r, pt_map pt_in, bool side_effect_p)
263 {
264  pt_map pt_out = pt_in;
265  if(!points_to_graph_bottom(pt_in)) {
266  list sel = reference_indices(r);
267  entity v = reference_variable(r);
269  // FI: some or all of these tests could be placed in
270  // dereferencing_to_points_to()
271  if(!entity_stub_sink_p(v)
272  && !formal_parameter_p(v)
273  && !ENDP(sel)
274  && pointer_type_p(t)) {
276  pt_out = dereferencing_to_points_to(e, pt_in);
277  free_expression(e);
278  }
279  pt_out = expressions_to_points_to(sel, pt_in, side_effect_p);
280  }
281  return pt_out;
282 }
283 
284 pt_map range_to_points_to(range r, pt_map pt_in, bool side_effect_p)
285 {
286  pt_map pt_out = pt_in;
287  expression l = range_lower(r);
288  expression u = range_upper(r);
290  pt_out = expression_to_points_to(l, pt_in, side_effect_p);
291  pt_out = expression_to_points_to(u, pt_out, side_effect_p);
292  pt_out = expression_to_points_to(i, pt_out, side_effect_p);
293  return pt_out;
294 }
295 
296 /* Three different kinds of calls are distinguished:
297  *
298  * - calls to constants, e.g. NULL,
299  *
300  * - calls to intrinsics, e.g. ++ or malloc(),
301  *
302  * - and calls to a user function.
303  *
304  * "el" is the effect list associated to the call site
305  */
306 pt_map call_to_points_to(call c, pt_map pt_in, list el, bool side_effect_p)
307 {
308  pt_map pt_out = pt_in;
309  if(!points_to_graph_bottom(pt_in)) {
310  tag tt;
311  entity f = call_function(c);
312  list al = call_arguments(c);
313  type ft = entity_type(f);
314  type rt = type_undefined;
315  if(type_functional_p(ft)) {
316  functional ff = type_functional(ft);
317  rt = functional_result(ff);
318 
319  // FI: we might have to handle here return?, exit, abort, (stop)
320  // if(ENTITY_STOP_P(e)||ENTITY_ABORT_SYSTEM_P(e)||ENTITY_EXIT_SYSTEM_P(e)
321  // It is done somewhere else
322 
323  /* points-to updates due to arguments */
324  // FI: this cannot be delayed but it is unfortunately applied
325  // again when going down? See arithmetic08 and 09?
326  // This is necessary but cannot be placed here because of the
327  // recursive calls
328  // FI: we are in trouble for post increment and post decrement...
329  // We should update the target a second time in sinks.c!
330  if(!ENTITY_CONDITIONAL_P(f)) {
331  // FI: This is OK only if all subexpressions are always evaluated
332  pt_out = expressions_to_points_to(al, pt_in, side_effect_p);
333  }
334  else
335  pt_out = expression_to_points_to(EXPRESSION(CAR(al)), pt_in, side_effect_p);
336 
337  if(!points_to_graph_bottom(pt_out)) {
338  switch( tt = value_tag(entity_initial(f))) {
339  case is_value_code:{
340  pips_assert("f is a user-defined function", value_code_p(entity_initial(f)));
341  pt_out = user_call_to_points_to(c, pt_out, el);
342  }
343  break;
344  case is_value_unknown:
345  pips_internal_error("function %s has an unknown value\n",
346  entity_name(f));
347  break;
348  case is_value_intrinsic:
349  pt_out = intrinsic_call_to_points_to(c, pt_in, side_effect_p);
350  break;
351  case is_value_constant:
352  pt_out = pt_in; // FI?
353  break;
354  case is_value_symbolic:{
355  value v = entity_initial(f);
356  symbolic s = value_symbolic(v);
358  pt_out = expression_to_points_to(ex, pt_in, side_effect_p);
359  }
360  break;
361  case is_value_expression:{
362  value v = entity_initial(f);
364  pt_out = expression_to_points_to(ex, pt_in, side_effect_p);
365  }
366  break;
367  default:
368  pips_internal_error("unknown tag %d\n", tt);
369  break;
370  }
371  }
372  }
373  else if(type_variable_p(ft)) {
374  /* Must be a pointer to a function */
375  if(pointer_type_p(ft)) {
376  /* I do not know if nft must be freed later */
377  type nft = type_to_pointed_type(ft);
378  pips_assert("Must be a function", type_functional_p(nft));
379  functional nff = type_functional(nft);
380  rt = functional_result(nff);
381  }
382  else
383  pips_internal_error("Unexpected type.\n");
384  }
385  else if(type_void_p(rt))
386  /* points-to updates due to arguments */
387  pt_out = expressions_to_points_to(al, pt_in, side_effect_p);
388  else
389  pips_internal_error("Unexpected type.\n");
390  }
391 
392  pips_assert("pt_out is consistent and defined",
394  && !points_to_graph_undefined_p(pt_out));
395 
396  return pt_out;
397 }
398 
399 
400 /* FI: this should not generate any points-to update
401  *
402  * it would be better not to go down here
403  */
405 {
406  pt_map pt_out = pt_in;
407 
408  return pt_out;
409 }
410 
411 pt_map intrinsic_call_to_points_to(call c, pt_map pt_in, bool side_effect_p)
412 {
413  pt_map pt_out = pt_in;
414  entity f = call_function(c);
415 
416  list al = call_arguments(c);
417 
418  //set_methods_for_proper_simple_effects();
419  //list el = call_to_proper_effects(c);
420  //generic_effects_reset_all_methods();
421 
422  pips_debug(5, "intrinsic function \"%s\"\n", entity_name(f));
423 
424  // FI: short term version
425  // pt_out = points_to_intrinsic(statement_undefined, c, f, al, pt_in, el);
426  // return pt_out;
427 
428  // FI: Where should we check that the update is linked to a pointer?
429  // Should we go down because a pointer assignment may be hidden anywhere...
430  // Or have we already taken care of this in call_to_points_to()
431 
432  if(ENTITY_ASSIGN_P(f)) {
433  expression lhs = EXPRESSION(CAR(al));
434  expression rhs = EXPRESSION(CAR(CDR(al)));
435  pt_out = assignment_to_points_to(lhs, rhs, pt_out);
436  }
437  else if (ENTITY_FREE_SYSTEM_P(f)) {
438  expression lhs = EXPRESSION(CAR(al));
439  pt_out = freed_pointer_to_points_to(lhs, pt_out, side_effect_p);
440  }
441  // According to C standard, pointer arithmetics does not change
442  // the targeted object.
443  else if(ENTITY_PLUS_UPDATE_P(f)) {
444  expression lhs = EXPRESSION(CAR(al));
445  type lhst = expression_to_type(lhs);
446  if(pointer_type_p(lhst)) {
447  expression delta = EXPRESSION(CAR(CDR(al)));
448  pt_out = pointer_arithmetic_to_points_to(lhs, delta, pt_out);
449  }
450  free_type(lhst);
451  }
452  else if(ENTITY_MINUS_UPDATE_P(f)) {
453  expression lhs = EXPRESSION(CAR(al));
454  type lhst = expression_to_type(lhs);
455  if(C_pointer_type_p(lhst)) {
456  expression rhs = EXPRESSION(CAR(CDR(al)));
458  expression delta = MakeUnaryCall(um, copy_expression(rhs));
459  pt_out = pointer_arithmetic_to_points_to(lhs, delta, pt_out);
460  free_expression(delta);
461  }
462  free_type(lhst);
463  }
465  expression lhs = EXPRESSION(CAR(al));
466  type lhst = expression_to_type(lhs);
467  if(C_pointer_type_p(lhst) && side_effect_p) {
468  expression delta = int_to_expression(1);
469  pt_out = pointer_arithmetic_to_points_to(lhs, delta, pt_out);
470  free_expression(delta);
471  }
472  free_type(lhst);
473  }
475  expression lhs = EXPRESSION(CAR(al));
476  type lhst = expression_to_type(lhs);
477  if(C_pointer_type_p(lhst)) {
478  expression delta = int_to_expression(-1);
479  pt_out = pointer_arithmetic_to_points_to(lhs, delta, pt_out);
480  free_expression(delta);
481  }
482  free_type(lhst);
483  }
485  /* Is the dereferenced pointer null or undefined? */
486  expression p = EXPRESSION(CAR(al));
487  pt_out = dereferencing_to_points_to(p, pt_out);
488  }
489  else if(ENTITY_PLUS_C_P(f) || ENTITY_MINUS_C_P(f)) {
490  /* Is the dereferenced pointer null or undefined? */
491  expression p1 = EXPRESSION(CAR(al));
492  type t1 = expression_to_type(p1);
493  if(pointer_type_p(t1))
494  pt_out = dereferencing_to_points_to(p1, pt_out);
495  else {
496  expression p2 = EXPRESSION(CAR(CDR(al)));
497  type t2 = expression_to_type(p2);
498  if(pointer_type_p(t2))
499  pt_out = dereferencing_to_points_to(p2, pt_out);
500  }
501  }
502  else if(ENTITY_ASSERT_FAIL_SYSTEM_P(f)) {
503  // FI: no return from assert failure
504  clear_pt_map(pt_out);
505  points_to_graph_bottom(pt_out) = true;
506  }
508  /* || ENTITY_ASSERT_FAIL_SYSTEM_P(f) */) {
509  clear_pt_map(pt_out);
510  points_to_graph_bottom(pt_out) = true;
511  }
512 #if 0
516  || ENTITY_ISOC99_SCANF_P(f)) {
517  FOREACH(EXPRESSION, a, al) {
519  if(C_pointer_type_p(at)) {
520  // For the side-effects on pt_out
521  list sinks = expression_to_points_to_sinks(a, pt_out);
522  if(gen_length(sinks)==1 && nowhere_cell_p(CELL(CAR(sinks)))) {
523  /* attempt at using an undefined value */
524  pips_user_warning("Undefined value \"%s\" is used at line %d.\n",
527 
528  clear_pt_map(pt_out);
529  points_to_graph_bottom(pt_out) = true;
530  }
531  gen_free_list(sinks);
532  // FI: there is no reason to dereference arguments beyond FILE * and format
533  pt_out = dereferencing_to_points_to(a, pt_out);
534  }
535  }
536  // FI: this is already overperformed by the previous loop
537  if(!points_to_graph_bottom(pt_out)
539  || ENTITY_ISOC99_FSCANF_P(f))) {
540  /* stdin, stdout, stderr, fd... must be defined and not NULL */
541  expression a1 = EXPRESSION(CAR(al));
542  if(expression_reference_p(a1)) {
543  expression d =
545  copy_expression(a1));
546  pt_out = expression_to_points_to(d, pt_out, false);
547  free_expression(d);
548  }
549  }
550  }
551 #endif
552  else if(ENTITY_FPRINTF_P(f)
553  || ENTITY_SPRINTF_P(f)
554  || ENTITY_FSCANF_P(f)
555  || ENTITY_SSCANF_P(f)
558  || ENTITY_PRINTF_P(f)
559  || ENTITY_SCANF_P(f)
560  || ENTITY_ISOC99_SCANF_P(f)) {
561  /* Check the FILE * parameter, when it exists, and the char *
562  * format parameter, as well as the char * other actual arguments
563  * since they may be dereferenced or not, depending on the format
564  * content. With a %p, the pointer is not referenced, with a %s,
565  * it is.
566  */
567  int n = 1;
568  int m = 2; // Number of mandatory parameters before the vararg part
569  if(ENTITY_PRINTF_P(f)
570  || ENTITY_SCANF_P(f)
572  m = 1;
573  FOREACH(EXPRESSION, a, al) {
575  if(n<=m) {
576  if(C_pointer_type_p(at)) {
577  // For the side-effects on pt_out
578  list sinks = expression_to_points_to_sinks(a, pt_out);
579  if(gen_length(sinks)==1 && nowhere_cell_p(CELL(CAR(sinks)))) {
580  /* attempt at using an undefined value */
581  pips_user_warning("Undefined value \"%s\" is used at line %d.\n",
584 
585  clear_pt_map(pt_out);
586  points_to_graph_bottom(pt_out) = true;
587  }
588  gen_free_list(sinks);
589  pt_out = dereferencing_to_points_to(a, pt_out);
590  }
591  else {
592  pips_user_error("Argument %d of intrinsics \"%s\" should be a "
593  "pointer and not \"%s\".\n",
594  n,
597  }
598  }
599  else { // The vararg part of the IO call site
600  if(char_star_type_p(at)) {
601  /* Expression a may be dereferenced or not depending on the
602  * corresponding format specification, %s or %p.
603  *
604  * We could try to analyze the format when it is available
605  * to decide if a dereferencing must occur with %s or not.
606  */
607  list sinks = expression_to_points_to_sinks(a, pt_out);
608  if(gen_length(sinks)==1 && nowhere_cell_p(CELL(CAR(sinks)))) {
609  /* possible attempt at using an undefined value */
610  pips_user_warning("Undefined value \"%s\" might be used at line %d.\n",
613 
614  }
615  gen_free_list(sinks);
616  pt_map pt_no = pt_out;
617  pt_map pt_yes = copy_points_to_graph(pt_out);
618  pt_yes = dereferencing_to_points_to(a, pt_yes);
619  pt_out = merge_points_to_graphs(pt_no, pt_yes);
622  free_pt_map(pt_yes), free_pt_map(pt_no);
623  }
624  }
625  n++;
626  }
627  if(n==1)
628  pips_user_error("IO intrinsics \"%s\" requires at least one argument",
630  else if(n==2 && m==2)
631  pips_user_error("IO intrinsics \"%s\" requires at least two arguments",
633  }
634  else if(ENTITY_C_RETURN_P(f)) {
635  /* it is assumed that only one return is present in any module
636  code because internal returns are replaced by gotos */
637  if(ENDP(al)) {
638  // clear_pt_map(pt_out);
639  ; // the necessary projections are performed elsewhere
640  }
641  else {
642  expression rhs = EXPRESSION(CAR(al));
643  type rhst = expression_to_type(rhs);
644  // FI: should we use the type of the current module?
645  if(pointer_type_p(rhst) || struct_type_p(rhst)) {
648  pt_out = assignment_to_points_to(lhs, rhs, pt_out);
649  }
650  free_type(rhst);
651  }
652  }
653  else if(ENTITY_FCLOSE_P(f)) {
654  expression lhs = EXPRESSION(CAR(al));
655  // pt_out = freed_pointer_to_points_to(lhs, pt_out, side_effect_p);
656  list lhc = expression_to_points_to_sources(lhs, pt_out);
657  cell uc = make_nowhere_cell();
658  list rhc = CONS(CELL, uc, NIL);
659  pt_out = list_assignment_to_points_to(lhc, rhc, pt_out);
660  }
661  else if(ENTITY_CONDITIONAL_P(f)) {
662  // FI: I needs this piece of code for assert();
663  expression c = EXPRESSION(CAR(al));
664  pt_map in_t = full_copy_pt_map(pt_out);
665  pt_map in_f = full_copy_pt_map(pt_out);
666  // FI: issue with the notion of pt_in
667  // stubs created when computing in_t should also be added in in_f
668  // or they are going to seem to be reallocated ambiguously in
669  // create_stub_entity(). Same issue I guess for the "if" construct
670  in_t = condition_to_points_to(c, in_t, true);
671  in_f = condition_to_points_to(c, in_f, false);
672  expression e1 = EXPRESSION(CAR(CDR(al)));
673  expression e2 = EXPRESSION(CAR(CDR(CDR(al))));
674  pt_map out_t = pt_map_undefined;
675 
676  if(!points_to_graph_bottom(in_t))
677  out_t = expression_to_points_to(e1, in_t, side_effect_p);
678 
679  pt_map out_f = pt_map_undefined;
680  // FI: should be factored out in a more general merge function...
681  if(!points_to_graph_bottom(in_f))
682  out_f = expression_to_points_to(e2, in_f, side_effect_p);
683 
684  if(points_to_graph_bottom(in_t))
685  pt_out = out_f;
686  else if(points_to_graph_bottom(in_f))
687  pt_out = out_t;
688  else
689  pt_out = merge_points_to_graphs(out_t, out_f);
690  // FI: this destroys pt_out for test case pointer02, Memory leaks...
691  //free_pt_map(in_t), free_pt_map(in_f), free_pt_map(out_t), free_pt_map(out_f);
692  }
693  else if(ENTITY_FOPEN_P(f)) {
694  expression e1 = EXPRESSION(CAR(al));
695  pt_out = dereferencing_to_points_to(e1, pt_out);
696  expression e2 = EXPRESSION(CAR(CDR(al)));
697  pt_out = dereferencing_to_points_to(e2, pt_out);
698  }
699  else if(ENTITY_FDOPEN_P(f)) {
700  expression e2 = EXPRESSION(CAR(CDR(al)));
701  pt_out = dereferencing_to_points_to(e2, pt_out);
702  }
703  else if(ENTITY_FREOPEN_P(f)) {
704  expression e1 = EXPRESSION(CAR(al));
705  pt_out = dereferencing_to_points_to(e1, pt_out);
706  expression e2 = EXPRESSION(CAR(CDR(al)));
707  pt_out = dereferencing_to_points_to(e2, pt_out);
708  expression e3 = EXPRESSION(CAR(CDR(CDR(al))));
709  pt_out = dereferencing_to_points_to(e3, pt_out);
710  }
711  else if(ENTITY_FREAD_P(f) || ENTITY_FWRITE_P(f)) {
712  expression e1 = EXPRESSION(CAR(al));
713  pt_out = dereferencing_to_points_to(e1, pt_out);
714  expression e4 = EXPRESSION(CAR(CDR(CDR(CDR(al)))));
715  pt_out = dereferencing_to_points_to(e4, pt_out);
716  }
717  else if(ENTITY_CLEARERR_P(f) || ENTITY_FEOF_P(f)
719  expression e1 = EXPRESSION(CAR(al));
720  pt_out = dereferencing_to_points_to(e1, pt_out);
721  }
724  expression e1 = EXPRESSION(CAR(al));
725  pt_out = dereferencing_to_points_to(e1, pt_out);
726  expression e2 = EXPRESSION(CAR(CDR(al)));
727  pt_out = dereferencing_to_points_to(e2, pt_out);
728  // FI: we might need to do more for e3 in strncat case
729  }
730  else {
731  // FI: fopen(), fclose() should be dealt with
732  // fopen implies that its path argument is not NULL, just like a test
733  // fclose implies that its fp argument is not NULL on input and
734  // points to undefined on output.
735 
736  // Not safe till all previous tests are defined
737  // It is assumed that other intrinsics do not generate points-to arcs...
738  // pips_internal_error("Not implemented yet\n");
739  pt_out = pt_in;
740  }
741 
742  pips_assert("pt_out is consistent and defined",
744  && !points_to_graph_undefined_p(pt_out));
745 
746  return pt_out;
747 }
748 
749 
750 /* Update the sink locations associated to the source "lhs" under
751  * points-to information pt_map by "delta".
752  *
753  * C standard guarantees that the sink objects is unchanged by pointer
754  * arithmetic.
755  *
756  * Property POINTS_TO_STRICT_POINTER_TYPES is used to be more or less
757  * flexible about formal parameters and local variables such as "int *
758  * p"
759  */
761  expression delta ,
762  pt_map pt_in)
763 {
764  pt_map pt_out = pt_in;
765  list sources = expression_to_points_to_sources(lhs, pt_out);
766  bool to_be_freed;
767  type et = points_to_expression_to_type(lhs, &to_be_freed);
768  FOREACH(CELL, source, sources) {
769  list sinks = source_to_sinks(source, pt_out, false);
770  if(ENDP(sinks)) {
772  //pips_internal_error("Sink missing for a source based on \"%s\".\n",
773  // entity_user_name(v));
774  pips_user_warning("No defined value for pointer \"%s\".\n",
775  entity_user_name(v));
776  if(gen_length(sources)==1)
777  // The code cannot be executed
778  clear_pt_map(pt_out);
779  }
780  offset_cells(source, sinks, delta, et, pt_out);
781  // FI: we could perform some filtering out of pt_in
782  // If an arc points from source to nowehere/undefined or to the
783  // null location, this arc should be removed from pt_in as it
784  // cannot lead to an execution reaching the next statement.
785  FOREACH(CELL, sink, sinks) {
786  if(nowhere_cell_p(sink))
787  remove_points_to_arcs(source, sink, pt_out);
788  else if(null_cell_p(sink))
789  remove_points_to_arcs(source, sink, pt_out);
790  }
791  }
792  // FI: should we free the sources list? Fully free it?
793  return pt_out;
794 }
795 ␌
796 /* Side effect on reference "r".
797  *
798  * r is assumed to be a reference to an array.
799  *
800  * The offset is applied to the last suscript.
801  */
803 {
804  value v = EvalExpression(delta);
805  list rsl = reference_indices(r);
807  int dv = constant_int(value_constant(v));
808  if(ENDP(rsl)) {
809  // FI: oops, we are in trouble; assume 0...
810  expression se = int_to_expression(dv);
812  }
813  else {
814  // Select the index that should be subscripted
816  expression lse = EXPRESSION(CAR(sl));
817  value vlse = EvalExpression(lse);
818  if(value_constant_p(vlse) && constant_int_p(value_constant(vlse))) {
819  int ov = constant_int(value_constant(vlse));
820  int k = get_int_property("POINTS_TO_SUBSCRIPT_LIMIT");
821  if(-k <= ov && ov <= k) {
822  expression nse = int_to_expression(dv+ov);
823  //EXPRESSION_(CAR(gen_last(sl))) = nse;
824  EXPRESSION_(CAR(sl)) = nse;
825  }
826  else {
828  //EXPRESSION_(CAR(gen_last(sl))) = nse;
829  EXPRESSION_(CAR(sl)) = nse;
830  }
831  free_expression(lse);
832  }
833  else {
834  // FI: assume * is used... UNBOUNDED_DIMENSION
836  //EXPRESSION_(CAR(gen_last(sl))) = nse;
837  EXPRESSION_(CAR(sl)) = nse;
838  free_expression(lse);
839  }
840  }
841  }
842  else {
843  if(ENDP(rsl)) {
845  reference_indices(r) = CONS(EXPRESSION, nse, NIL);
846  }
847  else {
849  expression ose = EXPRESSION(CAR(sl));
851  EXPRESSION_(CAR(sl)) = nse;
852  free_expression(ose);
853  }
854  }
855 }
856 ␌
857 /* Each cell in sinks is replaced by a cell located "delta" elements
858  * further up in the memory. In some cases, the same points-to are
859  * removed and added. For instance, t[0],t[1] -> t[1],t[2] because of
860  * a p++, and t[1] is removed and added.
861  *
862  * If the source may point to null, the corresponding arc is
863  * removed. If the source points only to null, the resulting graph is
864  * bottom.
865  *
866  * This procedure must be used when cells in "sinks" are components of
867  * points-to arcs stored in a points-to set.
868  */
869 void offset_cells(cell source, list sinks, expression delta, type et, pt_map in)
870 {
871  // FI: it would be easier to use two lists of arcs rather than sets.
872  // FI: should we assert that expression delta!=0?
873  pt_map old = new_pt_map();
874  pt_map new = new_pt_map();
875  bool unfeasible_p = false;
876  FOREACH(CELL, sink, sinks) {
877  if(!anywhere_cell_p(sink) && !cell_typed_anywhere_locations_p(sink)) {
878  points_to pt = find_arc_in_points_to_set(source, sink, in);
879  // FI: the arc may not be found; for instance, you know that
880  // _pp_1[1] points towards *NULL_POINTER*, but this is due to an arc
881  // _pp_1[*]->*NULL_POINTER*; this arc does not have to be updated
882  if(!points_to_undefined_p(pt)) {
883  if(null_cell_p(sink)) {
884  add_arc_to_pt_map(pt, old);
885  if(gen_length(sinks)==1) {
886  semantics_user_warning("Arithmetic operation performed on NULL pointer \"%s\".\n", points_to_cell_to_string(source));
887  unfeasible_p = true;
888  }
889  else
890  semantics_user_warning("Arithmetic operation performed on \"%s\", which might be a NULL pointer.\n", points_to_cell_to_string(source));
891  }
892  else {
893  add_arc_to_pt_map(pt, old);
894  points_to npt = offset_cell(pt, delta, et);
895  add_arc_to_pt_map(npt, new);
896  }
897  }
898  else {
899  // Another option would be to generate nothing in this case
900  // since it is taken care of by the lattice...
901 
902  // Since pt has not been found in "in", the approximation must be may
903  pt = make_points_to(copy_cell(source), copy_cell(sink),
906  points_to npt = offset_cell(pt, delta, et);
907  add_arc_to_pt_map(npt, new);
908  }
909  }
910  }
911  difference_of_pt_maps(in, in, old);
912  union_of_pt_maps(in, in, new);
913  if(unfeasible_p)
914  points_to_graph_bottom(in) = true;
915 }
916 
917 /* Allocate and return a new points-to "npt", copy of "pt", with an
918  * offset of "delta" on the sink. "et" is used to determine which
919  * index should be offseted.
920  *
921  * Some kind of k-limiting should be performed here to avoid creating
922  * too many new nodes in the points-to graph, such as t[0], t[1],... A
923  * fix point t[*] should be used when too may nodes already exist.
924  *
925  * Since "sink" is used to compute the key in the hash table used to
926  * represent set "in", it is not possible to perform a side effect on
927  * "sink" without removing and reinserting the corresponding arc.
928  *
929  * FI: I am not sure we have the necessary information to know which
930  * subscript must be updated when more than one is available. This is
931  * bad for multidimensional arrays and worse for references to stub
932  * that may include fields (or not) as subscript as well as lots of
933  * articificial dimensions due to the source.
934  *
935  * I assumed gen_last() to start with, but it is unlikely in general!
936  */
938 {
939  /* "&a[i]" should be transformed into "&a[i+eval(delta)]" when
940  "delta" can be statically evaluated */
941  points_to npt = copy_points_to(pt);
942  cell sink = points_to_sink(npt);
943  reference r = cell_any_reference(sink);
944  entity v = reference_variable(r);
945  if(nowhere_cell_p(sink))
946  ; // user error: possible incrementation of an uninitialized pointer
947  else if(null_cell_p(sink))
948  ; // Impossible: possible incrementation of a NULL pointer
949  else if(anywhere_cell_p(sink))
950  ; // It is already fuzzy no need to add more
951  // FI: it might be necessary to exclude *HEAP* too when a minimal
952  // heap model is used (ABSTRACT_HEAP_LOCATIONS = "unique")
953  else {
955  // FI: I do not understand why this is based on the type of v and
956  // not on the ype of r
957  if(array_type_p(vt)
958  // FI: the property should have been taken care of earlier when
959  // building sink
960  /*|| !get_bool_property("POINTS_TO_STRICT_POINTER_TYPES")*/) {
961  cell source = points_to_source(npt);
962  bool to_be_freed;
963  type source_t = points_to_cell_to_type(source, &to_be_freed);
964  type c_source_t = compute_basic_concrete_type(source_t);
965  if(to_be_freed) free_type(source_t);
966  type pt = type_to_pointed_type(c_source_t);
967  type e_sink_t = compute_basic_concrete_type(pt);
968  if(array_pointer_type_equal_p(vt, e_sink_t)
969  && get_bool_property("POINTS_TO_STRICT_POINTER_TYPES"))
970  pips_user_error("Use of pointer arithmetic on \"%s\" at line %d via reference \"%s\" is not "
971  "standard-compliant.\n"
972  "Reset property \"POINTS_TO_STRICT_POINTER_TYPES\""
973  " for usual non-standard compliant C code.\n",
974  entity_user_name(v),
977  else
978  offset_array_reference(r, delta, et);
979  }
980  else if(struct_type_p(vt)) {
981  // The struct may contain an array field.
982  // FI: should we check the existence of the field in the subscripts?
983  offset_array_reference(r, delta, et);
984  }
986  // FI: waiting for ROM buffers containing the constant strings...
987  offset_array_reference(r, delta, et);
988  }
989  // FI to be extended to pointers and points-to stubs
990  else {
991  cell source = points_to_source(npt);
992  if(get_bool_property("POINTS_TO_STRICT_POINTER_TYPES")) {
993  pips_user_error("Use of pointer arithmetic on \"%s\" at line %d via reference \"%s\" is not "
994  "standard-compliant.\n"
995  "Reset property \"POINTS_TO_STRICT_POINTER_TYPES\""
996  " for usual non-standard compliant C code.\n",
997  entity_user_name(v),
1000  }
1001  else {
1002  pips_user_error("Use of pointer arithmetic on \"%s\" at line %d via reference \"%s\" is not "
1003  "standard-compliant.\n",
1004  entity_user_name(v),
1007  }
1008  }
1009  }
1010  return npt;
1011 }
1012 ␌
1013 /* Each cell in sinks is replaced by a cell located "delta" elements
1014  * further up in the memory.
1015  *
1016  * Similar to offset_cells(), but, in spite of the name, cannot be
1017  * used with points-to cells that are part of a points-to belonging to
1018  * a points-to set.
1019  */
1021 {
1022  FOREACH(CELL, sink, sinks) {
1023  offset_points_to_cell(sink, delta, t, ENDP(CDR(sinks)));
1024  }
1025 }
1026 
1027 /* FI: offset_cell() has been derived from this function. Some
1028  * factoring out should be performed.
1029  *
1030  * The naming is all wrong: offset_points_to_cell() can operate on a
1031  * cell, while offset_cell() is designed to operate on a cell
1032  * component of a points-to.
1033  *
1034  * Type "t" is used to decide which subscript should be updated by delta.
1035  */
1037  expression delta,
1038  type t,
1039  bool unique_p __attribute__ ((__unused__)))
1040 {
1041  /* "&a[i]" should be transformed into "&a[i+eval(delta)]" when
1042  "delta" can be statically evaluated */
1043  reference r = cell_any_reference(sink);
1044  entity rv = reference_variable(r);
1045  if(nowhere_cell_p(sink))
1046  ; // user error: possible incrementation of an uninitialized pointer
1047  else if(null_cell_p(sink))
1048  // FI: the operation requested is impossible; the condition should
1049  // be checked above to update the pt_map and/or to signal a bug
1050  ; // Impossible: possible incrementation of a NULL pointer
1051  else if(anywhere_cell_p(sink))
1052  ; // It is already fuzzy no need to add more
1053  // FI: it might be necessary to exclude *HEAP* too when a minimal
1054  // heap model is used (ABSTRACT_HEAP_LOCATIONS = "unique")
1055  // FI: this has been dealt with somewhere else
1056  // else if(entity_array_p(rv)
1057  // || !get_bool_property("POINTS_TO_STRICT_POINTER_TYPES")) {
1058  else if(entity_array_p(rv) || cell_typed_anywhere_locations_p(sink)) {
1059  value val = EvalExpression(delta);
1060  list sl = reference_indices(r);
1061  if(value_constant_p(val) && constant_int_p(value_constant(val))) {
1062  int dv = constant_int(value_constant(val));
1063  if(ENDP(sl)) {
1064  if(entity_array_p(rv)) {
1065  // FI: oops, we are in trouble; assume 0...
1066  expression se = int_to_expression(dv);
1067  reference_indices(r) = CONS(EXPRESSION, se, NIL);
1068  }
1069  else {
1070  ; // FI: No need to add a zero subscript to a scalar variable
1071  }
1072  }
1073  else {
1074  // FI: this is wrong, there is no reason to update the last
1075  // subscript; the type of the offset should be passed as an
1076  // argument. See for instance dereferencing08.c. And
1077  // dereferencing18.c
1078  list tsl = find_points_to_subscript_for_type(sink, t);
1079  if(ENDP(tsl)) {
1080  // dereferencing18: the only possible offset is 0, dv==0,
1081  // Or the points-to information is approximate.
1082  // unique_p should be used here to decide if a warning should
1083  // be emitted
1084  ;
1085  }
1086  else {
1087  // expression lse = EXPRESSION(CAR(gen_last(sl)));
1088  expression lse = EXPRESSION(CAR(tsl));
1089  value vlse = EvalExpression(lse);
1090  if(value_constant_p(vlse) && constant_int_p(value_constant(vlse))) {
1091  int ov = constant_int(value_constant(vlse));
1092  int k = get_int_property("POINTS_TO_SUBSCRIPT_LIMIT");
1093  if(-k <= ov && ov <= k) {
1094  expression nse = int_to_expression(dv+ov);
1095  //EXPRESSION_(CAR(gen_last(sl))) = nse;
1096  EXPRESSION_(CAR(tsl)) = nse;
1097  }
1098  else {
1100  //EXPRESSION_(CAR(gen_last(sl))) = nse;
1101  EXPRESSION_(CAR(tsl)) = nse;
1102  }
1103  free_expression(lse);
1104  }
1105  else {
1106  // If the index cannot be computed, used the unbounded expression
1108  //EXPRESSION_(CAR(gen_last(sl))) = nse;
1109  EXPRESSION_(CAR(tsl)) = nse;
1110  free_expression(lse);
1111  }
1112  }
1113  }
1114  }
1115  else {
1116  if(ENDP(sl)) {
1118  reference_indices(r) = CONS(EXPRESSION, nse, NIL);
1119  }
1120  else {
1121  list tsl = find_points_to_subscript_for_type(sink, t);
1122  if(ENDP(tsl)) {
1123  /* No subscript is possible, but 0 and it does not need to appear */
1124  /* dereferencing18.c: a scalar was malloced */
1125  if(zero_expression_p(delta))
1126  ; // Nothing to be done: the subscript is ignored
1127  else {
1128  /* We might use unique_p and the value of delta to detect
1129  an error or to warn the user about a possible error */
1130  ;
1131  }
1132  }
1133  else {
1134  //expression ose = EXPRESSION(CAR(gen_last(sl)));
1135  expression ose = EXPRESSION(CAR(tsl));
1137  //EXPRESSION_(CAR(gen_last(sl))) = nse;
1138  EXPRESSION_(CAR(tsl)) = nse;
1139  free_expression(ose);
1140  }
1141  }
1142  }
1143  }
1144  // FI to be extended to pointers and points-to stubs
1145  else {
1146  if(zero_expression_p(delta)) {
1147  ;
1148  }
1149  else {
1150  pips_user_error("Use of pointer arithmetic on \"%s\" at line %d is not "
1151  "standard-compliant.\n%s",
1152  entity_user_name(rv),
1154  get_bool_property("POINTS_TO_STRICT_POINTER_TYPES")?
1155  "Try resetting property \"POINTS_TO_STRICT_POINTER_TYPES\""
1156  " for usual non-standard compliant C code.\n"
1157  :"");
1158  }
1159  }
1160 }
1161 
1162 ␌
1164 {
1165  pt_map pt_out = pt_in;
1166  // FI: lhs and rhs have already been used to update pt_in
1167  //pt_map pt_out = expression_to_points_to(lhs, pt_in);
1168  /* It is not obvious that you are allowed to evaluate this before
1169  the sink of lhs, but the standard probably forbid stupid side
1170  effects. */
1171  //pt_out = expression_to_points_to(lhs, pt_out);
1172  bool to_be_freed = false;
1173  type t = points_to_expression_to_type(lhs, &to_be_freed);
1174 
1176  if(pointer_type_p(ut))
1177  pt_out = pointer_assignment_to_points_to(lhs, rhs, pt_out);
1178  else if(struct_type_p(ut))
1179  pt_out = struct_assignment_to_points_to(lhs, rhs, pt_out);
1180  // FI: unions are not dealt with...
1181  else if(array_of_pointers_type_p(ut)) {
1182  /* Can occur in a declaration */
1183  /* When more precision is needed, the BRACE_INTRINSIC arguments
1184  will have to be analyzed... */
1185  pips_assert("lhs is a reference", expression_reference_p(lhs));
1187  list sl = reference_indices(r);
1188  pips_assert("The array reference has no indices", ENDP(sl));
1193  points_to a = make_points_to(source, sink,
1196  pt_out = add_arc_to_pt_map_(a, pt_in);
1197  }
1198  else if(array_of_struct_type_p(ut)) {
1199  pips_internal_error("Initialization of array of structs not implemented yet.\n");
1200  }
1201  else
1202  pt_out = pt_in; // What else?
1203 
1204  if(to_be_freed)
1205  free_type(t);
1206 
1207  return pt_out;
1208 }
1209 ␌
1210 /* Check that all cells in list "sinks" are compatible with type "ct"
1211  * if "eval_p" is false, and with the type pointed by "st" if eval_p is
1212  * true.
1213  */
1214 void check_type_of_points_to_cells(list sinks, type ct, bool eval_p)
1215 {
1216  type st = type_undefined;
1217 
1218  if(!ENDP(sinks)) {
1219  if(eval_p) {
1220  if(pointer_type_p(ct))
1221  st = copy_type(type_to_pointed_type(ct));
1222  else if(array_type_p(ct)) {
1224  }
1225  else
1226  pips_internal_error("Unexpected \"ct\" argument.\n");
1227  }
1228  else
1229  st = copy_type(ct);
1230  }
1231 
1232  FOREACH(CELL, c, sinks) {
1233  if(!null_cell_p(c)
1234  && !anywhere_cell_p(c)
1236  && !nowhere_cell_p(c)) {
1237  bool to_be_freed;
1238  type est = points_to_cell_to_type(c, &to_be_freed);
1239  type cest = compute_basic_concrete_type(est);
1240  //if(!array_pointer_type_equal_p(cest, st)
1241  //if(!concrete_type_equal_p(cest, st)
1242  if(!type_structurally_equal_p(cest, st)
1243  /* Adding the zero subscripts may muddle the type issue
1244  because "&a[0]" has not the same type as "a" although we
1245  normalize every cell into "a[0]". */
1246  && !(array_type_p(st)
1247  && array_pointer_type_equal_p(cest, st))
1248  //array_type_to_element_type(st)))
1249  /* Take care of the constant strings like "hello" */
1251  /* Take care of void */
1252  && !type_void_p(st) // cest could be checked as overloaded
1253  && !overloaded_type_p(cest)
1254  ) {
1255  pips_user_warning("Maybe an issue with a dynamic memory allocation.\n");
1256  pips_user_error("At line %d, "
1257  // "the type returned for the value of expression \"%s\"="
1258  "the type returned for the cell"
1259  "\"%s\", "
1260  "\"%s\", is not the expected type, \"%s\".\n",
1262  // expression_to_string(rhs),
1264  // copied from ri-util/type.c, print_type()
1265  string_of_type(cest),
1266  string_of_type(st));
1267  }
1268  }
1269  }
1270 }
1271 
1272 /* Check that the cells in list "sinks" have types compatible with the
1273  * expression on the left-hand side, lhs.
1274  *
1275  * List "sinks" is assumed to have been derived from the "rhs" expression.
1276  */
1278  // Was used in the error message..
1279  expression rhs __attribute__ ((unused)),
1280  list sinks)
1281 {
1282  // Some expression are synthesized to reuse existing functions.
1283  bool to_be_freed;
1284  type t = points_to_expression_to_type(lhs, &to_be_freed);
1286  type st = type_undefined; // sink type
1287  if(pointer_type_p(ct)) {
1289  }
1290  else if(array_type_p(ct)) {
1292  }
1293  else if(scalar_integer_type_p(ct)) {
1294  /* At least for the NULL pointer... */
1295  st = ct;
1296  }
1297  else
1298  pips_internal_error("Unexpected type for value.\n");
1299 
1300  if(!type_void_star_p(ct)) { // void * is compatible with all types...
1301  check_type_of_points_to_cells(sinks, st, false);
1302  }
1303  // Late free, to be able to see "t" under gdb...
1304  if(to_be_freed) free_type(t);
1305 }
1306 
1307 /* Any abstract location of the lhs in L is going to point to any sink of
1308  * any abstract location of the rhs in R.
1309  *
1310  * New points-to information must be added when a formal parameter
1311  * is dereferenced.
1312  *
1313  * Store independence must be checked.
1314  */
1316  expression rhs,
1317  pt_map pt_in)
1318 {
1319  pt_map pt_out = pt_in;
1320 
1321  pips_assert("pt_out is consistent on entry",
1323 
1324  list L = expression_to_points_to_sources(lhs, pt_out);
1325  /* Beware of points-to cell lattice: e.g. add a[*] to a[1] */
1326  /* This is not the right place to take the lattice into account. As
1327  a result, a[1] woud not kill a[1] anymore. The problem must be
1328  taken care of by the equations used in
1329  list_assignment_to_points_to(). */
1330  // L = points_to_cells_to_upper_bound_points_to_cells(L);
1331 
1332  pips_assert("pt_out is consistent after computing L",
1334 
1335  /* Make sure all cells in L are pointers: l may be an array of pointers */
1336  /* FI: I am not sure it is useful here because the conversion to an
1337  array due to property POINTS_TO_STRICT_POINTER_TYPES may not have
1338  occured yet */
1339  FOREACH(CELL, l, L) {
1340  bool to_be_freed;
1341  type lt = points_to_cell_to_type(l, &to_be_freed);
1342  if(array_type_p(lt)) {
1343  cell nl = copy_cell(l);
1344  // For Pointers/properties04.c, you want a zero subscript for
1345  // the lhs
1347  // FI: since it is an array, most of the pointers will be unchanged
1348  // FI: this should be useless, but it has an impact because
1349  // points-to stubs are computed on demand; see Pointers/assignment12.c
1351  list os = source_to_sinks(nl, pt_out, true);
1352  list nll = CONS(CELL, nl, NIL);
1353  pt_out = list_assignment_to_points_to(nll, os, pt_out);
1354  gen_free_list(nll);
1355  }
1356  if(to_be_freed) free_type(lt);
1357  }
1358 
1359  pips_assert("pt_out is consistent after cells are dangerously updated",
1361 
1362  /* Retrieve the memory locations that might be reached by the rhs
1363  *
1364  * Update the real "pt_in", the calling context, and "pt_out" by
1365  * adding new stubs linked directly or indirectly to the formal
1366  * parameters and global variables if necessary.
1367  */
1368  list R = expression_to_points_to_sinks(rhs, pt_out);
1369 
1370  check_rhs_value_types(lhs, rhs, R);
1371 
1372  pips_assert("pt_out is consistent after computing R",
1374 
1375  if(ENDP(L) || ENDP(R)) {
1376  //pips_assert("Left hand side reference list is not empty.\n", !ENDP(L));
1377  //pips_assert("Right hand side reference list is not empty.\n", !ENDP(R));
1378 
1379  // FI: where do we want to check for dereferencement of
1380  // nowhere/undefined and NULL? Here? Or within
1381  // list_assignment_to_points_to?
1382 
1383  /* We must be in a dead-code portion. If not pleased, adjust properties... */
1384  if(ENDP(L)) {
1386  pips_user_warning("Expression \"%s\" could not be dereferenced at line %d.\n",
1387  expression_to_string(lhs),
1389  else
1390  pips_user_warning("Expression \"%s\" could not be dereferenced.\n",
1391  expression_to_string(lhs));
1392  }
1393  if(ENDP(R)) {
1395  pips_user_warning("Expression \"%s\" could not be dereferenced at line %d.\n",
1396  expression_to_string(rhs),
1398  else
1399  pips_user_warning("Expression \"%s\" could not be dereferenced.\n",
1400  expression_to_string(rhs));
1401  }
1402  clear_pt_map(pt_out);
1403  points_to_graph_bottom(pt_out) = true;
1404  }
1405  else {
1406  // We are in trouble if L=={null} or R=={nowhere)...
1407  // We are not sure what to do if null in L or if nowhere in R
1408  int nR = (int) gen_length(R);
1409  if(nR==1 && nowhere_cell_p(CELL(CAR(R)))) {
1411  pips_user_warning("Assignment of an undefined value to \"%s\" at line %d.\n",
1412  expression_to_string(lhs),
1414  else
1415  pips_user_warning("Assignment of an undefined value to \"%s\".\n",
1416  expression_to_string(lhs));
1417  /* The C99 standard does not preclude the propagation of
1418  indeterminate values. It is often used in our test cases when
1419  structs are assigned.
1420 
1421  clear_pt_map(pt_out);
1422  points_to_graph_bottom(pt_out) = true;
1423  */
1424  pt_out = list_assignment_to_points_to(L, R, pt_out);
1425  }
1426  else
1427  pt_out = list_assignment_to_points_to(L, R, pt_out);
1428  }
1429 
1430  // FI: memory leak(s)?
1431 
1432  pips_assert("pt_out is consistent", consistent_points_to_graph_p(pt_out));
1433 
1434  return pt_out;
1435 }
1436 
1438  expression rhs,
1439  pt_map pt_in)
1440 {
1441  /* FI: this is a crazy idea to avoid problems in balancing test
1442  * branches. It should only be useful when the formal context has to
1443  * be expanded by this assignment. lhs = lhs;
1444  *
1445  * Of course, it is a catastrophy when expression lhs has side effects...
1446  *
1447  * And it does not work because the current "in" of the test is
1448  * modified by side-effect no seen when the false branch is analyzed.
1449  */
1450  // pt_map pt_out = internal_pointer_assignment_to_points_to(lhs, lhs, pt_in);
1451  pt_map pt_out = internal_pointer_assignment_to_points_to(lhs, rhs, pt_in);
1452  return pt_out;
1453 }
1454 ␌
1455 /* Remove from points-to cell list R cells that certainly cannot be
1456  freed. */
1458 {
1459  list nhl = NIL; // No heap list: cannot be freed
1460  FOREACH(CELL, c, R) {
1461  if(heap_cell_p(c) || stub_points_to_cell_p(c)) {
1463  list inds = reference_indices(r);
1464  /* if c is a heap location with indices other than zero then we
1465  have bumped into a non-legal free */
1466  if(!ENDP(inds)) {
1467  expression ind = EXPRESSION (CAR(inds));
1468  // No offset allowed for a free()
1469  if(!expression_null_p(ind))
1470  nhl = CONS(CELL, c, nhl);
1471  }
1472  // gen_free_list(inds);
1473  }
1474  else if(!heap_cell_p(c)
1475  && !stub_points_to_cell_p(c)
1477  nhl = CONS(CELL, c, nhl);
1478  }
1479  gen_list_and_not(&R, nhl);
1480  gen_free_list(nhl);
1481  return R;
1482 }
1483 
1484 /* Error detections on "L" and "R" have already been performed. R only
1485  * contains heap locations or stub locations, i.e. potential heap
1486  * locations. Neither L nor R are empty. "lhs" is provided for other
1487  * error messages.
1488  */
1490 {
1491  pt_map pt_out = pt_in;
1492  list ML = NIL; /* First level memory leaks */
1493 
1494  pips_assert("L is not empty", !ENDP(L));
1495  pips_assert("R is not empty", !ENDP(R));
1496 
1497  /* Build a nowhere cell - Should we check a property to type it or not? */
1498  //list N = CONS(CELL, make_nowhere_cell(), NIL);
1502 
1503  /* Remove Kill_1 if it is not empty by definition */
1504  if(gen_length(L)==1 && atomic_points_to_cell_p(CELL(CAR(L)))) {
1505  set pt_out_s = points_to_graph_set(pt_out);
1506  SET_FOREACH(points_to, pts, pt_out_s) {
1507  cell l = points_to_source(pts);
1508  // FI: use the CP lattice and its operators instead?
1509  //if(related_points_to_cell_in_list_p(l, L)) {
1510  if(points_to_cell_in_list_p(l, L)) {
1511  // FI: assuming you can perform the removal inside the loop...
1512  remove_arc_from_pt_map(pts, pt_out);
1513  }
1514  }
1515  }
1516 
1517  /* Memory leak detection... Must be computed early, before pt_out
1518  has been (too?) modified. Transitive closure not performed... If
1519  one cell has been freed and if it has become unreachable, then
1520  arcs starting from it have become useless and other cells that
1521  were pointed by it may also have become unreachable. */
1522  if(gen_length(R)==1 && unreachable_points_to_cell_p(CELL(CAR(R)),pt_out)) {
1523  cell c = CELL(CAR(R));
1525  if(pointer_type_p(ct) || struct_type_p(ct)
1527  || array_of_struct_type_p(ct)) {
1528  // FI: this might not work for arrays of pointers?
1529  // Many forms of "source" can be developped when we are dealing
1530  // struct and arrays
1531  // FI: do we need a specific version of source_to_sinks()?
1533  //cell nc = make_cell_reference(make_reference(v, NIL));
1534  list PML = variable_to_sinks(v, pt_out, true);
1535  FOREACH(CELL, m, PML) {
1536  if(heap_cell_p(m)) {
1538  pips_user_warning("Memory leak for bucket \"%s\".\n",
1539  entity_name(b));
1540  ML = CONS(CELL, m, ML);
1541  }
1542  }
1543  }
1544  }
1545 
1546  /* Add Gen_2, which is not conditionned by gen_length(R) or atomicity. */
1547  set pt_out_s = points_to_graph_set(pt_out);
1548  SET_FOREACH(points_to, pts, pt_out_s) {
1549  cell r = points_to_sink(pts);
1550  if(points_to_cell_in_list_p(r, R)) {
1551  if(!null_cell_p(r) && !anywhere_cell_p(r) && !nowhere_cell_p(r)) {
1552  /* Compute and add Gen_2 */
1553  cell source = points_to_source(pts);
1554  // FI: it should be a make_typed_nowhere_cell()
1557  cell sink = make_typed_nowhere_cell(pt);
1558  // FI: why may? because heap cells are always abstract locations
1559  //approximation a = make_approximation_may();
1561  points_to npt = make_points_to(copy_cell(source), sink, a,
1563  add_arc_to_pt_map(npt, pt_out);
1564  /* Do not notify the user that the source of the new
1565  nowhere points to relation is a dangling pointer
1566  because it is only a may information. Exact alias
1567  information or a more precise heap model would be
1568  necessary to have exact information about dangling
1569  pointers. */
1570  if(stub_points_to_cell_p(r)) {
1572  pips_user_warning("Dangling pointer \"%s\" has been detected at line %d.\n",
1573  entity_user_name(b),
1575  }
1576  }
1577  }
1578  }
1579 
1580 
1581  /* Remove Kill_2 if it is not empty by definition... which it is if
1582  heap(r) is true, but not if stub(r). Has to be done after Gen_2,
1583  or modification of pt_out should be delayed, which would avoid
1584  the internal modification of pt_out_s and make the code easier to
1585  understand... */
1586  if(gen_length(R)==1 && generic_atomic_points_to_cell_p(CELL(CAR(R)), false)) {
1587  set pt_out_s = points_to_graph_set(pt_out);
1588  cell r = CELL(CAR(R));
1589  if(!null_cell_p(r) && !anywhere_cell_p(r) && !nowhere_cell_p(r)) {
1590  SET_FOREACH(points_to, pts, pt_out_s) {
1591  cell s = points_to_sink(pts);
1592  if(points_to_cell_equal_p(r, s)) {
1593  // FI: pv_whileloop05, lots of related cells to remove after a free...
1594  // FI: assuming you can perform the removal inside the loop...
1595  remove_arc_from_pt_map(pts, pt_out);
1596  }
1597  }
1598  }
1599  }
1600 
1601  /* Remove Kill_3 if it is not empty by definition: with the
1602  current heap model, it is always empty. Unreachable cells are
1603  dealt somewhere else. They can be tested with
1604  points_to_sink_to_sources().
1605 
1606  FI: Must be placed after gen_1 in case the assignment makes the cell
1607  reachable? Nonsense?
1608  */
1609  if(gen_length(R)==1
1610  && (atomic_points_to_cell_p(CELL(CAR(R)))
1611  || unreachable_points_to_cell_p(CELL(CAR(R)), pt_out))) {
1612  cell c = CELL(CAR(R));
1613  list S = points_to_sink_to_sources(c, pt_out, false);
1614  if(ENDP(S) || atomic_points_to_cell_p(c)) {
1615  set pt_out_s = points_to_graph_set(pt_out);
1616  SET_FOREACH(points_to, pts, pt_out_s) {
1617  cell l = points_to_source(pts);
1619  // Potentially memory leaked cell:
1620  cell r = points_to_sink(pts);
1621  pt_out = memory_leak_to_more_memory_leaks(r, pt_out);
1622  remove_arc_from_pt_map(pts, pt_out);
1623  }
1624  }
1625  }
1626  else
1627  gen_free_list(S);
1628  }
1629 
1630  /* Add Gen_1 - Not too late since pt_out has aready been modified? */
1631  pt_out = list_assignment_to_points_to(L, N, pt_out);
1632 
1633  /* Add Gen_2: useless, already performed by Kill_2 */
1634 
1635  /*
1636  * Other pointers may or must now be dangling because their target
1637  * has been freed. Already detected at the level of Gen_2.
1638  */
1639 
1640  /* More memory leaks? */
1641  FOREACH(CELL, m, ML)
1642  pt_out = memory_leak_to_more_memory_leaks(m, pt_out);
1643  gen_free_list(ML);
1644 
1645  /* Clean up the resulting graph */
1646  // pt_out = remove_unreachable_heap_vertices_in_points_to_graph(pt_out, true);
1647  return pt_out;
1648 }
1649 
1650 ␌
1651  /* Any abstract location of the lhs in L is going to point to nowhere, maybe.
1652  *
1653  * Any source in pt_in pointing towards any location in lhs may or
1654  * Must now points towards nowhere (malloc07).
1655  *
1656  * New points-to information must be added when a formal parameter
1657  * is dereferenced.
1658  *
1659  * Equations for "free(e);":
1660  *
1661  * Let L = expression_to_sources(e,in)
1662  *
1663  * and R_1 = (expression_to_sinks(e,in) ^ (HEAP U STUBS)) - {undefined}
1664  *
1665  * where ^ denotes the set intersection.
1666  *
1667  * If R_1 is empty, an execution error must occur.
1668  *
1669  * If R_1={NULL}, nothing happens. Let R=R_1-{NULL}.
1670  *
1671  * Any location "l" corresponding to "e" can now point to nowhere/undefined:
1672  *
1673  * Gen_1 = {pts=(l,nowhere,a) | l in L}
1674  *
1675  * Any location source that pointed to a location r in the heap,
1676  * pointed to by some l by definition, can now point to
1677  * nowhere/undefined also:
1678  *
1679  * Gen_2 = {pts=(source,nowhere,a) | exists r in R
1680  * && r in Heap or Stubs
1681  * && exists pts'=(source,r,a') in in}
1682  *
1683  * If e corresponds to a unique (non-abstract?) location l, any arc
1684  * starting from l can be removed:
1685  *
1686  * Kill_1 = {pts=(l,r,a) in in | l in L && |L|=1 && atomic(l)}
1687  *
1688  * If the freed location r is precisely known, any arc pointing
1689  * towards it can be removed:
1690  *
1691  * Kill_2 = {pts=(l,r,a) in in | r in R && |R|=1 && atomic(r)}
1692  *
1693  * If the freed location r is precisely known or if it can no longer
1694  * be reached, any arc pointing from it can be removed:
1695  *
1696  * Kill_3 = {pts=(r,d,a) in in | r in R && |R|=1 && (atomic(r)
1697  * v unreachable_p(r, in)}
1698  *
1699  * Then the set PML = { d | heap(d) ^ (r,d,a) in Kill_3} becomes a set
1700  * of potential meory leaks. They are leaked if they become
1701  * unreachable in the new points-to relation out (see below) and they
1702  * generate recursively new potential memory leaks and an updated
1703  * points-to relation.
1704  *
1705  * Since our current heap model only use abstract locations and since
1706  * we do not keep any alias information, the predicate atomic should
1707  * always return false and the sets Kill_2 and Kill_3 should always be
1708  * empty, except if a stub is freed: locally the stub is atomic.
1709  *
1710  * So, after the execution of "free(e);", the points-to relation is:
1711  *
1712  * out = (in - Kill_1 - Kill_2 - Kill_3) U Gen_1 U Gen_2
1713  *
1714  * Warnings for potential dangling pointers:
1715  *
1716  * DP = {r|exists pts=(r,l,a) in Gen_2} // To be checked
1717  *
1718  * No warning is issued as those are only potential.
1719  *
1720  * Memory leaks: the freed bucket may be the only bucket containing
1721  * pointers towards another bucket:
1722  *
1723  * PML = {source_to_sinks(r)|r in R}
1724  * ML = {m|m in PML && heap_cell_p(m) && !reachable(m, out)}
1725  *
1726  * Note: for DP and ML, we could compute may and must/exact sets. We only
1727  * compute must/exact sets to avoid swamping the log file with false alarms.
1728  *
1729  * FI->FC: it might be better to split the problem according to
1730  * |R|. If |R|=1, you know which bucket is destroyed, unless it is an
1731  * abstract bucket... which we do not really know even at the
1732  * intraprocedural level. In that case, you could remove all edges
1733  * starting from r and then substitute r by nowhere/undefined.
1734  *
1735  * If |R| is greater than 1, then a new node nowhere/undefined must be
1736  * added and any arc ending up in R must be duplicated with a similar
1737  * arc ending up in the new node.
1738  *
1739  * The cardinal of |L| does not seem to have an impact: it does, see Kill_1
1740  */
1741 pt_map freed_pointer_to_points_to(expression lhs, pt_map pt_in, bool side_effect_p)
1742 {
1743  // FI: is this redundant with processing already performed by callers?
1744  // A test case is needed...
1745  pt_map pt_out = expression_to_points_to(lhs, pt_in, side_effect_p);
1746  list PML = NIL;
1747 
1748  list R_1 = expression_to_points_to_sinks(lhs, pt_out);
1749  list R = NIL;
1750  /* Remove cells from R_1 that do not belong to Heap: they cannot be
1751  freed */
1752  FOREACH(CELL,r, R_1) {
1753  if(heap_cell_p(r)
1754  || stub_points_to_cell_p(r)
1756  || null_cell_p(r))
1757  R = CONS(CELL, r, R);
1758  }
1759  gen_free_list(R_1);
1760 
1761  if(ENDP(R)) {
1762  /* A execution error is certain */
1763  pips_user_warning("Expression \"%s\" at line %d cannot be freed.\n",
1764  expression_to_string(lhs),
1766  clear_pt_map(pt_out);
1767  points_to_graph_bottom(pt_out) = true;
1768  }
1769  else if(gen_length(R)==1 && null_cell_p(CELL(CAR(R)))) {
1770  /* Free(NULL) has no effect*/
1771  ;
1772  }
1773  else {
1774  /* Remove from R locations that cannot be freed */
1775  R = freeable_points_to_cells(R);
1776 
1777  if(ENDP(R)) {
1778  /* We have bumped into a non-legal free such as free(p[10]). See test
1779  case malloc10.c */
1780  pips_user_warning("Free of a non-heap allocated address pointed "
1781  "by \"%s\" at line %d.\n"
1782  "Or bug in the points-to analysis...\n",
1783  expression_to_string(lhs),
1785  clear_pt_map(pt_out);
1786  points_to_graph_bottom(pt_out) = true;
1787  }
1788  else {
1789  list L = expression_to_points_to_sources(lhs, pt_out);
1790  pips_assert("L is not empty", !ENDP(L));
1791  pt_out = freed_list_to_points_to(lhs, L, R, pt_in);
1792  gen_free_list(L);
1793  }
1794  }
1795 
1796  // FI: memory leak(s) in this function?
1797  //gen_free_list(N);
1798  gen_full_free_list(R);
1799  gen_free_list(PML);
1800 
1801  return pt_out;
1802 }
1803 
1804 /* Remove last subscripts of cell c till its type becomes a scalar
1805  * pointer.
1806  *
1807  * This of course may fail.
1808  */
1810 {
1811  bool to_be_freed;
1812  type t = points_to_cell_to_type(c, &to_be_freed);
1814  list sl = reference_indices(r);
1815  bool remove_p = !pointer_type_p(t);
1816  if(to_be_freed) free_type(t);
1817  while(remove_p) {
1818  if(!ENDP(sl)) {
1819  /* Remove the last subscript, hopefully 0 */
1820  list ls = gen_last(sl); // last subscript
1821  expression lse = EXPRESSION(CAR(ls));
1823  break; // This subscript cannot be removed
1824  gen_list_and_not(&sl, ls);
1825  reference_indices(r) = sl;
1826  // because sl is a sublist of ls, the chunk has already been freed
1827  // gen_full_free_list(ls);
1828  // gen_free_list(ls);
1829  t = points_to_cell_to_type(c, &to_be_freed);
1830  // remove_p = !pointer_type_p(t); we may end up with char[] instead of char*
1831  remove_p = !C_pointer_type_p(t);
1832  if(to_be_freed) free_type(t);
1833  }
1834  else
1835  break; // FI: in fact, an internal error
1836  }
1837  return c;
1838 }
1839 
1840 /* Undo the extra eval performed when stubs are generated: 0
1841  * subscripts are added when arrays are involved.
1842  *
1843  */
1845 {
1846  FOREACH(CELL, c, cl) {
1847  if(null_cell_p(c)) // There may be other exceptions...
1848  ;
1849  else
1850  (void) reduce_cell_to_pointer_type(c);
1851  }
1852  return cl;
1853 }
1854 ␌
1855 /* Returns a list of cells of pointer type which are included in cell
1856  * "c". Useful when "c" is a struct or an array of structs or
1857  * pointers. Returns a list with cell "c" if it denotes a pointer.
1858  *
1859  * If set "pt" is defined, make sure that each cell in the returned
1860  * list, "pcl" appears in "pt".
1861  */
1863 {
1864  list pcl = NIL; // pointer cell list
1866  if(pointer_type_p(c_t) && cell_in_points_to_set_p(c, pts)) {
1867  cell nc = copy_cell(c);
1868  pcl = CONS(CELL, nc, pcl);
1869  }
1870  else if(struct_type_p(c_t)) {
1871  /* Look for pointer and struct and array of pointers or struct fields */
1872  list fl = struct_type_to_fields(c_t);
1873  FOREACH(ENTITY, f, fl) {
1875  if(pointer_type_p(f_t) || struct_type_p(f_t)
1876  || array_of_pointers_type_p(f_t)
1877  || array_of_struct_type_p(f_t)) {
1878  cell nc = copy_cell(c);
1880  // FI: possible memory leak for nc;
1881  // If it is not a pointer, it should be freed
1882  // If it is a pointer, it might be useful or not
1884  pcl = gen_nconc(pcl, ppcl);
1885  // If nc is not in pcl, it should be free
1886  }
1887  }
1888  }
1889  else if(array_of_pointers_type_p(c_t) || array_of_struct_type_p(c_t)) {
1890  /* transformer */
1891  cell nc = copy_cell(c);
1894  // FI: should nc be freed or not ?
1895  // If nc is not in pcl, it should be free
1896  }
1897  return pcl;
1898 }
1899 
1901 {
1903 }
1904 
1906 {
1908 }
1909 
1910 
1911 
1912 /* Convert cells in l into derived pointer cells when possible
1913  *
1914  * The elements of list pl are reused in list l
1915  *
1916  */
1918 {
1919  list l = NIL;
1920  FOREACH(CELL, pc, pl) {
1922  l = gen_nconc(l, nl);
1923  }
1924  return l;
1925 }
1926 
1927 /* Cell "l" has been memory leaked for sure and is not referenced any
1928  more in "in". Its successors may be leaked too. */
1930 {
1931  pt_map out = in;
1932  // potential memory leaks
1934  FOREACH(CELL, c, pml) {
1935  // This first test is probably useless because if has been
1936  // partially or fully performed by the caller
1937  if(heap_cell_p(c) && unreachable_points_to_cell_p(c, in)) {
1938  /* Remove useless unreachable arcs */
1939  list dl = NIL, npml = NIL;
1940  set out_s = points_to_graph_set(out);
1941  SET_FOREACH(points_to, pt, out_s) {
1942  cell source = points_to_source(pt);
1943  // FI: a weaker test based on the lattice is needed
1944  if(points_to_cell_equal_p(source, c)) {
1945  dl = CONS(POINTS_TO, pt, dl);
1946  cell sink = points_to_sink(pt);
1947  npml = CONS(CELL, sink, npml);
1948  // FI: we need to remove pt before we can test for unreachability...
1949  /*
1950  if(heap_cell_p(sink) && unreachable_points_to_cell_p(sink, out)) {
1951  pips_user_warning("Heap bucket \"%s\" leaked at line %d.\n",
1952  points_to_cell_to_string(sink),
1953  points_to_context_statement_line_number());
1954  */
1955  }
1956  }
1957  FOREACH(POINTS_TO, d, dl)
1959  gen_free_list(dl);
1960 
1961  FOREACH(CELL, sink, npml) {
1962  if(heap_cell_p(sink) && unreachable_points_to_cell_p(sink, out)) {
1963  if(false)
1964  pips_user_warning("Heap bucket \"%s\" leaked.\n",
1965  points_to_cell_to_string(sink));
1966  else
1967  pips_user_warning("Heap bucket \"%s\" leaked at line %d.\n",
1970  /* Look for a chain of memory leaks */
1971  //if(!points_to_cell_equal_p(c, l))
1973  }
1974  }
1975  gen_free_list(npml);
1976  }
1977  }
1978  return out;
1979 }
1980 
1981 ␌
1982 /* Update "pt_out" when any element of L can be assigned any element of R
1983  *
1984  * FI->AM: Potential and sure memory leaks are not (yet) detected.
1985  *
1986  ******************************************
1987  *
1988  * FI->AM: the distinction between may and must sets used in the
1989  * implementation seem useless.
1990  *
1991  * Old description by Amira:
1992  *
1993  * KILL_MAY = kill_may_set()
1994  * KILL_MUST= kill_must_set()
1995  *
1996  * GEN_MAY = gen_may_set()
1997  * GEN_MUST= gen_must_set()
1998  *
1999  * KILL = KILL_MAY U KILL_MUST
2000  * GEN = GEN_MAY U GEN_MUST
2001  * PT_OUT = (PT_OUT - KILL) U GEN
2002  *
2003  ******************************************
2004  *
2005  * This function is used to model a C pointer assignment "e1 = e2;"
2006  *
2007  * Let L = expression_to_sources(e1) and R = expression_to_sinks(e2).
2008  *
2009  * Let "in" be the points-to relation before executing the assignment.
2010  *
2011  * Gen(L,R) = {pts| exist l in L exists r in R s.t. pts=(l,r,|L|=1)
2012  *
2013  * Kill(L,in) = {pts=(l,sink,must)| l in L}
2014  *
2015  * Let K=Kill(L,in) and out = (in-K) U gen(L,R)
2016  *
2017  * For memory leaks, let
2018  *
2019  * ML(K,out) = {c in Heap | exists pts=(l,c,a) in K
2020  * && !(exists pts'=(l',c,a') in out)}
2021  *
2022  * For error dereferencing, such as nowhere/undefined and NULL, check
2023  * the content of L.
2024  *
2025  * This function is described in Amira Mensi's dissertation.
2026  *
2027  * Test cases designed to check the behavior of this function: ?!?
2028  */
2030 {
2031  pips_assert("This function is not called with a bottom points-to",
2032  !points_to_graph_bottom(pt_out));
2033 
2034  pips_assert("pt_out is consistent on entry",
2036 
2037  /* Check possible dereferencing errors */
2038  list ndl = NIL; // null dereferencing error list
2039  list udl = NIL; // undefined dereferencing error list
2040  // FI->AM: you have no way to know if stubs are atomic or not...
2041  // I am not sure the atomic predicate takes this into account
2042  // but it does not really matter intraprocedurally: stubs are atomic
2043  bool singleton_p = (gen_length(L)==1
2044  && generic_atomic_points_to_cell_p(CELL(CAR(L)), false));
2045  FOREACH(CELL, c, L) {
2046  if(nowhere_cell_p(c)){
2047  udl = CONS(CELL, c, udl);
2048  if(singleton_p)
2049  // Not necessarily a user error if the code is dead
2050  // Should be controlled by an extra property...
2051  pips_user_warning("Dereferencing of an undefined pointer \"%s\" at line %d.\n",
2054  else
2055  pips_user_warning("Possible dereferencing of an undefined pointer.\n");
2056  }
2057  else if(null_cell_p(c)) {
2058  ndl = CONS(CELL, c, ndl);
2059  if(singleton_p)
2060  // Not necessarily a user error if the code is dead
2061  // Should be controlled by an extra property...
2062  pips_user_warning("Dereferencing of a null pointer \"%s\" at line %d.\n",
2065  else
2066  pips_user_warning("Possible dereferencing of a null pointer \"%s\" at line %d.\n",
2069  }
2070  else {
2071  /* For arrays, an extra eval has been applied by adding 0 subscripts */
2072  cell nc = copy_cell(c); // FI: for debugging purpose
2075  if(!C_pointer_type_p(ct) && !overloaded_type_p(ct)) {
2076  fprintf(stderr, "nc=");
2078  fprintf(stderr, "\nc=");
2080  pips_internal_error("\nSource cell cannot really be a source cell\n");
2081  }
2082  free_cell(nc);
2083  }
2084  }
2085 
2086  pips_assert("pt_out is consistent", consistent_points_to_graph_p(pt_out));
2087 
2088  if(!ENDP(ndl) || !ENDP(udl)) {
2089  if(!ENDP(ndl))
2090  pips_user_warning("Possible NULL pointer dereferencing.\n");
2091  else
2092  pips_user_warning("Possible undefined pointer dereferencing.\n");
2093 
2094  /* What do we want to do when the left hand side is NULL or UNDEFINED? */
2095  bool null_dereferencing_p
2096  = get_bool_property("POINTS_TO_NULL_POINTER_DEREFERENCING");
2097  bool nowhere_dereferencing_p
2098  = get_bool_property("POINTS_TO_UNINITIALIZED_POINTER_DEREFERENCING");
2099  if(!null_dereferencing_p) {
2100  gen_list_and_not(&L, ndl);
2101  if(!nowhere_dereferencing_p) {
2102  gen_list_and_not(&L, udl);
2103  }
2104 
2105  // FI: I guess all undefined and nowhere cells in L should be
2106  // removed and replaced by only one anywhere cell
2107  // FI: it should be typed according to the content of the cells in del
2108 
2109  if(!ENDP(ndl) && null_dereferencing_p) {
2110  cell nc = CELL(CAR(ndl));
2113  gen_list_and_not(&L, ndl);
2114  L = CONS(CELL, c, L);
2115  }
2116 
2117  if(!ENDP(udl) && nowhere_dereferencing_p) {
2118  cell nc = CELL(CAR(udl));
2121  gen_list_and_not(&L, udl);
2122  L = CONS(CELL, c, L);
2123  }
2124 
2125  gen_free_list(ndl), gen_free_list(udl);
2126  }
2127  }
2128 
2129  if(ENDP(L)) {
2130  /* The code cannot be executed */
2131  clear_pt_map(pt_out);
2132  points_to_graph_bottom(pt_out) = true;
2133  }
2134  else {
2135  /* Compute the data-flow equation for the may and the must edges...
2136  *
2137  * out = (in - kill) U gen ?
2138  */
2139 
2140  /* Extract MAY/MUST points to relations from the input set "pt_out" */
2141  set pt_out_s = points_to_graph_set(pt_out);
2142  set in_may = points_to_may_filter(pt_out_s);
2143  set in_must = points_to_must_filter(pt_out_s);
2144  //set kill_may = kill_may_set(L, in_may);
2145  // Arcs whose approximation must be changed
2146  set kill_may = kill_may_set(L, in_must);
2147  // Arcs that are definitely killed
2148  set kill_must = kill_must_set(L, pt_out_s);
2149  // FI: easiest way to find the proper set "kill_may"
2150  kill_may = set_difference(kill_may, kill_may, kill_must);
2151  bool address_of_p = true;
2152  // gen_may = gen_2 in the dissertation
2153  set gen_may = gen_may_set(L, R, pt_out_s, &address_of_p);
2154  // set gen_must = gen_must_set(L, R, in_must, &address_of_p);
2155  //set kill/* = new_pt_map()*/;
2156  set kill = new_simple_pt_map();
2157  // FI->AM: do we really want to keep the same arc with two different
2158  // approximations? The whole business of may/must does not seem
2159  // useful.
2160  //kill = set_union(kill, kill_may, kill_must);
2161  // kill_may is handled direclty below
2162  kill = kill_must;
2164  //set_union(gen, gen_may, gen_must);
2165  set_assign(gen, gen_may);
2166 
2167  pips_assert("\"gen\" is consistent", consistent_points_to_set(gen));
2168 
2169  if(set_empty_p(gen)) {
2170  bool type_sensitive_p = !get_bool_property("ALIASING_ACROSS_TYPES");
2171  if(type_sensitive_p)
2172  gen = points_to_anywhere_typed(L, pt_out_s);
2173  else
2174  gen = points_to_anywhere(L, pt_out_s);
2175  }
2176 
2177  // FI->AM: shouldn't it be a kill_must here?
2178  set_difference(pt_out_s, pt_out_s, kill);
2179 
2180  pips_assert("After removing the kill set, pt_out is consistent",
2182 
2183  set_union(pt_out_s, pt_out_s, gen);
2184 
2185  // FI->AM: use kill_may to reduce the precision of these arcs
2186  // Easier than to make sure than "gen_may1", i.e. "gen_1" in the
2187  // dissertation, is consistent with "kill_may", i.e. kill_2 in the
2188  // dissertation
2189 
2190  SET_FOREACH(points_to, pt, kill_may) {
2192  if(approximation_exact_p(a)) {
2197  remove_arc_from_pt_map(pt, pt_out);
2198  add_arc_to_pt_map(npt, pt_out);
2199  }
2200  }
2201 
2202  pips_assert("After union and approximation updates pt_out is consistent",
2204 
2205  /* Check kill_must for potential memory leaks */
2206  SET_FOREACH(points_to, kpt, kill_must) {
2207  cell d = points_to_sink(kpt);
2208  //approximation ap = points_to_approximation(kpt);
2209  // approximation_exact_p(ap) && : this is incompatible with heap_cell_p
2210  if(heap_cell_p(d)
2211  && unreachable_points_to_cell_p(d, pt_out)) {
2212  /* FI: this error message may be wrong in case of a call to
2213  * realloc(); see Pointers/hyantes02.c, hyantes03.c
2214  *
2215  * FI: this error message may deal with a bucket that does not
2216  * really exist because its allocation was conditional.
2217  *
2218  * To make things worse, the warning is emitted in an
2219  * iterative loop analysis.
2220  */
2221  pips_user_warning("Heap bucket \"%s\" %sleaked at line %d.\n",
2223  set_size(kill_must)>1? "possibly " : "",
2225 
2226  /* Look for a chain of memory leaks. Since they are also
2227  "related" to "d", this must be done before the next
2228  step. */
2229  pt_out = memory_leak_to_more_memory_leaks(d, pt_out);
2230 
2231  /* Look for related lost arcs. See Pointers/malloc18.c */
2232  reference dr = cell_any_reference(d);
2233  entity dv = reference_variable(dr);
2234  // cell nd = make_cell_reference(make_reference(dv, NIL));
2235  //points_to_cell_add_unbounded_subscripts(nd);
2236  list dal = NIL; // Deleted arc list
2237  SET_FOREACH(points_to, pt, pt_out_s) {
2238  cell s = points_to_source(pt);
2239  reference sr = cell_any_reference(s);
2240  entity sv = reference_variable(sr);
2241  if(dv==sv) {
2242  if(unreachable_points_to_cell_p(s, pt_out))
2243  dal = CONS(POINTS_TO, pt, dal);
2244  }
2245  }
2246  FOREACH(POINTS_TO, da, dal)
2247  remove_arc_from_pt_map(da, pt_out);
2248  gen_free_list(dal);
2249  }
2250  }
2251 
2252  sets_free(in_may, in_must,
2253  kill_may, kill_must,
2254  gen_may, /*gen_must,*/
2255  gen,/* kill,*/ NULL);
2256  // clear_pt_map(pt_out); // FI: why not free?
2257  }
2258 
2259  return pt_out;
2260 }
2261 
2263  expression rhs,
2264  pt_map in)
2265 {
2266  pt_map out = in;
2267  // Implementation 0:
2268  // pips_internal_error("Not implemented yet.\n");
2269  // pips_assert("to please gcc, waiting for implementation", lhs==rhs && in==in);
2271 
2272  // L must contain a unique cell, containing a non-index reference
2273  pips_assert("One struct to initialize", (int) gen_length(L)==1);
2274  cell c = CELL(CAR(L));
2276  entity e = reference_variable(r);
2277  pips_assert("c is not indexed", ENDP(reference_indices(r)));
2278  if(0) {
2279  /* Temporary implementation: use anywhere as default initialization */
2280  // ignore rhs
2282  FOREACH(CELL, source, l) {
2283  bool to_be_freed;
2284  type t = points_to_cell_to_type(source, &to_be_freed);
2286  cell sink = make_anywhere_cell(c_t);
2287  if(to_be_freed) free_type(t);
2288  points_to pt = make_points_to(source, sink,
2291  add_arc_to_pt_map(pt, out);
2292  }
2293  }
2294  else {
2295  /* We must assign to each relevant field its initial value */
2296  list fl = struct_variable_to_fields(e); // list of entities
2298  pips_assert("The field and initial value lists have the same length",
2299  gen_length(fl)==gen_length(vl));
2300  list cvl = vl;
2301  FOREACH(ENTITY, f, fl) {
2302  reference nr =
2305  out = assignment_to_points_to(nlhs, EXPRESSION(CAR(cvl)), out);
2306  POP(cvl);
2307  }
2308  }
2309 
2310  return out;
2311 }
2312 
2313 /* pt_in is modified by side-effects and returned as pt_out
2314  *
2315  * This function is also used for declarations, although the syntax
2316  * for declarations is reacher than the syntax for assignments which
2317  * can use BRACE_INTRINSIC.
2318  */
2320  expression rhs,
2321  pt_map pt_in)
2322 {
2323  pt_map pt_out = pt_in;
2325  pt_out = struct_initialization_to_points_to(lhs, rhs, pt_in);
2326  else {
2327  list L = expression_to_points_to_sources(lhs, pt_out);
2328  list R = expression_to_points_to_sources(rhs, pt_out);
2329  FOREACH(CELL, lc, L) {
2330  bool l_to_be_freed;
2331  type lt = cell_to_type(lc, &l_to_be_freed);
2333  if(!entity_abstract_location_p(le)) {
2334  FOREACH(CELL, rc, R) {
2335  bool r_to_be_freed;
2336  type rt = cell_to_type(rc, &r_to_be_freed);
2338  if(entity_abstract_location_p(le)) {
2339  if(entity_abstract_location_p(re)) {
2340  pips_internal_error("Not implemented yet.");
2341  }
2342  else {
2343  pips_internal_error("Not implemented yet.");
2344  }
2345  }
2346  else {
2347  if(entity_abstract_location_p(re)) {
2348  // FI: when re==NULL, we could generate a user warning or
2349  // ignore the dereferencement of NULL...
2350 
2351  // All fields are going to point to this abstract
2352  // location... or to the elements pointed by this abstract
2353  // location
2354  pips_assert("Left type is struct",
2355  struct_type_p(lt));
2357  type st = entity_type(ste); // structure type
2358  list fl = type_struct(st); // field list
2359  FOREACH(ENTITY, f, fl) {
2360  type ft = entity_type(f); // field type
2361  if(pointer_type_p(ft)) {
2363  // reference rr = copy_reference(cell_any_reference(rc));
2365  cell lc = make_cell_reference(lr);
2366  type p_t = type_to_pointed_type(ft);
2367  cell rc = make_anywhere_cell(p_t);
2368  // reference_add_field_dimension(rr, f);
2369  // expression nlhs = reference_to_expression(lr);
2370  // expression nrhs = reference_to_expression(rr);
2371 
2372  // FI: too bad this cannot be reused because of an assert in normalize_reference()....
2373  // pt_out = assignment_to_points_to(nlhs, nrhs, pt_out);
2375  // FI: pt is allocated but not used...
2376  // FI: see update_points_to_graph_with_arc()?
2377  /* Current arc list (cal): the new arc may be
2378  conflicting with an existing must arc */
2379  list cal = points_to_source_to_arcs(lc, pt_out, false);
2380  list oal = NIL;
2381  list nal = NIL;
2382  FOREACH(POINTS_TO, a, cal) {
2384  if(approximation_exact_p(ap)) {
2385  oal = CONS(POINTS_TO, a, oal);
2386  points_to na =
2391  nal = CONS(POINTS_TO, na, nal);
2392  }
2393  }
2394  FOREACH(POINTS_TO, oa, oal)
2395  remove_arc_from_pt_map(oa, pt_out);
2396  FOREACH(POINTS_TO, na, nal)
2397  add_arc_to_pt_map(na, pt_out);
2398  gen_free_list(oal), gen_free_list(nal);
2399  add_arc_to_pt_map(pt, pt_out); // FI: I guess...
2400  // FI->FC: it would be nice to have a Newgen free_xxxxs() to
2401  // free a list of objects of type xxx with one call
2402  // FI: why would we free these expressions?
2403  // free_expression(lhs), free_expression(rhs);
2404  }
2405  else if(struct_type_p(ft)) {
2406  pips_internal_error("Not implemented yet.\n");
2407  }
2408  else {
2409  ; // Do nothing
2410  }
2411  }
2412  }
2413  else {
2414  pips_assert("Both types are struct or array of struct",
2416  && (struct_type_p(rt) || array_of_struct_type_p(rt)));
2417  /* We may have an implicit array of struct in the right or
2418  * left hand side
2419  */
2420  // pips_assert("Both type are equal", type_equal_p(lt, rt));
2421  basic ltb = variable_basic(type_variable(lt));
2422  basic rtb = variable_basic(type_variable(rt));
2423  pips_assert("Both type are somehow equal",
2424  basic_equal_p(ltb, rtb));
2426  type st = entity_type(ste); // structure type
2427  list fl = type_struct(st); // field list
2428  FOREACH(ENTITY, f, fl) {
2429  type uft = entity_basic_concrete_type(f); // field type
2430  // type uft = ultimate_type(ft);
2431  bool array_p = /*array_type_p(ft) ||*/ array_type_p(uft);
2432  if(!array_p && (pointer_type_p(uft) || struct_type_p(uft))) {
2435  /* FI: conditionally add zero subscripts necessary to
2436  move from an array "a" to its first element,
2437  e.g. a[0][0][0] */
2444  pt_out = assignment_to_points_to(nlhs, nrhs, pt_out);
2445  // FI->FC: it would be nice to have a Newgen free_xxxxs() to
2446  // free a list of objects of type xxx with one call
2447  // The references within the expressions are now part of pt_out
2448  // free_expression(lhs), free_expression(rhs);
2449  }
2450  else if(array_p && (array_of_pointers_type_p(uft)
2451  || pointer_type_p(uft)
2452  || array_of_struct_type_p(uft)
2453  || struct_type_p(uft))) {
2454  // Same as above, but an unbounded subscript is added...
2455  // Quite a special assign in C...
2463  CONS(EXPRESSION, li, NIL));
2465  CONS(EXPRESSION, ri, NIL));
2468  pt_out = assignment_to_points_to(nlhs, nrhs, pt_out);
2469  }
2470  else {
2471  ; // Do nothing
2472  }
2473  }
2474  }
2475  }
2476  }
2477  }
2478  else {
2479  // FI: the lhs is an unknown struct allocated anywhere
2480  // FI: we might have to generate new arcs. e.g. from HEAP to STACK...
2481  pips_internal_error("Not implemented yet.\n");
2482  }
2483  }
2484  }
2485  // pips_internal_error("Not implemented yet for lhs %p and rhs %p\n", lhs, rhs);
2486 
2487  return pt_out;
2488 }
2489 
2490 pt_map application_to_points_to(application a, pt_map pt_in, bool side_effect_p)
2491 {
2493  list al = application_arguments(a);
2494  pt_map pt_out = expression_to_points_to(f, pt_in, side_effect_p);
2495 
2496  pt_out = expressions_to_points_to(al, pt_out, side_effect_p);
2497  /* FI: We should also identify the possibly called functions and
2498  update the points-to according to the possible call sites. */
2499  pips_internal_error("Not implemented yet for application\n");
2500 
2501  return pt_out;
2502 }
2503 ␌
2504 /* Update points-to set "in" according to the content of the
2505  * expression using side effects. Use "true_p" to know if the
2506  * condition must be met or not.
2507  *
2508  * FI: the side effects should not be taken into account because this
2509  * function is often called twice, once for the true branch and once
2510  * for the false branch of a test.
2511  */
2513 {
2514  pt_map out = in;
2515  if(!points_to_graph_bottom(in)) {
2516  syntax cs = expression_syntax(c);
2517 
2518  if(syntax_reference_p(cs)) {
2519  /* For instance, C short cut "if(p)" for "if(p!=NULL)" */
2520  //out = reference_condition_to_points_to(syntax_reference(cs), in, true_p);
2522  }
2523  else if(syntax_call_p(cs)) {
2524  //list el = expression_to_proper_constant_path_effects(c);
2525  list el = NIL;
2526  out = call_condition_to_points_to(syntax_call(cs), in, el, true_p);
2527  //gen_full_free_list(el);
2528  }
2529  else {
2530  pips_internal_error("Not implemented yet.\n");
2531  }
2532  }
2533  pips_assert("out is consistent", points_to_graph_consistent_p(out));
2534  return out;
2535 }
2536 
2537 /* Handle conditions such as "if(p)" */
2539 {
2540  pt_map out = in;
2541  entity v = reference_variable(r);
2543  list sl = reference_indices(r);
2544 
2545  /* Do not take care of side effects in references... */
2546  out = expressions_to_points_to(sl, out, false);
2547 
2548  /* are we dealing with a pointer? */
2549  if(pointer_type_p(vt)) {
2550  if(true_p) {
2551  /* if p points to NULL, the condition is not feasible. If not,
2552  remove any arc from p to NULL */
2553  if(reference_must_points_to_null_p(r, in)) {
2554  // FI: memory leak with clear_pt?
2555  pips_user_warning("Dead code detected.\n");
2556  clear_pt_map(out);
2557  points_to_graph_bottom(out) = true;
2558  }
2559  else {
2560  /* Make a points-to NULL and remove the arc from the current out */
2563  points_to a = make_points_to(source, sink, make_approximation_may(),
2565  remove_arc_from_pt_map(a, in);
2566  free_points_to(a);
2567  }
2568  }
2569  else {
2570  if(reference_may_points_to_null_p(r, in)) {
2571  /* remove any arc from v to anything and add an arc from p to NULL */
2572  set in_s = points_to_graph_set(in);
2573  points_to_source_projection(in_s, v);
2574  /* Make a points-to NULL and remove the arc from the current out */
2579  add_arc_to_pt_map(a, in);
2580  }
2581  else {
2582  /* This condition is always false */
2583  pips_user_warning("Dead code detected.\n");
2584  clear_pt_map(out);
2585  points_to_graph_bottom(out) = true;
2586  }
2587  }
2588  }
2589 
2590  return out;
2591 }
2592 
2593 /* Handle any condition that is a call such as "if(p!=q)", "if(*p)",
2594  * "if(foo(p=q))"... */
2596 {
2597  pt_map out = in;
2598  entity f = call_function(c);
2599  value fv = entity_initial(f);
2600  if(value_intrinsic_p(fv))
2601  out = intrinsic_call_condition_to_points_to(c, in, true_p);
2602  else if(value_code_p(fv))
2603  out = user_call_condition_to_points_to(c, in, el, true_p);
2604  else if(value_constant_p(fv)) {
2605  // For instance "if(1)"
2606  ; // do nothing
2607  }
2608  else
2609  // FI: you might have an apply on a functional pointer?
2610  pips_internal_error("Not implemented yet.\n");
2611  pips_assert("out is consistent", points_to_graph_consistent_p(out));
2612  return out;
2613 }
2614 
2615 /* We can break down the intrinsics according to their arity or
2616  * according to their kinds... or according to both conditions...
2617  */
2619 {
2620  pt_map out = in;
2621  entity f = call_function(c);
2622 
2625  else if(ENTITY_LOGICAL_OPERATOR_P(f))
2627  else if(ENTITY_ASSIGN_P(f)) {
2628  // Evaluate side effects only once...
2629  out = intrinsic_call_to_points_to(c, in, true_p);
2631  //bool to_be_freed;
2633  //type lhs_t = compute_basic_concrete_type(t);
2634  //if(to_be_freed) free_type(t);
2635  if(pointer_type_p(lhs_t)) {
2638  if(cells_must_point_to_null_p(R) && true_p) {
2639  pips_user_warning("Dead code detected.\n");
2640  clear_pt_map(out);
2641  points_to_graph_bottom(out) = true;
2642  }
2643  else if(cells_may_not_point_to_null_p(R) && !true_p) {
2644  pips_user_warning("Dead code detected.\n");
2645  clear_pt_map(out);
2646  points_to_graph_bottom(out) = true;
2647  }
2648  gen_free_list(R);
2649  }
2650  }
2651  else {
2656  /* Make sure that all dereferencements are possible? Might be
2657  included in intrinsic_call_to_points_to()... */
2658  //bool to_be_freed;
2660  if(pointer_type_p(et)) {
2662  out = condition_to_points_to(p, out, true_p);
2663  }
2664  //if(to_be_freed) free_type(et);
2665  }
2666  // Take care of side effects as in "if(*p++)"
2667  // We must take care of side effects only once...
2668  // Let say, when the condition is evaluated for true
2669  // Not too sure about side effects in condtions
2670  // We might also use "false" as last actual parameter...
2671  // FI: no, this has been taken care of earlier
2672  out = intrinsic_call_to_points_to(c, in, false);
2673  //pips_internal_error("Not implemented yet.\n");
2674  }
2675  pips_assert("out is consistent", points_to_graph_consistent_p(out));
2676  return out;
2677 }
2678 
2680 {
2681  pt_map out = in;
2682  // FI: a call site to handle like any other user call site...
2683  // Althgouh you'd like to know if true or false is returned...
2684  //pips_user_warning("Interprocedural points-to not implemented yet. "
2685  // "Call site fully ignored.\n");
2686  //
2687  if(true_p) // Analyze the call only once?
2688  out = user_call_to_points_to(c, in, el);
2689  else // No, because side-effects must be taken into account for both branches
2690  out = user_call_to_points_to(c, in, el);
2691  return out;
2692 }
2693 
2694 /* Deal with "!", "&&", "||" etc. */
2696 {
2697  entity f = call_function(c);
2698  list al = call_arguments(c);
2699  pt_map out = in;
2700  if(ENTITY_NOT_P(f)) {
2701  expression nc = EXPRESSION(CAR(al));
2702  out = condition_to_points_to(nc, in, !true_p);
2703  }
2704  else if((ENTITY_AND_P(f) && true_p) || (ENTITY_OR_P(f) && !true_p)) {
2705  /* Combine the conditions */
2706  expression nc1 = EXPRESSION(CAR(al));
2707  out = condition_to_points_to(nc1, in, true_p);
2708  expression nc2 = EXPRESSION(CAR(CDR(al)));
2709  out = condition_to_points_to(nc2, out, true_p);
2710  }
2711  else if((ENTITY_AND_P(f) && !true_p) || (ENTITY_OR_P(f) && true_p)) {
2712  /* Merge the results of the different conditions... */
2713  pt_map in2 = full_copy_pt_map(in);
2714  expression nc1 = EXPRESSION(CAR(al));
2715  pt_map out1 = condition_to_points_to(nc1, in, true_p);
2716  expression nc2 = EXPRESSION(CAR(CDR(al)));
2717  pt_map out2 = condition_to_points_to(nc2, in2, true_p);
2718  // FI: memory leak? Does merge_points_to_set() allocated a new set?
2719  out = merge_points_to_graphs(out1, out2);
2720  clear_pt_map(out2); // FI: you do no want to free the arcs
2721  free_pt_map(out2);
2722  }
2723  else
2724  pips_internal_error("Not implemented yet for boolean operator \"%s\".\n",
2725  entity_local_name(f));
2726  pips_assert("out is consistent", points_to_graph_consistent_p(out));
2727  return out;
2728 }
2729 ␌
2730 /* See if you can decide that the addresses linked to c1 are xxx
2731  * than the addresses linked to c2.
2732  *
2733  * True is returned when a decision can be made.
2734  *
2735  * False is returned when no decision can be made.
2736  */
2737 #define LESS_THAN 0
2738 #define LESS_THAN_OR_EQUAL_TO 1
2739 #define GREATER_THAN 2
2740 #define GREATER_THAN_OR_EQUAL_TO 3
2741 
2742 static bool cell_is_xxx_p(cell c1, cell c2, int xxx)
2743 {
2744  bool xxx_p = true;
2745  reference r1 = cell_any_reference(c1);
2746  reference r2 = cell_any_reference(c2);
2747  entity v1 = reference_variable(r1);
2748  entity v2 = reference_variable(r2);
2749  if(v1!=v2) {
2750  xxx_p = false; // FI: useless, but the pips_user_error() may be removed
2751  pips_user_error("Incomparable pointers to \"%s\" and \"%s\" are compared.\n",
2752  reference_to_string(r1),
2753  reference_to_string(r2));
2754  }
2755  else {
2756  /* You must compare the subscript expressions lexicographically */
2757  list sl1 = reference_indices(r1), sl1c = sl1;
2758  list sl2 = reference_indices(r2), sl2c = sl2;
2759  for(sl1c = sl1;
2760  !ENDP(sl1c) && !ENDP(sl2c) && xxx_p;
2761  sl1c = CDR(sl1c), sl2c = CDR(sl2c)) {
2762  expression s1 = EXPRESSION(CAR(sl1c));
2763  expression s2 = EXPRESSION(CAR(sl2c));
2765  xxx_p = false;
2766  else {
2767  value v1 = EvalExpression(s1);
2768  value v2 = EvalExpression(s2);
2769  if(!value_constant_p(v1) || !value_constant_p(v2)) {
2770  // FI: this should be a pips_internal_error due to
2771  // constraints on points_to sets
2772  xxx_p = false;
2773  pips_internal_error("Unexpected subscripts in points-to.\n");
2774  }
2775  else {
2776  constant c1 = value_constant(v1);
2777  constant c2 = value_constant(v2);
2778  if(!constant_int_p(c1) || !constant_int_p(c2)) {
2779  xxx_p = false;
2780  pips_internal_error("Unexpected subscripts in points-to.\n");
2781  }
2782  else {
2783  int i1 = constant_int(c1);
2784  int i2 = constant_int(c2);
2785  // FI: you should break when i1<i2
2786  switch(xxx) {
2787  case LESS_THAN:
2788  xxx_p = (i1<i2);
2789  break;
2790  case LESS_THAN_OR_EQUAL_TO:
2791  xxx_p = (i1<=i2);
2792  break;
2793  case GREATER_THAN:
2794  xxx_p = (i1>i2);
2795  break;
2797  xxx_p = (i1>=i2);
2798  break;
2799  default:
2800  pips_internal_error("Unknown comparison.\n");
2801  }
2802  }
2803  }
2804  }
2805  }
2806  // FI: Not good for a lexicographic order, might need equal_p as
2807  // well, but sufficient for arithmetic02
2808  //if(xxx_p && !ENDP(sl1c))
2809  // xxx_p = false;
2810  }
2811  return xxx_p;
2812 }
2813 /* See if you can decide that the addresses linked to c1 are smaller
2814  * than the addresses linked to c2.
2815  *
2816  * True is returned when a decision can be made.
2817  *
2818  * False is returned when no decision can be made.
2819  */
2821 {
2822  return cell_is_xxx_p(c1, c2, LESS_THAN_OR_EQUAL_TO);
2823 }
2824 
2826 {
2827  return cell_is_xxx_p(c1, c2, LESS_THAN);
2828 }
2829 
2831 {
2832  return cell_is_xxx_p(c1, c2, GREATER_THAN_OR_EQUAL_TO);
2833 }
2834 
2836 {
2837  return cell_is_xxx_p(c1, c2, GREATER_THAN);
2838 }
2839 ␌
2840 /* The condition is e==NULL
2841  *
2842  * e==NULL may be true if exists c in sinks(e) s.t. {NULL} is included in c.
2843  * else e==NULL must be false.
2844  *
2845  * Some arcs in in may be removed: forall c in sources(e):
2846  *
2847  * out = in - {pt=(a,b) in in | a in sources(e) and b=NULL}
2848  */
2850 {
2851  pt_map out = in;
2852  type et = expression_to_type(e);
2853  if(pointer_type_p(et)) {
2855  bool null_initialization_p
2856  = get_bool_property("POINTS_TO_NULL_POINTER_INITIALIZATION");
2857 
2858  if(ENDP(R)) {
2859  // Maybe, a dereferencement user error occured?
2860  pips_internal_error("A dereferencement should always succeed.\n");
2861  }
2862 
2863  /* May the condition be true under "in"? */
2864  bool found_p = false;
2865  FOREACH(CELL, c, R) {
2866  if(null_cell_p(c)
2867  || anywhere_cell_p(c)
2869  /* If NULL initialization is not performed, a stub can
2870  represent a NULL. */
2871  || (!null_initialization_p && stub_points_to_cell_p(c))) {
2872  found_p = true;
2873  break;
2874  }
2875  }
2876  if(!found_p) {
2877  clear_pt_map(out);
2878  points_to_graph_bottom(out) = true;
2879  }
2880  else {
2881  /* Remove arcs incompatible with the condition e==NULL and add
2882  the arc e->NULL */
2884  pips_assert("A lhs expression has at least one source", !ENDP(L));
2885  int nL = (int) gen_length(L);
2886  cell fc = CELL(CAR(L));
2887  if(nL==1 && atomic_points_to_cell_p(fc)) {
2888  /* All arcs starting from fc can be removed and replaced by
2889  one arc from fc to NULL. */
2892  make_null_cell(),
2895  add_arc_to_pt_map(pt, out);
2896  }
2897  else {
2899  cell source = points_to_source(pt);
2900  if(cell_in_list_p(source, L)) {
2901  cell sink = points_to_sink(pt);
2902  if(!(null_cell_p(sink)
2903  || anywhere_cell_p(sink)
2904  || cell_typed_anywhere_locations_p(sink))) {
2906  }
2907  }
2908  }
2909  }
2910  }
2911  gen_free_list(R); // FI: should be full?
2912  }
2913  return out;
2914 }
2915 
2916 /* The condition is e!=NULL
2917  *
2918  * e!=NULL may be true if exists c in sinks(e) s.t. c != {NULL}
2919  *
2920  * e!=NULL is false if forall c in sinks(e) c is included in {NULL}
2921  *
2922  * Arcs that can be removed:
2923  *
2924  * FI: I decided not to merge this function with the previous one till
2925  * they are both fully defined and tested.
2926  */
2928 {
2929  pt_map out = in;
2930  type et = expression_to_type(e);
2931  if(pointer_type_p(et)) {
2933 
2934  if(ENDP(L)) {
2935  // Maybe, a dereferencement user error occured?
2936  pips_internal_error("A dereferencement should always succeed.\n");
2937  }
2938 
2939  /* May the condition be true under "in"? */
2940  bool found_p = false;
2941  FOREACH(CELL, c, L) {
2942  if(!null_cell_p(c)) {
2943  found_p = true;
2944  break;
2945  }
2946  }
2947  if(!found_p) {
2948  clear_pt_map(out);
2949  points_to_graph_bottom(out) = true;
2950  }
2951  else {
2952  /* Remove arcs incompatible with the condition e!=NULL */
2955  cell source = points_to_source(pt);
2956  if(cell_in_list_p(source, L)) {
2957  cell sink = points_to_sink(pt);
2958  if(null_cell_p(sink)) {
2960  }
2961  }
2962  }
2963  }
2964  }
2965  return out;
2966 }
2967 
2968 /* The expression list "al" contains exactly two arguments, "lhs" and
2969  * "rhs". Check if "lhs==rhs" may return true.
2970  *
2971  * If these expressions are pointers, "in" is modified by removing
2972  * arcs that are not compatible with the equality. If no arc is left, a
2973  * bottom "out" is returned.
2974  *
2975  * If one of these two expressions cannot be evaluated according to
2976  * the C standard, i.e. its value is undefined, a bottom graph is
2977  * returned.
2978  *
2979  * "out" is "in", modified by side-effects.
2980  *
2981  * This function has many commonalities with
2982  * non_equal_condition_to_points_to(). They were developped
2983  * independently to avoid mistakes when dealing with negations of
2984  * quantifiers. They could now be unified.
2985  */
2987 {
2988  pt_map out = in;
2989  expression lhs = EXPRESSION(CAR(al));
2990  expression rhs = EXPRESSION(CAR(CDR(al)));
2991 
2992  // FI: in fact, any integer could be used in a pointer comparison...
2993  if(expression_null_p(lhs))
2995  else if(expression_null_p(rhs))
2997  else {
2998  type lhst = expression_to_type(lhs);
2999  type rhst = expression_to_type(rhs);
3000  if(pointer_type_p(lhst) && pointer_type_p(rhst)) {
3002  int nL = (int) gen_length(L);
3003  /* Is it impossible to evaluate lhs?
3004  *
3005  * The check is too low. The message will be emitted twice
3006  * because conditions are often evaluated as true and false.
3007  */
3008  if(nL==1 && nowhere_cell_p(CELL(CAR(L)))) {
3009  clear_pt_map(out);
3010  points_to_graph_bottom(out) = true;
3011  pips_user_warning("Unitialized pointer is used to evaluate expression"
3012  " \"%s\" at line %d.\n", expression_to_string(lhs),
3014  }
3015  else {
3016  /* Is it impossible to evaluate rhs? */
3017  list R = expression_to_points_to_sinks(rhs, in);
3018  int nR = (int) gen_length(R);
3019  if(nR==1 && nowhere_cell_p(CELL(CAR(R)))) {
3020  clear_pt_map(out);
3021  points_to_graph_bottom(out) = true;
3022  pips_user_warning("Unitialized pointer is used to evaluate expression"
3023  " \"%s\".\n", expression_to_string(rhs),
3025  }
3026  else {
3027  /* Is the condition feasible? */
3028  bool equal_p = false;
3029  FOREACH(CELL, cl, L) {
3030  FOREACH(CELL, cr, R) {
3031  if(points_to_cells_intersect_p(cl, cr)) {
3032  equal_p = true;
3033  break;
3034  }
3035  }
3036  if(equal_p)
3037  break;
3038  }
3039  if(!equal_p) {
3040  // lhs==rhs is impossible
3041  clear_pt_map(out);
3042  points_to_graph_bottom(out) = true;
3043  }
3044  else {
3045  // It is possible to remove some arcs? if18.c
3046  int nL = (int) gen_length(L);
3047  int nR = (int) gen_length(R);
3048  cell c = cell_undefined;
3049  list O = list_undefined;
3050  if(nL==1 && atomic_points_to_cell_p(CELL(CAR(L)))) {
3051  c = CELL(CAR(L));
3053  }
3054  else if(nR==1 && atomic_points_to_cell_p(CELL(CAR(R)))) {
3055  c = CELL(CAR(R));
3057  }
3058  if(!cell_undefined_p(c)) {
3059  if((int) gen_length(O)==1) {
3060  cell oc = CELL(CAR(O));
3063  copy_cell(c),
3066  add_arc_to_pt_map(pt, out);
3067  }
3068  }
3069  }
3070  }
3071  }
3072  }
3073  free_type(lhst), free_type(rhst);
3074  }
3075  return out;
3076 }
3077 
3078 /* The expression list "al" contains exactly two arguments.
3079  *
3080  * If these expressions are pointers, "in" is modified by removing
3081  * arcs that are not compatible with the equality. If no arc is left, a
3082  * bottom "in" is returned.
3083  *
3084  * "out" is "in", modified by side-effects.
3085  */
3087 {
3088  // FI: this code is almost identical to the code above
3089  // It should be shared with a more general test first and then a
3090  // precise test to decide if you add or remove arcs
3091  pt_map out = in;
3092  expression lhs = EXPRESSION(CAR(al));
3093  expression rhs = EXPRESSION(CAR(CDR(al)));
3094 
3095  // FI: in fact, any integer could be used in a pointer comparison...
3096  if(expression_null_p(lhs))
3098  else if(expression_null_p(rhs))
3100  else {
3101  type lhst = expression_to_type(lhs);
3102  type rhst = expression_to_type(rhs);
3103  if(pointer_type_p(lhst) && pointer_type_p(rhst)) {
3105  list R = expression_to_points_to_sinks(rhs, in);
3106  //bool equal_p = false;
3107  int nL = (int) gen_length(L);
3108  int nR = (int) gen_length(R);
3109  pips_assert("The two expressions can be dereferenced", nL>=1 && nR>=1);
3110  if(nL==1 && nR==1) {
3111  cell cl = CELL(CAR(L));
3112  cell cr = CELL(CAR(R));
3113  /* Is the condition lhs!=rhs certainly impossible to evaluate?
3114  * If not, is it always false? */
3115  if((atomic_points_to_cell_p(cl)
3117  && points_to_cell_equal_p(cl, cr))
3118  || nowhere_cell_p(cl)
3119  || nowhere_cell_p(cr)) {
3120  // one or more expressions is not evaluable or the condition
3121  // is not feasible
3122  clear_pt_map(out);
3123  points_to_graph_bottom(out) = true;
3124  if(nowhere_cell_p(cl))
3125  pips_user_warning("Unitialized pointer is used to evaluate expression"
3126  " \"%s\" at line %d.\n",
3127  expression_to_string(lhs),
3129  if(nowhere_cell_p(cr))
3130  pips_user_warning("Unitialized pointer is used to evaluate expression"
3131  " \"%s\" at line %d.\n",
3132  expression_to_string(rhs),
3134  }
3135  }
3136  else {
3137  // It is possible to remove some arcs? if18.c
3138  int nL = (int) gen_length(L);
3139  int nR = (int) gen_length(R);
3140  cell c = cell_undefined;
3141  list O = list_undefined;
3142  if(nL==1 && atomic_points_to_cell_p(CELL(CAR(L)))) {
3143  c = CELL(CAR(L));
3145  }
3146  else if(nR==1 && atomic_points_to_cell_p(CELL(CAR(R)))) {
3147  c = CELL(CAR(R));
3149  }
3150  if(!cell_undefined_p(c)) {
3151  if((int) gen_length(O)==1) {
3152  cell oc = CELL(CAR(O));
3154  copy_cell(c),
3158  // Should we free pt? Or is it done by remove_arc_from_pt_map()?
3159  }
3160  }
3161  }
3162  }
3163  free_type(lhst), free_type(rhst);
3164  }
3165  return in;
3166 }
3167 
3168 /* The expression list "al" contains exactly two arguments.
3169  *
3170  * If these expressions are pointers, "in" is modified by removing
3171  * arcs that are not compatible with the equality. If no arc is left, a
3172  * bottom "in" is returned.
3173  *
3174  * "out" is "in", modified by side-effects.
3175  */
3177 {
3178  pt_map out = in;
3179  bool (*cmp_function)(cell, cell);
3180 
3181  if((ENTITY_LESS_OR_EQUAL_P(f) && true_p)
3182  || (ENTITY_GREATER_THAN_P(f) && !true_p)) {
3183  // cmp_function = cell_is_less_than_or_equal_to_p;
3184  cmp_function = cell_is_greater_than_p;
3185  }
3186  else if((ENTITY_LESS_OR_EQUAL_P(f) && !true_p)
3187  || (ENTITY_GREATER_THAN_P(f) && true_p)) {
3188  // cmp_function = cell_is_greater_than_p;
3189  cmp_function = cell_is_less_than_or_equal_to_p;
3190  }
3191  else if((ENTITY_GREATER_OR_EQUAL_P(f) && true_p)
3192  || (ENTITY_LESS_THAN_P(f) && !true_p)) {
3193  // cmp_function = cell_is_greater_than_or_equal_to_p;
3194  cmp_function = cell_is_less_than_p;
3195  }
3196  else if((ENTITY_GREATER_OR_EQUAL_P(f) && !true_p)
3197  || (ENTITY_LESS_THAN_P(f) && true_p)) {
3198  //cmp_function = cell_is_less_than_p;
3199  cmp_function = cell_is_greater_than_or_equal_to_p;
3200  }
3201  else {
3202  pips_internal_error("Unexpected relational operator.\n");
3203  cmp_function = NULL;
3204  }
3205 
3206  expression lhs = EXPRESSION(CAR(al));
3207  type lhst = expression_to_type(lhs);
3208  expression rhs = EXPRESSION(CAR(CDR(al)));
3209  type rhst = expression_to_type(rhs);
3210  if(pointer_type_p(lhst) || pointer_type_p(rhst)) {
3212  if(gen_length(L)==1) { // FI: one fixed bound
3213  cell lc = CELL(CAR(L));
3215  set out_s = points_to_graph_set(out);
3216  SET_FOREACH(points_to, pt, out_s) {
3217  cell source = points_to_source(pt);
3218  if(cell_in_list_p(source, RR)) {
3219  cell sink = points_to_sink(pt);
3220  if(cmp_function(lc, sink)) {
3222  if(approximation_exact_p(a)) {
3223  /* The condition cannot violate an exact arc. */
3224  // clear_pt_map(out);
3225  points_to_graph_bottom(out) = true;
3226  // Would be useless/different with a union
3228  }
3229  else
3231  }
3232  }
3233  }
3234  }
3235  else {
3236  list R = expression_to_points_to_sinks(rhs, in);
3237  if(gen_length(R)==1) { // FI: one fixed bound
3238  cell rc = CELL(CAR(R));
3239  list LL = expression_to_points_to_sources(lhs, in);
3240  set out_s = points_to_graph_set(out);
3241  SET_FOREACH(points_to, pt, out_s) {
3242  cell source = points_to_source(pt);
3243  if(cell_in_list_p(source, LL)) {
3244  cell sink = points_to_sink(pt);
3245  if(cmp_function(sink, rc)) {
3246  // FI: Oops in middle of the iterator...
3248  if(approximation_exact_p(a)) {
3249  /* The condition cannot violate an exact arc. */
3250  // clear_pt_map(out);
3251  points_to_graph_bottom(out) = true;
3252  // Would be useless/different with a union
3254  }
3255  else
3257  }
3258  }
3259  }
3260  }
3261  }
3262  }
3263  free_type(lhst), free_type(rhst);
3264 
3265  return in;
3266 }
3267 ␌
3268 /* Update the points-to information "in" according to the validity of
3269  * the condition.
3270  *
3271  * We can remove the arcs that violate the condition or decide that the
3272  * condition cannot be true.
3273  */
3275 {
3276  pt_map out = in;
3277  entity f = call_function(c);
3278  list al = call_arguments(c);
3279 
3280  if((ENTITY_EQUAL_P(f) && true_p)
3281  || (ENTITY_NON_EQUAL_P(f) && !true_p)) {
3283  }
3284  else if((ENTITY_EQUAL_P(f) && !true_p)
3285  || (ENTITY_NON_EQUAL_P(f) && true_p)) {
3287  }
3288  else if(ENTITY_LESS_OR_EQUAL_P(f)
3291  || ENTITY_LESS_THAN_P(f)) {
3292  out = order_condition_to_points_to(f, al, true_p, in);
3293  }
3294  else {
3295  pips_internal_error("Not implemented yet.\n");
3296  }
3297  pips_assert("out is consistent", points_to_graph_consistent_p(out));
3298  return out;
3299 }
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
int get_int_property(const string)
cell make_cell_reference(reference _field_)
Definition: effects.c:293
void free_cell(cell p)
Definition: effects.c:249
approximation make_approximation_exact(void)
Definition: effects.c:185
approximation copy_approximation(approximation p)
APPROXIMATION.
Definition: effects.c:132
approximation make_approximation_may(void)
Definition: effects.c:179
descriptor copy_descriptor(descriptor p)
DESCRIPTOR.
Definition: effects.c:389
descriptor make_descriptor_none(void)
Definition: effects.c:442
cell copy_cell(cell p)
CELL.
Definition: effects.c:246
points_to make_points_to(cell a1, cell a2, approximation a3, descriptor a4)
void free_points_to(points_to p)
bool points_to_graph_consistent_p(points_to_graph p)
points_to copy_points_to(points_to p)
POINTS_TO.
points_to_graph copy_points_to_graph(points_to_graph p)
POINTS_TO_GRAPH.
type copy_type(type p)
TYPE.
Definition: ri.c:2655
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
reference make_reference(entity a1, list a2)
Definition: ri.c:2083
void free_expression(expression p)
Definition: ri.c:853
reference copy_reference(reference p)
REFERENCE.
Definition: ri.c:2047
void free_type(type p)
Definition: ri.c:2658
#define remove_arc_from_pt_map(a, s)
#define add_arc_to_pt_map(a, s)
#define pt_map_undefined
#define clear_pt_map(pt)
#define difference_of_pt_maps(pt1, pt2, pt3)
#define free_pt_map(pt)
#define new_simple_pt_map()
#define new_pt_map()
#define union_of_pt_maps(pt1, pt2, pt3)
static FILE * out
Definition: alias_check.c:128
bool entity_abstract_location_p(entity al)
bool entity_stub_sink_p(entity e)
test if an entity is a stub sink for a formal parameter e.g.
bool cell_typed_anywhere_locations_p(cell c)
test if a cell is the bottom of the lattice
cell make_anywhere_cell(type t)
void const char const char const int
set kill_must_set(list L, set in)
Generate the subset of arcs that must be removed from the points-to graph "in".
set points_to_may_filter(set in)
returns a set which contains all the MAY points to
set kill_may_set(list L, set in_may)
Compute the set of arcs in the input points-to relation "in" whose approximation must be changed from...
set points_to_must_filter(set in)
returns a set which contains all the EXACT points to
cell make_nowhere_cell()
This file contains all the operators defining constant paths :
set gen_may_set(list L, list R, set in_may, bool *address_of_p)
Should be moved to anywhere_abstract_locations.c.
set points_to_anywhere(list lhs_list, set input)
cell make_typed_nowhere_cell(type t)
set points_to_anywhere_typed(list lhs_list, set input)
Already exists in points_to_general_algorithm.c, to be removed later...
pt_map dereferencing_to_points_to(expression p, pt_map in)
Make sure that expression p can be dereferenced in points-to graph "in".
reference reference_add_field_dimension(reference, entity)
add a field f as a subscript to a reference r if it is meaningful.
Definition: effects.c:1475
bool related_points_to_cell_in_list_p(cell, list)
Two cells are related if they are based on the same entity.
Definition: points_to.c:149
type cell_to_type(cell, bool *)
Definition: type.c:513
type points_to_reference_to_concrete_type(reference)
Definition: type.c:685
cell make_anywhere_points_to_cell(type)
Function storing points to information attached to a statement.
Definition: points_to.c:87
type points_to_cell_to_type(cell, bool *)
FI: I need more generality than is offered by cell_to_type()
Definition: type.c:665
reference cell_any_reference(cell)
API for reference.
Definition: effects.c:77
cell points_to_cell_add_field_dimension(cell, entity)
Functions about points-to cells - There is no cell.c file.
Definition: effects.c:1444
void points_to_cell_add_unbounded_subscripts(cell)
Definition: effects.c:1632
bool cells_may_not_point_to_null_p(list)
Definition: points_to.c:763
list points_to_reference_to_typed_index(reference, type)
Look for the index in "r" that corresponds to a pointer of type "t" and return the corresponding elem...
Definition: points_to.c:361
type points_to_cell_to_concrete_type(cell)
Definition: type.c:676
bool field_reference_expression_p(expression)
Check if expression "e" is a reference to a struct field.
Definition: points_to.c:224
bool points_to_cell_equal_p(cell, cell)
Definition: points_to.c:916
cell make_null_pointer_value_cell(void)
type points_to_expression_to_type(expression, bool *)
FI: I need more generality than is offered by expression_to_type() because fields are assimilated to ...
Definition: type.c:592
bool anywhere_cell_p(cell)
Is it an anywhere cell?
Definition: effects.c:367
type points_to_expression_to_concrete_type(expression)
The type returned is stored in a hash-table.
Definition: type.c:617
bool generic_atomic_points_to_cell_p(cell, bool)
Is it a unique concrete memory location?
Definition: points_to.c:452
bool nowhere_cell_p(cell)
Target of an undefined pointer.
Definition: effects.c:455
reference simple_reference_add_field_dimension(reference, entity)
Do not check anything, just add f as a last subscript.
Definition: effects.c:1581
bool cells_must_point_to_null_p(list)
Definition: points_to.c:750
bool points_to_cell_in_list_p(cell, list)
Definition: points_to.c:117
bool atomic_points_to_cell_p(cell)
Is it a unique concrete memory location?
Definition: points_to.c:423
list find_points_to_subscript_for_type(cell, type)
Find the subscript in the reference of cell "c" that would make the reference type be "t" if the subs...
Definition: type.c:1274
bool adapt_reference_to_type(reference, type, int(*)(void))
FI: a really stupid function...
Definition: type.c:1327
string effect_reference_to_string(reference)
Definition: prettyprint.c:155
bool null_cell_p(cell)
Definition: effects.c:466
bool stub_points_to_cell_p(cell)
Definition: points_to.c:108
void points_to_cell_update_last_subscript(cell, expression)
Transform reference a[i]...[j] and expression s into reference a[i]..[j+s] if j and s are constant in...
Definition: effects.c:1643
void points_to_cell_add_zero_subscripts(cell)
Definition: effects.c:1615
bool heap_cell_p(cell)
Any heap cell, more or less abstract or typed.
Definition: effects.c:420
bool points_to_cells_intersect_p(cell, cell)
points-to cells use abstract addresses, hence the proper comparison is an intersection.
Definition: points_to.c:532
#define cell_undefined_p(x)
Definition: effects.h:431
struct _newgen_struct_cell_ * cell
Definition: effects.h:90
#define cell_undefined
Definition: effects.h:430
#define approximation_exact_p(x)
Definition: effects.h:369
#define CELL(x)
CELL.
Definition: effects.h:424
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
void gen_full_free_list(list l)
Definition: genClib.c:1023
#define RR
Definition: genspec.h:95
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963
#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
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
list gen_last(list l)
Return the last element of a list.
Definition: list.c:578
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
#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_user_warning
Definition: misc-local.h:146
#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 pips_user_error
Definition: misc-local.h:147
bool set_empty_p(const set)
tell whether set s is empty.
Definition: set.c:367
#define set_undefined
Definition: newgen_set.h:48
set set_assign(set, const set)
Assign a set with the content of another set.
Definition: set.c:129
void sets_free(set,...)
Free several sets in one call.
Definition: set.c:340
int set_size(const set)
returns the number of items in s.
Definition: set.c:359
set set_difference(set, const set, const set)
Definition: set.c:256
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
set set_union(set, const set, const set)
Definition: set.c:211
int bool
we cannot use an enum or stdbool because we need to be compatible with newgen, thus boolean need to h...
Definition: newgen_types.h:78
int tag
TAG.
Definition: newgen_types.h:92
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
#define remove_arc_from_pt_map_(a, s)
void offset_points_to_cell(cell sink, expression delta, type t, bool unique_p __attribute__((__unused__)))
FI: offset_cell() has been derived from this function.
Definition: expression.c:1036
pt_map relational_intrinsic_call_condition_to_points_to(call c, pt_map in, bool true_p)
Update the points-to information "in" according to the validity of the condition.
Definition: expression.c:3274
void offset_array_reference(reference r, expression delta, type et)
Side effect on reference "r".
Definition: expression.c:802
points_to offset_cell(points_to pt, expression delta, type et)
Allocate and return a new points-to "npt", copy of "pt", with an offset of "delta" on the sink.
Definition: expression.c:937
static bool cell_is_xxx_p(cell c1, cell c2, int xxx)
Definition: expression.c:2742
pt_map reference_condition_to_points_to(reference r, pt_map in, bool true_p)
Handle conditions such as "if(p)".
Definition: expression.c:2538
#define GREATER_THAN_OR_EQUAL_TO
Definition: expression.c:2740
pt_map constant_call_to_points_to(call c __attribute__((unused)), pt_map pt_in)
FI: this should not generate any points-to update.
Definition: expression.c:404
pt_map equal_condition_to_points_to(list al, pt_map in)
The expression list "al" contains exactly two arguments, "lhs" and "rhs".
Definition: expression.c:2986
pt_map pointer_arithmetic_to_points_to(expression lhs, expression delta, pt_map pt_in)
Update the sink locations associated to the source "lhs" under points-to information pt_map by "delta...
Definition: expression.c:760
pt_map struct_assignment_to_points_to(expression lhs, expression rhs, pt_map pt_in)
pt_in is modified by side-effects and returned as pt_out
Definition: expression.c:2319
cell reduce_cell_to_pointer_type(cell c)
Remove last subscripts of cell c till its type becomes a scalar pointer.
Definition: expression.c:1809
pt_map user_call_condition_to_points_to(call c, pt_map in, list el, bool true_p)
Definition: expression.c:2679
#define LESS_THAN
See if you can decide that the addresses linked to c1 are xxx than the addresses linked to c2.
Definition: expression.c:2737
pt_map intrinsic_call_condition_to_points_to(call c, pt_map in, bool true_p)
We can break down the intrinsics according to their arity or according to their kinds....
Definition: expression.c:2618
#define GREATER_THAN
Definition: expression.c:2739
pt_map freed_pointer_to_points_to(expression lhs, pt_map pt_in, bool side_effect_p)
Any abstract location of the lhs in L is going to point to nowhere, maybe.
Definition: expression.c:1741
void check_rhs_value_types(expression lhs, expression rhs __attribute__((unused)), list sinks)
Check that the cells in list "sinks" have types compatible with the expression on the left-hand side,...
Definition: expression.c:1277
pt_map call_condition_to_points_to(call c, pt_map in, list el, bool true_p)
Handle any condition that is a call such as "if(p!=q)", "if(*p)", "if(foo(p=q))".....
Definition: expression.c:2595
pt_map call_to_points_to(call c, pt_map pt_in, list el, bool side_effect_p)
Three different kinds of calls are distinguished:
Definition: expression.c:306
pt_map expressions_to_points_to(list el, pt_map pt_in, bool side_effect_p)
Compute the points-to information pt_out that results from the evaluation of a possibly empty list of...
Definition: expression.c:243
void check_type_of_points_to_cells(list sinks, type ct, bool eval_p)
Check that all cells in list "sinks" are compatible with type "ct" if "eval_p" is false,...
Definition: expression.c:1214
#define LESS_THAN_OR_EQUAL_TO
Definition: expression.c:2738
pt_map application_to_points_to(application a, pt_map pt_in, bool side_effect_p)
Definition: expression.c:2490
pt_map struct_initialization_to_points_to(expression lhs, expression rhs, pt_map in)
Definition: expression.c:2262
list reduce_cells_to_pointer_type(list cl)
Undo the extra eval performed when stubs are generated: 0 subscripts are added when arrays are involv...
Definition: expression.c:1844
void offset_cells(cell source, list sinks, expression delta, type et, pt_map in)
Each cell in sinks is replaced by a cell located "delta" elements further up in the memory.
Definition: expression.c:869
pt_map list_assignment_to_points_to(list L, list R, pt_map pt_out)
Update "pt_out" when any element of L can be assigned any element of R.
Definition: expression.c:2029
void subscripted_reference_to_points_to(reference r, list sl, pt_map pt_in)
FI: what is this function supposed to do? Just update "pt_in" to make sure that "r" can be dereferenc...
Definition: expression.c:57
list points_to_cell_to_useful_pointer_cells(cell c, set pts)
Definition: expression.c:1905
bool cell_is_greater_than_or_equal_to_p(cell c1, cell c2)
Definition: expression.c:2830
pt_map boolean_intrinsic_call_condition_to_points_to(call c, pt_map in, bool true_p)
Deal with "!", "&&", "||" etc.
Definition: expression.c:2695
pt_map internal_pointer_assignment_to_points_to(expression lhs, expression rhs, pt_map pt_in)
Any abstract location of the lhs in L is going to point to any sink of any abstract location of the r...
Definition: expression.c:1315
pt_map condition_to_points_to(expression c, pt_map in, bool true_p)
Update points-to set "in" according to the content of the expression using side effects.
Definition: expression.c:2512
pt_map order_condition_to_points_to(entity f, list al, bool true_p, pt_map in)
The expression list "al" contains exactly two arguments.
Definition: expression.c:3176
pt_map memory_leak_to_more_memory_leaks(cell l, pt_map in)
Cell "l" has been memory leaked for sure and is not referenced any more in "in".
Definition: expression.c:1929
pt_map null_non_equal_condition_to_points_to(expression e, pt_map in)
The condition is e!=NULL.
Definition: expression.c:2927
bool cell_is_greater_than_p(cell c1, cell c2)
Definition: expression.c:2835
pt_map pointer_assignment_to_points_to(expression lhs, expression rhs, pt_map pt_in)
Definition: expression.c:1437
void offset_points_to_cells(list sinks, expression delta, type t)
Each cell in sinks is replaced by a cell located "delta" elements further up in the memory.
Definition: expression.c:1020
pt_map range_to_points_to(range r, pt_map pt_in, bool side_effect_p)
Definition: expression.c:284
static list generic_points_to_cell_to_useful_pointer_cells(cell c, set pts)
Returns a list of cells of pointer type which are included in cell "c".
Definition: expression.c:1862
bool cell_is_less_than_p(cell c1, cell c2)
Definition: expression.c:2825
pt_map freed_list_to_points_to(expression lhs, list L, list R, pt_map pt_in)
Error detections on "L" and "R" have already been performed.
Definition: expression.c:1489
pt_map intrinsic_call_to_points_to(call c, pt_map pt_in, bool side_effect_p)
Definition: expression.c:411
bool cell_is_less_than_or_equal_to_p(cell c1, cell c2)
See if you can decide that the addresses linked to c1 are smaller than the addresses linked to c2.
Definition: expression.c:2820
pt_map reference_to_points_to(reference r, pt_map pt_in, bool side_effect_p)
The subscript expressions may impact the points-to information.
Definition: expression.c:262
pt_map expression_to_points_to(expression e, pt_map pt_in, bool side_effect_p)
Update pt_in and pt_out according to expression e.
Definition: expression.c:115
pt_map non_equal_condition_to_points_to(list al, pt_map in)
The expression list "al" contains exactly two arguments.
Definition: expression.c:3086
list freeable_points_to_cells(list R)
Remove from points-to cell list R cells that certainly cannot be freed.
Definition: expression.c:1457
list points_to_cells_to_pointer_cells(list pl)
Convert cells in l into derived pointer cells when possible.
Definition: expression.c:1917
pt_map assignment_to_points_to(expression lhs, expression rhs, pt_map pt_in)
Definition: expression.c:1163
pt_map null_equal_condition_to_points_to(expression e, pt_map in)
The condition is e==NULL.
Definition: expression.c:2849
list points_to_cell_to_pointer_cells(cell c)
Definition: expression.c:1900
points_to_graph user_call_to_points_to(call c, points_to_graph pt_in, list el)
FI: limited to the interprocedural option.
bool cell_in_list_p(cell, const list)
bool unreachable_points_to_cell_p(cell, pt_map)
Can cell c be accessed via another cell?
list reference_to_points_to_sinks(reference, type, pt_map, bool, bool)
Returns a list of memory cells "sinks" possibly accessed by the evaluation of reference "r".
Definition: sinks.c:755
bool reference_must_points_to_null_p(reference, pt_map)
Definition: sinks.c:1859
bool cell_in_points_to_set_p(cell, set)
Check if a cell c appears as source or sink in points-to set pts.
list points_to_source_to_arcs(cell, pt_map, bool)
Build the list of arcs whose source is "source" according to the points-to graphs "ptm".
points_to find_arc_in_points_to_set(cell, cell, pt_map)
The approximation is not taken into account.
pt_map add_arc_to_pt_map_(points_to, pt_map)
bool statement_points_to_context_defined_p(void)
Definition: statement.c:145
bool reference_may_points_to_null_p(reference, pt_map)
Definition: sinks.c:1873
void remove_points_to_arcs(cell, cell, pt_map)
cell make_null_cell(void)
Definition: sinks.c:95
points_to_graph points_to_cell_source_projection(points_to_graph, cell)
Remove all arcs in "ptg" starting from "c".
pt_map full_copy_pt_map(pt_map)
Definition: statement.c:67
set points_to_source_projection(set, entity)
Remove all arcs starting from e because e has been assigned a new value.
bool consistent_points_to_set(set)
make sure that set "s" does not contain redundant or contradictory elements
list variable_to_pointer_locations(entity)
variable.c
Definition: variable.c:66
void remove_impossible_arcs_to_null(list *, pt_map)
You know that null and undefined cells in "*pL" are impossible because of the operation that is going...
int points_to_context_statement_line_number(void)
Definition: statement.c:120
string points_to_cell_to_string(cell)
list variable_to_sinks(entity, pt_map, bool)
Return all cells in points-to set "pts" who source is based on entity "e".
list source_to_sinks(cell, pt_map, bool)
Return a list of cells, "sinks", that are sink for some arc whose source is "source" or related to "s...
list points_to_sink_to_sources(cell, pt_map, bool)
Build the sources of sink "sink" according to the points-to graphs.
bool consistent_points_to_graph_p(points_to_graph)
pt_map merge_points_to_graphs(pt_map, pt_map)
#define points_to_approximation(x)
#define points_to_undefined_p(x)
#define points_to_graph_undefined_p(x)
#define points_to_sink(x)
#define points_to_graph_bottom(x)
#define POINTS_TO(x)
POINTS_TO.
#define points_to_graph_set(x)
#define points_to_descriptor(x)
#define points_to_source(x)
string reference_to_string(reference r)
Definition: expression.c:87
string expression_to_string(expression e)
Definition: expression.c:77
#define print_points_to_cell(x)
Definition: print.c:377
string string_of_type(const type)
Definition: type.c:56
string type_to_full_string_definition(type)
type.c
Definition: type.c:45
static hash_table pl
properties are stored in this hash table (string -> property) for fast accesses.
Definition: properties.c:783
static statement gen(int what, entity src, entity trg, entity lid, entity proc, entity(*create_src)(), entity(*create_trg)(), Psysteme sr, list ldiff)
arguments: all that may be useful to generate some code
Definition: remapping.c:498
#define ENTITY_STRCMP_SYSTEM_P(e)
include <string.h>
#define ENTITY_OR_P(e)
#define ENTITY_FSCANF_P(e)
#define ENTITY_PLUS_UPDATE_P(e)
#define ENTITY_RELATIONAL_OPERATOR_P(e)
#define ENTITY_FWRITE_P(e)
#define ENTITY_FREE_SYSTEM_P(e)
#define ENTITY_STOP_P(e)
#define ENTITY_SCANF_P(e)
#define ENTITY_STRNCMP_SYSTEM_P(e)
#define ENTITY_AND_P(e)
#define ENTITY_NON_EQUAL_P(e)
#define ENTITY_EQUAL_P(e)
#define ENTITY_ASSIGN_P(e)
#define ENTITY_FEOF_P(e)
#define ENTITY_DEREFERENCING_P(e)
#define ENTITY_LESS_THAN_P(e)
#define ENTITY_ISOC99_SSCANF_P(e)
#define ENTITY_PRINTF_P(e)
o functions: C library and system io.Amira Mensi
#define ENTITY_POINT_TO_P(e)
#define ENTITY_PRE_DECREMENT_P(e)
#define ENTITY_POST_DECREMENT_P(e)
#define DEREFERENCING_OPERATOR_NAME
Definition: ri-util-local.h:93
#define ENTITY_FOPEN_P(e)
#define ENTITY_POST_INCREMENT_P(e)
#define ENTITY_EXIT_SYSTEM_P(e)
#define ENTITY_CONDITIONAL_P(e)
#define ENTITY_FCLOSE_P(e)
#define ENTITY_ISOC99_SCANF_P(e)
#define unary_intrinsic_expression(name, e)
Building quickly bool expressions, FC.
#define ENTITY_PRE_INCREMENT_P(e)
#define ENTITY_FREAD_P(e)
#define ENTITY_NOT_P(e)
#define ENTITY_PLUS_C_P(e)
#define ENTITY_SPRINTF_P(e)
#define ENTITY_GREATER_THAN_P(e)
#define ENTITY_SSCANF_P(e)
#define ENTITY_LOGICAL_OPERATOR_P(e)
Attention : This definition is different with the Fortran Standard where the logical operators are th...
#define ENTITY_FREOPEN_P(e)
#define ENTITY_MINUS_C_P(e)
#define ENTITY_FERROR_P(e)
#define ENTITY_STRNCAT_SYSTEM_P(e)
#define ENTITY_ABORT_SYSTEM_P(e)
#define ENTITY_FDOPEN_P(e)
#define UNARY_MINUS_OPERATOR_NAME
#define ENTITY_C_RETURN_P(e)
#define ENTITY_ISOC99_FSCANF_P(e)
#define ENTITY_FPRINTF_P(e)
#define ENTITY_FILENO_P(e)
#define ENTITY_LESS_OR_EQUAL_P(e)
#define ENTITY_MINUS_UPDATE_P(e)
#define ENTITY_CLEARERR_P(e)
#define ENTITY_STRCAT_SYSTEM_P(e)
#define ENTITY_GREATER_OR_EQUAL_P(e)
#define ENTITY_ASSERT_FAIL_SYSTEM_P(e)
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
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
bool entity_array_p(entity e)
Is e a variable with an array type?
Definition: entity.c:754
entity FindOrCreateTopLevelEntity(const char *name)
Return a top-level entity.
Definition: entity.c:1603
value EvalExpression(expression e)
Evaluate statically an expression.
Definition: eval.c:108
list struct_initialization_expression_to_expressions(expression e)
Returns a list of expressions hidden by the brace function.
Definition: expression.c:4073
expression reference_to_expression(reference r)
Definition: expression.c:196
bool zero_expression_p(expression e)
Definition: expression.c:1217
void reference_add_zero_subscripts(reference r, type t)
Definition: expression.c:261
expression make_unbounded_expression()
Definition: expression.c:4339
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
bool expression_null_p(expression exp)
returns true if the expression is equal to zero or NULL (even if there is a cast before such as in (v...
Definition: expression.c:2611
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 MakeUnaryCall(entity f, expression a)
Creates a call expression to a function with one argument.
Definition: expression.c:342
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
bool unbounded_expression_p(expression e)
Definition: expression.c:4329
reference expression_reference(expression e)
Short cut, meaningful only if expression_reference_p(e) holds.
Definition: expression.c:1832
bool C_initialization_expression_p(expression e)
Definition: expression.c:4056
entity function_to_return_value(entity m)
Returns the entity rv that carries the value returned by module m, when m is not a C void function or...
Definition: module.c:509
bool char_star_constant_function_type_p(type)
Beware of typedefs.
Definition: type.c:5787
bool array_type_p(type)
Definition: type.c:2942
type array_type_to_sub_array_type(type)
Allocate a new type, the sub-array type of "t".
Definition: type.c:5718
bool type_void_star_p(type)
Definition: type.c:5765
type expression_to_type(expression)
For an array declared as int a[10][20], the type returned for a[i] is int [20].
Definition: type.c:2486
bool array_of_pointers_type_p(type)
Definition: type.c:3025
bool scalar_integer_type_p(type)
Definition: type.c:3276
bool basic_equal_p(basic, basic)
Definition: type.c:927
type type_to_pointed_type(type)
returns t if t is not a pointer type, and the pointed type if t is a pointer type.
Definition: type.c:5265
type entity_basic_concrete_type(entity)
retrieves or computes and then returns the basic concrete type of an entity
Definition: type.c:3677
bool pointer_type_p(type)
Check for scalar pointers.
Definition: type.c:2993
bool type_structurally_equal_p(type, type)
Type t1 and t2 are equal if their basic concrete components are equal.
Definition: type.c:586
bool array_pointer_type_equal_p(type, type)
assume that a pointer to type x is equal to a 1-D array of x
Definition: type.c:609
size_t type_depth(type)
Number of steps to access the lowest leave of type t without dereferencing.
Definition: type.c:4880
bool formal_parameter_p(entity)
Definition: variable.c:1489
list struct_type_to_fields(type)
Definition: type.c:5798
bool struct_type_p(type)
Returns true if t is of type derived and if the derived type is a struct.
Definition: type.c:3121
type array_type_to_element_type(type)
returns the type of the elements of an array type, as a newly allocated type.
Definition: type.c:5700
type compute_basic_concrete_type(type)
computes a new type which is the basic concrete type of the input type (this new type is not stored i...
Definition: type.c:3556
bool overloaded_type_p(type)
Returns true if t is a variable type with a basic overloaded.
Definition: type.c:2666
bool char_star_type_p(type)
Beware of typedefs.
Definition: type.c:5774
bool array_of_struct_type_p(type)
Definition: type.c:3133
bool char_type_p(type)
return true whether ‘t’ is a char or an unsigned char
Definition: type.c:2877
bool C_pointer_type_p(type)
Returns OK for "char[]" as well as for "char *".
Definition: type.c:3011
list struct_variable_to_fields(entity)
Assume that v is declared as a struct.
Definition: variable.c:2045
#define type_functional_p(x)
Definition: ri.h:2950
#define value_tag(x)
Definition: ri.h:3064
#define type_struct(x)
Definition: ri.h:2964
#define value_code_p(x)
Definition: ri.h:3065
#define basic_pointer(x)
Definition: ri.h:637
#define syntax_reference_p(x)
Definition: ri.h:2728
#define functional_result(x)
Definition: ri.h:1444
#define value_constant(x)
Definition: ri.h:3073
#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 EXPRESSION_(x)
Definition: ri.h:1220
#define reference_variable(x)
Definition: ri.h:2326
#define basic_derived(x)
Definition: ri.h:640
#define SIZEOFEXPRESSION(x)
SIZEOFEXPRESSION.
Definition: ri.h:2364
#define range_upper(x)
Definition: ri.h:2290
#define value_intrinsic_p(x)
Definition: ri.h:3074
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define constant_int(x)
Definition: ri.h:850
#define syntax_call_p(x)
Definition: ri.h:2734
#define sizeofexpression_expression(x)
Definition: ri.h:2409
#define syntax_cast(x)
Definition: ri.h:2739
#define type_functional(x)
Definition: ri.h:2952
#define syntax_application(x)
Definition: ri.h:2748
#define syntax_va_arg(x)
Definition: ri.h:2751
#define type_variable(x)
Definition: ri.h:2949
@ is_value_intrinsic
Definition: ri.h:3034
@ is_value_unknown
Definition: ri.h:3035
@ is_value_expression
Definition: ri.h:3036
@ is_value_constant
Definition: ri.h:3033
@ is_value_code
Definition: ri.h:3031
@ is_value_symbolic
Definition: ri.h:3032
#define syntax_range(x)
Definition: ri.h:2733
@ is_syntax_range
Definition: ri.h:2692
@ is_syntax_application
Definition: ri.h:2697
@ is_syntax_cast
Definition: ri.h:2694
@ is_syntax_call
Definition: ri.h:2693
@ is_syntax_va_arg
Definition: ri.h:2698
@ is_syntax_reference
Definition: ri.h:2691
@ is_syntax_sizeofexpression
Definition: ri.h:2695
@ is_syntax_subscript
Definition: ri.h:2696
#define range_increment(x)
Definition: ri.h:2292
#define value_constant_p(x)
Definition: ri.h:3071
#define value_symbolic(x)
Definition: ri.h:3070
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define cast_expression(x)
Definition: ri.h:747
#define application_arguments(x)
Definition: ri.h:510
#define subscript_indices(x)
Definition: ri.h:2563
#define constant_int_p(x)
Definition: ri.h:848
#define type_void_p(x)
Definition: ri.h:2959
#define entity_name(x)
Definition: ri.h:2790
#define reference_indices(x)
Definition: ri.h:2328
#define syntax_sizeofexpression(x)
Definition: ri.h:2742
#define sizeofexpression_type_p(x)
Definition: ri.h:2404
#define syntax_call(x)
Definition: ri.h:2736
#define subscript_array(x)
Definition: ri.h:2561
#define application_function(x)
Definition: ri.h:508
#define range_lower(x)
Definition: ri.h:2288
#define type_undefined
Definition: ri.h:2883
#define syntax_subscript(x)
Definition: ri.h:2745
#define call_arguments(x)
Definition: ri.h:711
#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 symbolic_expression(x)
Definition: ri.h:2597
#define value_expression(x)
Definition: ri.h:3082
#define variable_basic(x)
Definition: ri.h:3120
#define entity_initial(x)
Definition: ri.h:2796
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#define semantics_user_warning
static list expression_to_points_to_sources(_UNUSED_ expression e, _UNUSED_ points_to_graph in)
Definition: expression.c:108
static list expression_to_points_to_sinks(_UNUSED_ expression e, _UNUSED_ points_to_graph in)
Definition: expression.c:100
s1
Definition: set.c:247
Definition: pip__tab.h:30
Base of the parameters.
Definition: pip_interface.c:89
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
static FILE * out2