PIPS
points_to_set.c
Go to the documentation of this file.
1 /*
2 
3  $Id: points_to_set.c 23412 2017-08-09 15:07:09Z 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 /* private implementation of points_to set.
26 
27  points_to_equal_p to determine if two points_to relations are equal (same
28  source, same sink, same relation)
29 
30  points_to_rank how to compute rank for a points_to element
31 
32 */
33 #ifdef HAVE_CONFIG_H
34  #include "pips_config.h"
35 #endif
36 
37 #include <stdlib.h>
38 #include <stdio.h>
39 
40 #include "genC.h"
41 #include "linear.h"
42 
43 #include "ri.h"
44 #include "effects.h"
45 
46 #include "ri-util.h"
47 #include "effects-util.h"
48 
49 #include "misc.h"
50 
51 #include "text-util.h"
52 #include "prettyprint.h" // for debugging
53 #include "properties.h"
54 
55 #include "points_to_private.h"
56 #include "points-to.h"
57 
58 #define INITIAL_SET_SIZE 10
59 
60 int compare_entities_without_scope(const entity *pe1, const entity *pe2)
61 {
62  int
63  null_1 = (*pe1==(entity)NULL),
64  null_2 = (*pe2==(entity)NULL);
65 
66  if (null_1 || null_2)
67  return(null_2-null_1);
68  else {
69  /* FI: Which sorting do you want? */
70 
71  string s1 = entity_name(*pe1);
72  string s2 = entity_name(*pe2);
73 
74  return strcmp(s1,s2);
75  }
76 }
77 
79 {
82 
83  return e;
84 }
85 
86 
87 
88 /*return true if two acces_path are equals*/
89 bool locations_equal_p(cell acc1, cell acc2)
90 {
91  return cell_equal_p(acc1, acc2);
92 }
93 
94 /* returns true if two points-to arcs "vpt1" and "vpt2" are equal.
95  *
96  * Used to build sets of points-to using the set library of Newgen
97  */
98 int points_to_equal_p( const void * vpt1, const void* vpt2)
99 {
100  points_to pt1 = (points_to) vpt1;
101  points_to pt2 = (points_to) vpt2;
102 
103  //same source
104  cell c1 = points_to_source(pt1);
105  cell c2 = points_to_source(pt2);
106  bool cmp1 = locations_equal_p(c1,c2);
107 
108  // same sink
109  cell c3 = points_to_sink(pt1);
110  cell c4 = points_to_sink(pt2);
111  bool cmp2 = locations_equal_p(c3,c4);
112 
113  // same approximation
116  // FI: must is forgotten...
117  //bool cmp3 = (approximation_exact_p(a1) && approximation_exact_p(a2))
118  // || ( approximation_may_p(a1) && approximation_may_p(a2));
119  // FI: should we identify "exact" and "must"?
120  bool cmp3 = (approximation_tag(a1)==approximation_tag(a2));
121  bool cmp = cmp1 && cmp2 && cmp3;
122 
123  ifdebug(8) {
124  printf("%s for pt1=%p and pt2=%p\n", bool_to_string(cmp), pt1, pt2);
125  print_points_to(pt1);
126  print_points_to(pt2);
127  }
128 
129  return cmp;
130 }
131 
132 
133 /* create a key which is a concatenation of the source's name, the
134  sink's name and the approximation of their relation(may or exact)*/
135 _uint points_to_rank( const void * vpt, size_t size)
136 {
137  points_to pt= (points_to)vpt;
138  cell source = points_to_source(pt);
139  cell sink = points_to_sink(pt);
141  tag rel_tag = approximation_tag(rel);
142  string s = strdup(int2a(rel_tag));
143  reference sro = cell_to_reference(source);
144  reference sri = cell_to_reference(sink);
145  // FI: strdup must be useless
146  string s1 = strdup(reference_to_string(sro));
147  string s2 = strdup(reference_to_string(sri));
148  string key = strdup(concatenate(s1,
149  " ",
150  s2,
151  s,
152  NULL));
153  _uint rank = hash_string_rank(key,size);
154  free(key);
155  return rank;
156 }
157 
158 /* create a string which is a concatenation of the source's name, the
159  * sink's name and the approximation of their relation(may or exact).
160  *
161  * The same string is used by the function points_to_rank()
162  */
163 string points_to_name(const points_to pt)
164 {
165  cell source = points_to_source(pt);
166  cell sink = points_to_sink(pt);
168  tag rel_tag = approximation_tag(rel);
169  string s = strdup(int2a(rel_tag));
170  reference sro = cell_to_reference(source);
171  reference sri = cell_to_reference(sink);
172  string s1 = strdup(reference_to_string(sro));
173  string s2 = strdup(reference_to_string(sri));
174  string key = strdup(concatenate(s1,
175  " ",
176  s2,
177  s,
178  NULL));
179  return key;
180 }
181 
182 /* Create a string which is the cell reference in C syntax.
183  *
184  * A new string is allocated.
185  */
186 string points_to_cell_name(cell source)
187 {
188  reference sro = cell_to_reference(source);
189  string key = strdup(reference_to_string(sro));
190 
191  return key;
192 }
193 
194 /* Remove from "pts" arcs based on at least one local entity in list
195  * "l" and preserve those based on static and global entities. This
196  * function is called when exiting a statement block.
197  *
198  * Detection of dangling pointers.
199  *
200  * Detection of memory leaks. Could be skipped when dealing with the
201  * "main" module, but the information would have to be passed down
202  * thru an extra parameter.
203  *
204  * Side-effects on argument "pts" which is returned.
205  */
206 set points_to_set_block_projection(set pts, list l, bool main_p, bool body_p)
207 {
208  list pls = NIL; // Possibly lost sinks
209  list new_l = NIL; // new arcs to add
210  list old_l = NIL; // old arcs to remove
212  FOREACH(ENTITY, e, l) {
214  // The use of "sink_p" is only an optimization
215  bool sink_p = pointer_type_p(uet)
217  || struct_type_p(uet)
218  || array_of_struct_type_p(uet);
219 
220  SET_FOREACH(points_to, pt, pts){
221  cell source = points_to_source(pt);
222  cell sink = points_to_sink(pt);
225 
226  if(sink_p && e == e_sr && (!(variable_static_p(e_sr) || top_level_entity_p(e_sr) || heap_cell_p(source) || e_sr==rv))) {
227  set_del_element(pts, pts, (void*)pt);
228  if(heap_cell_p(sink)) {
229  /* Check for memory leaks */
230  pls = CONS(CELL, sink, pls);
231  }
232  // FI: memory leak? sink should be copied and pt be freed...
233  }
234  else if(e == e_sk
235  && (!(variable_static_p(e_sk)
236  || top_level_entity_p(e_sk)
237  || heap_cell_p(sink)))) {
238  if(gen_in_list_p(e_sr, l)) {
239  /* Both the sink and the source disappear: the arc is removed */
240  set_del_element(pts, pts, (void*)pt);
241  }
242  else {
244 
245  if(approximation_exact_p(a)) {
246  // FI: this may be transient if the source is a formal
247  // parameter and if the projected block is the function
248  // statement
249  if(!body_p || !formal_parameter_p(e_sr))
250  pips_user_warning("Dangling pointer \"%s\" towards \"%s\".\n",
251  entity_user_name(e_sr),
252  entity_user_name(e_sk));
253  }
254  // list lhs = CONS(CELL, source, NIL);
255  // pts = points_to_nowhere_typed(lhs, pts);
256  bool to_be_freed;
257  type sink_t = points_to_cell_to_type(sink, &to_be_freed);
258  type n_sink_t = copy_type(sink_t);
259  if(to_be_freed) free_type(sink_t);
260  points_to npt = make_points_to(copy_cell(source),
261  make_typed_nowhere_cell(n_sink_t),
264  // Since we are looping on pts... no side-effects on pts
265  new_l = CONS(POINTS_TO, npt, new_l);
266  old_l = CONS(POINTS_TO, pt, old_l);
267  }
268  }
269  }
270  }
271 
272  FOREACH(POINTS_TO, npt, new_l)
273  add_arc_to_simple_pt_map(npt, pts);
274  gen_free_list(new_l);
275  FOREACH(POINTS_TO, pt, old_l)
277  gen_free_list(old_l);
278 
279  if(!main_p) {
280  /* Any memory leak? */
281  FOREACH(CELL, c, pls) {
282  if(!sink_in_set_p(c, pts)) {
284  entity b = reference_variable(r);
285  pips_user_warning("Memory leak for bucket \"%s\".\n",
286  entity_name(b));
287  points_to_graph ptg = make_points_to_graph(false, pts);
288  ptg = memory_leak_to_more_memory_leaks(c, ptg);
291  }
292  }
293  }
294  return pts;
295 }
296 
297 /* Remove all arcs starting from e because e has been assigned a new value */
299 {
300  list pls = NIL; // Possibly lost sinks
301 
302  SET_FOREACH(points_to, pt, pts) {
303  cell source = points_to_source(pt);
304  cell sink = points_to_sink(pt);
306  //entity e_sk = reference_variable(cell_to_reference(sink));
307 
308  if(e == e_sr) {
309  set_del_element(pts, pts, (void*)pt);
310  if(heap_cell_p(sink)) {
311  /* Check for memory leaks */
312  pls = CONS(CELL, sink, pls);
313  }
314  }
315  }
316 
317  /* Any memory leak? */
318  FOREACH(CELL, c, pls) {
319  if(!sink_in_set_p(c, pts)) {
321  entity b = reference_variable(r);
322  pips_user_warning("Memory leak for bucket \"%s\".\n",
323  entity_name(b));
324  }
325  }
326  return pts;
327 }
328 
329 /* Remove all arcs in "ptg" starting from "c" */
331 {
332  set pts = points_to_graph_set(ptg);
333 
334  SET_FOREACH(points_to, pt, pts) {
335  cell source = points_to_source(pt);
336 
337  if(cell_equal_p(source, c)) {
338  set_del_element(pts, pts, (void*)pt);
339  }
340  }
341 
342  return ptg;
343 }
344 
345 /* All arcs in relation "g" must be removed or updated if they use the
346  * node "c".
347  *
348  * If "c" is the source of an arc, the arc must be removed and the
349  * sink is a new potential leak.
350  *
351  * If "c" is the sink of an arc, *NOWHERE*, i.e. *UNDEFINED* is the
352  * new sink. The approximation is unchanged.
353  *
354  * Since the heap model does not support a precise analysis, this is
355  * not sure. For the time being, all buckets allocated by the same
356  * statement have a unique name. So arcs pointing to one cannot be
357  * removed when another one is freed. However, since we check that no
358  * arc points to an abstract bucket before we declare a sure memory
359  * leak, this should be OK in the context of memory leaks...
360  */
362 {
363  // FI: do we have to check the atomicity of the source? If it is
364  // removed, it is removed, isn'it? So it's up to the caller?
365 
366  list pmll = NIL; // potential memory leak list
367  list ral = NIL; // removed arc list
368  list nal = NIL; // new arc list
369  SET_FOREACH(points_to, a, g) {
370  cell source = points_to_source(a);
371  cell sink = points_to_sink(a);
372  if(points_to_cell_equal_p(c, source)) {
373  ral = CONS(POINTS_TO, a, ral);
374  if(heap_cell_p(sink) /* && atomic_points_to_cell_p(c)*/ ) {
375  pmll = CONS(CELL, sink, pmll);
376  }
377  }
378  else if(points_to_cell_equal_p(c, sink)) {
379  type sink_t = points_to_cell_to_concrete_type(sink);
380  cell nsink =
381  get_bool_property("ALIASING_ACROSS_TYPES")?
383  : make_typed_nowhere_cell(sink_t);
385  points_to na = make_points_to(copy_cell(source),
386  nsink,
387  nap,
389  ral = CONS(POINTS_TO, a, ral);
390  nal = CONS(POINTS_TO, na, nal);
391  }
392  }
393 
394  /* Apply the arc removals */
395  FOREACH(POINTS_TO, ra, ral)
397 
398  /* Apply the arc additions */
399  FOREACH(POINTS_TO, na, nal)
401 
402  /* Look for effective memory leaks induced by the removal */
404  if(!ENDP(emll)) {
405  /* Go down recursively... */
406  remove_points_to_cells(emll, g);
407  }
408 
409  return g;
410 }
411 
412 /* All nodes, i.e. cells, in "cl" must be removed from graph "g".
413  *
414  * graph "g" is updated by side-effects and returned.
415  */
417 {
418  FOREACH(CELL, c, cl)
419  (void) remove_points_to_cell(c, g);
420  return g;
421 }
422 
423 /* A new list, "emll", is allocated. It contains the cells in the
424  * potential memory leak list that are unreachable in set/relation
425  * "res". Relation "res" is unchanged. List "pmll" is unchanged.
426  *
427  * FI: This is not a sufficient implementation. It fails with strongly
428  * connected components (SCC) in "res". The fixed point algorithms are
429  * likely to generate SCCs.
430  */
432 {
433  list emll = NIL; // Effective memory leak list
434  FOREACH(CELL, h, pmll) {
435  bool found_p = false;
436  SET_FOREACH(points_to, pt, res) {
437  cell sink = points_to_sink(pt);
438  if(points_to_cell_equal_p(h, sink)) {
439  found_p = true;
440  break;
441  }
442  }
443  if(!found_p) {
444  // FI: because of the current heap model, all arcs to a memory
445  // bucket are may arcs. We probably cannot get more than
446  // "possible" memory leak. More thinking needed.
447  // FI: Especially for sources that are not atomic...
448  pips_user_warning("Memory cell %s leaked.\n",
450  emll = CONS(CELL, h, emll);
451  }
452  }
453  return emll;
454 }
455 
456 /* "pts" is the points-to relation existing at the return point of a
457  * function. Meaningless arcs in an interprocedural context must be
458  * eliminated.
459  *
460  * The concept of "meaningless" arc has changed. Formal parameters are
461  * no longer "projected" although some of them are copies because,
462  * when they are not written, they are aliases of the actual parameters
463  * and carry useful information.
464  *
465  * Unfortunately, we do not compute the information about may/must be
466  * written pointers.
467  *
468  * As a consequence, some memory leaks cannot be detected here. The
469  * problem could be spotted when handling a call site, but then the
470  * memory leak will be indicated at each call site. This is not
471  * implemented, but we have a test case,
472  * Pointers/Mensi.sub/conditional_free01.c.
473  *
474  * FI: side-effects to be used explicitly in this function
475  * For the time being a new set is allocated
476  */
478 {
481  set_assign(res, pts);
482  /* Do we have a useful return value? */
486  if(pointer_type_p(rt) || struct_type_p(rt))
488 
489  list pmll = NIL; // Potential memory leak list
490 
491  SET_FOREACH(points_to, pt, pts) {
493  /* Preserve the return value. And indexed formal parameters
494  * such as s.tab? No, because struct are passed by copy. But not
495  * arrays... Except that copies are perfect alias of the actual
496  * argument when they are not modified. Since we do not have
497  * information about modified formal parameter, the Written set,
498  * we should provisionally preserve all formal parameters, no
499  * matter what they points to. See
500  * EffectsWithPointsTo/modif_pointer0a4.c */
501  cell source = points_to_source(pt);
502  //type source_t = points_to_cell_to_concrete_type(source);
503  reference r = cell_any_reference(source);
504  //list sl = reference_indices(r);
505  entity v = reference_variable(r);
507  if(rv!=v && !array_type_p(v_t) && !formal_parameter_p(v)) {
508  /* Also preserve nowhere generated by free although the
509  * pointer itself is not written. Beware that a formal pointer
510  * may be written... FI: we should be able to check is the
511  * source has been written or not in the current
512  * function... See Pointers/array10.c. However, it is still
513  * transiently true and not a bug.
514  */
515  cell sink = points_to_sink(pt);
516  if(!nowhere_cell_p(sink)) {
517  // FI: written by Amira
518  set_del_element(res, res, (void*)pt);
519  if((heap_cell_p(sink) || all_heap_locations_cell_p(sink))
520  // FI: we are protected by the test on v_t
521  // The atomicity should not be an issue here
522  && atomic_points_to_cell_p(source))
523  pmll = CONS(CELL, sink, pmll);
524  }
525  }
526  }
527  }
528 
529  /* Detect memory leaks */
530  list emll = potential_to_effective_memory_leaks(pmll, res);
531  gen_free_list(pmll);
532 
533  /* Look recursively for more memory leaks: cells in "emll" are no
534  longer reachable */
535  res = remove_points_to_cells(emll, res);
536  gen_free_list(emll);
537 
538  return res;
539 }
540 
541 /* Return true if a cell is out of scope
542  *
543  * FI: I add formal parameters as in scope variables...
544  *
545  * FI: I remove formal parameters because this function is used to
546  * compute the OUT set. The modified or not values of formal parameter
547  * are not relevant. If they have not been modified, the useful
548  * information is already available in the IN set (oops, see next
549  * comment below). If they have been modified, they are no longer
550  * reachable and must be projected.
551  *
552  * FI: Unfortunately, some information gathered about the input
553  * parametrs during the function analysis is lost. For instance, a
554  * pointer must be different from NULL (e.g. see argv03.c). But if you
555  * do not know if the pointer has been written or not, you do not know
556  * if the information is usable or not. This is also an issue for
557  * interprocedural analysis: can the result always be trusted for any
558  * actual input context?
559  */
561 {
563  entity e = reference_variable(r);
564  return !(variable_static_p(e) || entity_stub_sink_p(e) || top_level_entity_p(e) || entity_heap_location_p(e) /*|| formal_parameter_p(e)*/ );
565 }
566 ␌
567 /* print a points-to arc for debug */
568 void print_or_dump_points_to(const points_to pt, bool print_p)
569 {
570  if(points_to_undefined_p(pt))
571  (void) fprintf(stderr,"POINTS_TO UNDEFINED\n");
572  // For debugging with gdb, dynamic type checking
574  (void) fprintf(stderr,"Arg. \"pt\"is not a points_to.\n");
575  else {
576  cell source = points_to_source(pt);
577  cell sink = points_to_sink(pt);
579  reference r1 = cell_to_reference(source);
580  reference r2 = cell_to_reference(sink);
581  entity v1 = reference_variable(r1);
582  entity v2 = reference_variable(r2);
586 
587  fprintf(stderr,"%p ", pt);
588  if(m!=m1)
589  fprintf(stderr,"%s" MODULE_SEP_STRING, entity_local_name(m1));
590  print_reference(r1);
591  fprintf(stderr,"->");
592  if(m!=m2 && !null_cell_p(sink) && !nowhere_cell_p(sink)
594  fprintf(stderr,"%s" MODULE_SEP_STRING, entity_local_name(m2));
595  print_reference(r2);
596  fprintf(stderr," (%s)", approximation_to_string(app));
597  if(!print_p) {
598  fprintf(stderr," [%p, %p]", points_to_source(pt), points_to_sink(pt));
599  }
600  fprintf(stderr,"\n");
601  }
602 }
603 
605 {
606  print_or_dump_points_to(pt, true);
607 }
608 
609 void dump_points_to(const points_to pt)
610 {
611  print_or_dump_points_to(pt, false);
612 }
613 
614 /* Print a set of points-to for debug */
615 void print_or_dump_points_to_set(string what, set s, bool print_p)
616 {
617  fprintf(stderr,"points-to set %s:\n", what);
618  if(set_undefined_p(s))
619  fprintf(stderr, "undefined set\n");
620  else if(s==NULL)
621  fprintf(stderr, "uninitialized set\n");
622  else if(set_size(s)==0)
623  fprintf(stderr, "empty set\n");
624  else {
625  if(print_p) {
626  SET_MAP(elt, print_points_to((points_to) elt), s);
627  }
628  else {
629  SET_MAP(elt, dump_points_to((points_to) elt), s);
630  }
631  }
632  fprintf(stderr, "\n");
633 }
634 
635 void print_points_to_set(string what, set s)
636 {
637  print_or_dump_points_to_set(what, s, true);
638 }
639 
640 void dump_points_to_set(string what, set s)
641 {
642  print_or_dump_points_to_set(what, s, false);
643 }
644 ␌
645 /* test if a cell appear as a source in a set of points-to */
646 bool source_in_set_p(cell source, set s)
647 {
648  bool in_p = false;
649  SET_FOREACH ( points_to, pt, s ) {
650  /* if( opkill_may_vreference(source, points_to_source(pt) )) */
651  if(cell_equal_p(source, points_to_source(pt)))
652  return true;
653  }
654  return in_p;
655 }
656 /* test if a cell "source" appears as a source in a set of points-to */
658 {
659  bool in_p = false;
660  SET_FOREACH ( points_to, pt, s ) {
661  /* if( opkill_may_vreference(source, points_to_source(pt) )) */
662  if(cell_equal_p(source, points_to_source(pt))) {
663  in_p = true;
664  break;
665  }
666  else if(cell_included_p(points_to_source(pt), source)) {
667  in_p = true;
668  break;
669  }
670  }
671  return in_p;
672 }
673 
675 {
676  return source_in_set_p(source, points_to_graph_set(s));
677 }
678 
679 /* test if a cell appear as a sink in a set of points-to */
680 bool sink_in_set_p(cell sink, set s)
681 {
682  bool in_p = false;
683  SET_FOREACH ( points_to, pt, s ) {
684  if( cell_equal_p(points_to_sink(pt),sink) )
685  in_p = true;
686  }
687  return in_p;
688 }
689 
690 /* The approximation is not taken into account
691  *
692  * It might be faster to look up the different points-to arcs that can
693  * be made with source, sink and any approximation.
694  */
696 {
697  // FI: no longer compatible with definition of pt_map as set
698  set s = points_to_graph_set(ptm);
700  SET_FOREACH(points_to, pt, s) {
701  if(cell_equal_p(points_to_source(pt), source)
702  && cell_equal_p(points_to_sink(pt), sink) ) {
703  fpt = pt;
704  break;
705  }
706  }
707  return fpt;
708 }
709 ␌
710 /* source is assumed to be either nowhere/undefined or anywhere, it
711  * may be typed or not.
712  *
713  * Shouldn't we create NULL pointers if the corresponding property is set?
714  * Does it matter for anywhere/nowhere?
715  *
716  * pts must be updated with the new arc(s).
717  */
719 {
720  /* FI: we should return an anywhere cell with the proper type */
721  /* FI: should we add the corresponding arcs in pts? */
722  /* FI: should we take care of typed anywhere as well? */
723 
724  list sinks = NIL;
725  // reference r = cell_any_reference(source);
726  // entity v = reference_variable(r);
727  // FI: it would be better to print the reference... words_reference()...
728  // FI: sinks==NIL would be interpreted as a bug...
729  // If we dereference a nowhere/undefined, we should end up
730  // anywhere to please gcc and Fabien Coelho
731  // type vt = ultimate_type(entity_type(v));
732  bool to_be_freed;
733  type ct = points_to_cell_to_type(source, &to_be_freed);
735  if(type_variable_p(vt)) {
736  if(pointer_type_p(vt)) {
737  // FI: should nt be freed?
738  type nt = type_to_pointed_type(vt);
740  sinks = CONS(CELL, c, NIL);
741  points_to pt = make_points_to(copy_cell(source), c,
744  pts = add_arc_to_pt_map_(pt, pts);
745  }
746  else if(struct_type_p(vt)) {
747  variable vrt = type_variable(vt);
748  basic b = variable_basic(vrt);
749  entity se = basic_derived(b);
750  type st = entity_type(se);
751  pips_assert("se is an internal struct", type_struct_p(st));
752  list fl = type_struct(st);
753  FOREACH(ENTITY, f, fl) {
754  type ft = entity_type(f);
755  type uft = compute_basic_concrete_type(ft); // FI: to be freed...
756  if(pointer_type_p(uft)) {
757  cell nsource = copy_cell(source); // FI: memory leak?
758  nsource = points_to_cell_add_field_dimension(nsource, f);
759  type nt = type_to_pointed_type(uft);
761  points_to pt = make_points_to(nsource, nsink,
764  pts = add_arc_to_pt_map_(pt, pts);
765  //sinks = source_to_sinks(source, pts, false);
766  sinks = CONS(CELL, nsink, NIL);
767  }
768  else if(struct_type_p(uft)) {
769  cell nsource = copy_cell(source); // FI: memory leak?
770  nsource = points_to_cell_add_field_dimension(nsource, f);
771  sinks = anywhere_source_to_sinks(nsource, pts);
772  //pips_internal_error("Not implemented yet.\n");
773  }
774  else if(array_type_p(uft)) {
775  variable uftv = type_variable(uft);
776  basic uftb = variable_basic(uftv);
777  if(basic_pointer_p(uftb)) {
778  cell nsource = copy_cell(source); // FI: memory leak?
779  reference r = cell_any_reference(nsource);
781  type nt = ultimate_type(uft); // FI: get rid of the dimensions
783  points_to pt = make_points_to(nsource, nsink,
786  pts = add_arc_to_pt_map_(pt, pts);
787  sinks = CONS(CELL, nsink, NIL);
788  }
789  }
790  }
791  }
792  else if(array_type_p(vt)) {
793  variable uftv = type_variable(vt);
794  basic uftb = variable_basic(uftv);
795  if(basic_pointer_p(uftb)) {
796  cell nsource = copy_cell(source); // FI: memory leak?
797  reference r = cell_any_reference(nsource);
799  }
800  }
801  else if(overloaded_type_p(vt)) {
803  sinks = CONS(CELL, c, NIL);
804  points_to pt = make_points_to(copy_cell(source), c,
807  pts = add_arc_to_pt_map_(pt, pts);
808  }
809  else
810  // FI: struct might be dereferenced?
811  // FI: should this be tested when entering this function rather
812  // than expecting that the caller is safe
813  pips_internal_error("Unexpected dereferenced type.\n");
814  }
815  else if(type_area_p(vt)) {
816  // FI: this should be removed using type_overloaded for the
817  // "untyped" anywhere
819  reference r = make_reference(e, NIL);
820  cell c = make_cell_reference(r);
821  sinks = CONS(CELL, c, NIL);
822  points_to pt = make_points_to(copy_cell(source), c,
825  pts = add_arc_to_pt_map_(pt, pts);
826  }
827  else {
828  pips_internal_error("Unexpected dereferenced type.\n");
829  }
830 
831  if(to_be_freed) free_type(ct);
832 
833  return sinks;
834 }
835 ␌
836 /* For debugging */
838 {
839  if(ENDP(p))
840  fprintf(stderr, "p is empty.\n");
841  else {
842  FOREACH(CELL, c, p) {
843  if(c!=CELL(CAR(p)))
844  fprintf(stderr, "->");
846  }
847  fprintf(stderr, "\n");
848  }
849 }
850 ␌
851 /* A type "t" is compatible with a cell "c" if any of the enclosing
852  * cell "c'" of "c", including "c", is of type "t".
853  *
854  * For instance, "a.next" is included in "a". It is compatible with
855  * both the type of "a" and the type of "a.next".
856  */
858 {
859  cell nc = copy_cell(c);
860  reference nr = cell_any_reference(nc);
861  //list sl = reference_indices(nr);
862  bool compatible_p = false;
863 
864  do {
865  bool to_be_freed;
866  type nct = cell_to_type(nc, &to_be_freed);
868  compatible_p = true;
869  if(to_be_freed) free_type(nct);
870  break;
871  }
872  else if(ENDP(reference_indices(nr))) {
873  if(to_be_freed) free_type(nct);
874  break;
875  }
876  else {
877  if(to_be_freed) free_type(nct);
878  /* Remove the last subscript */
880  gen_remove(&reference_indices(nr), l);
881  }
882  } while(true);
883 
884  ifdebug(8) {
885  bool to_be_freed;
886  type ct = cell_to_type(nc, &to_be_freed);
887  pips_debug(8, "Cell of type \"%s\" is %s included in cell of type \"%s\"\n",
889  compatible_p? "":"not",
891  if(to_be_freed) free_type(ct);
892  }
893 
894  free_cell(nc);
895 
896  return compatible_p;
897 }
898 
899 /* See if a super-cell of "c" exists witf type "t". A supercell is a
900  * cell "nc" equals to cell "c" but with a shorter subscript list.
901  *
902  * This function is almost identical to the previous one.
903  *
904  * A new cell is allocated and returned.
905  */
907 {
908  cell nc = copy_cell(c);
909  reference nr = cell_any_reference(nc);
910  //list sl = reference_indices(nr);
911  bool compatible_p = false;
912 
913  do {
914  bool to_be_freed;
915  type nct = cell_to_type(nc, &to_be_freed);
916  if(type_equal_p(t, nct)) {
917  compatible_p = true;
918  if(to_be_freed) free_type(nct);
919  break;
920  }
921  else if(ENDP(reference_indices(nr))) {
922  if(to_be_freed) free_type(nct);
923  break;
924  }
925  else {
926  if(to_be_freed) free_type(nct);
927  /* Remove the last subscript */
929  gen_remove(&reference_indices(nr), l);
930  }
931  } while(true);
932 
933  ifdebug(8) {
934  bool to_be_freed;
935  type ct = cell_to_type(nc, &to_be_freed);
936  pips_debug(8, "Cell of type \"%s\" is %s included in cell of type \"%s\"\n",
939  compatible_p? "":"not");
940  if(to_be_freed) free_type(ct);
941  if(compatible_p) {
942  pips_debug(8, "Type compatible cell \"");
944  fprintf(stderr, "\"\n.");
945  }
946  }
947 
948  return nc;
949 }
950 
951 ␌
952 /* Find the "k"-th node of type "t" in list "p". Beware of cycles? No
953  * reason since "p" is bounded... The problem must be addressed when
954  * "p" is built.
955  *
956  * An issue with "t": the nodes are references and they carry multiple
957  * types, one for each number of subscripts or fields they have. So
958  * for instance, s1 and s1.next denote the same location.
959  */
961 {
962  int count = 0;
963  cell kc = cell_undefined;
964  FOREACH(CELL, c, p) {
965  // bool to_be_freed;
966  // type ct = cell_to_type(c, &to_be_freed);
967  // if(type_equal_p(t, ct)) {
969  count++;
970  if(count==k) {
971  kc = type_compatible_super_cell(t,c);
972  break;
973  }
974  }
975  }
976  ifdebug(8) {
977  pips_debug(8, "Could not find %d nodes of type \"%s\" in path \"", k,
980  fprintf(stderr, "\"\n");
981  }
982  return kc;
983 }
984 ␌
986 {
987  bool in_path_p = false;
988  FOREACH(CELL, c, p) {
989  if(cell_equal_p(c, n)) {
990  in_path_p = true;
991  break;
992  }
993  }
994  return in_path_p;
995 }
996 ␌
997 /* "p" is a points-to path ending with a cell that points towards a
998  * new cell ot type "t". To avoid creating infinite/unbounded path, no
999  * more than k nodes of type "t" can be present in path "p". If k are
1000  * found, a cycle is created to represent longer paths. The
1001  * corresponding arc is returned. If the creation condition is not
1002  * met, do not create a new arc.
1003  */
1005  int k,
1006  type t,
1007  bool array_p,
1008  pt_map in)
1009 {
1010  pips_assert("p contains at least one element", !ENDP(p));
1011 
1013  cell c = CELL(CAR(p));
1014  list sources = sink_to_sources(c, points_to_graph_set(in), false); // No duplication of cells
1015 
1016  if(ENDP(sources)) {
1017  /* The current path cannot be made any longer */
1018 
1019  /* Find the k-th node of type "t" if it exists */
1021  if(!cell_undefined_p(kc)) {
1022  // cell nkc = copy_cell(kc);
1023  // The above function should return a freshly allocated cell or
1024  // a cell_undefined
1025  cell nkc = kc;
1026  cell source = copy_cell(CELL(CAR(gen_last(p))));
1027  pt = make_points_to(source, nkc, make_approximation_may(),
1029  }
1030  }
1031  else {
1032  FOREACH(CELL, source, sources) {
1033  /* Skip sources that are already in the path "p" so as to avoid
1034  infinite path due to cycles in points-to graph "in". */
1035  if(node_in_points_to_path_p(source, p)) {
1036  ; // Could be useful for debugging
1037  }
1038  else {
1039  list np = CONS(CELL, source, p); // make the path longer
1040  // And recurse
1041  pt = points_to_path_to_k_limited_points_to_path(np, k, t, array_p, in);
1042  // And restore p
1043  CDR(np) = NIL;
1044  gen_free_list(np);
1045  if(!points_to_undefined_p(pt)) // Stop as soon as an arc has been created; FI->AM/FC: may not be correct...
1046  break;
1047  }
1048  }
1049  }
1050  return pt;
1051 }
1052 ␌
1053 
1054 /* Create a new node "sink" of type "t" and a new arc "pt" starting
1055  * from node "source", if no path starting from any node and ending in
1056  * "source", built with arcs in the points-to set "in", contains more
1057  * than k nodes of type "t" (the type of the sink). If k nodes of type
1058  * "t" are already in the path, create a new arc "pt" between the
1059  * "source" and the k-th node in the path.
1060  *
1061  * Parameter "array_p" indicates if the source is an array or a
1062  * scalar. Different models can be chosen. For instance, Beatrice
1063  * Creusillet wants to have an array as target and obtain something
1064  * like argv[*]->_argv_1[*] although argv[*]->_argv-1 might also be a
1065  * correct model if _argv_1 is an abstract location representing lots
1066  * of different physical locations.
1067  *
1068  * Parameter k is defined by a property.
1069  *
1070  * FI: not to clear about what is going to happen when "source" is the
1071  * final node of several paths.
1072  *
1073  * Also, beware of circular paths.
1074  *
1075  * Efficiency is not yet a goal...
1076  */
1078 {
1079  int k = get_int_property("POINTS_TO_PATH_LIMIT");
1080  pips_assert("k is greater than one", k>=1);
1082 
1083  // FI: the vertex with an excessive out-degree does not have to be
1084  // source and is not source in list05 case... The test below is useless
1085 
1086  // We should check the out-degree of each source in "in" and see if
1087  // any is beyond limit.
1088 
1089  //list sink_l = points_to_source_to_sinks(source, in, false);
1090  //int od = (int) gen_length(sink_l);
1091  //string mod_cell_name = string_undefined; // maximum out-degree cell
1092  //int od = maximal_out_degree_of_points_to_graph(&mod_cell_name, in);
1093  // list sink_l = points_to_source_to_sinks(mod_cell_name, in, false);
1094  //list sink_l = points_to_source_name_to_sinks(mod_cell_name, in, false);
1095  if(false /*&& od>=odl*/ ) {
1096  // FI: not too sure about argument "true"
1097  //cell mod_cell = points_to_source_name_to_source_cell(mod_cell_name, in, true);
1098  //pt = fuse_points_to_sink_cells(mod_cell, sink_l, in);
1099  ;
1100  }
1101  else {
1102  list p = CONS(CELL, source, NIL); // points-to path...
1103 
1104  // FI: not to sure about he possible memory leaks...
1105  pt = points_to_path_to_k_limited_points_to_path(p, k, t, array_p, in);
1106 
1107  /* No cycle could be created, the paths can safely be made longer. */
1108  if(points_to_undefined_p(pt)) {
1109  // exact or not?
1110  // FI: the points-to towards NULL will be added later by a caller...
1111  bool exact_p = !get_bool_property("POINTS_TO_NULL_POINTER_INITIALIZATION");
1112  pt = create_stub_points_to(source, t, exact_p);
1113  }
1114  gen_free_list(p);
1115  }
1116  return pt;
1117 }
1118 ␌
1119 /* Build a list of possible cell sources for cell "sink" in points-to
1120  * graph "pts". If fresh_p is set, allocate new cells, if not just
1121  * build the spine of the list.
1122  */
1123 list sink_to_sources(cell sink, set pts, bool fresh_p)
1124 {
1125  list sources = NIL;
1126 
1127  // FI: This is a short-term short cut
1128  // The & operator can be applied to anything
1129  // We should start with all subscripts and then get rid of subscript
1130  // one by one and each time add a new source
1131 
1132  /* Get rid of the constant subscripts since they are not direclty
1133  part of the points-to scheme on the sink side */
1134  //entity v = reference_variable(cell_any_reference(sink));
1135  //reference nr = make_reference(v, NIL);
1136  //cell nsink = make_cell_reference(nr);
1137 
1138  /* 1. Try to find the source in the points-to information */
1139  SET_FOREACH(points_to, pt, pts) {
1140  // FI: a more flexible test is needed as the sink cell may be
1141  // either a, or a[0] or a[*] or a[*][*] or...
1142  //if(cell_equal_p(nsink, points_to_sink(pt))) {
1143  if(related_points_to_cells_p(sink, points_to_sink(pt))) {
1144  cell sc = fresh_p? copy_cell(points_to_source(pt))
1145  : points_to_source(pt);
1146  sources = CONS(CELL, sc, sources);
1147  }
1148  }
1149  //free_cell(nsink);
1150  return sources;
1151 }
1152 ␌
1153 list stub_source_to_sinks(cell source, pt_map pts, bool fresh_p)
1154 {
1155  list sinks = NIL;
1156  reference r = cell_any_reference(source);
1157  list sl = reference_indices(r);
1158  if(ENDP(sl))
1159  sinks = scalar_stub_source_to_sinks(source, pts, fresh_p);
1160  else
1161  sinks = array_stub_source_to_sinks(source, pts, fresh_p);
1162  return sinks;
1163 }
1164 
1165 list scalar_stub_source_to_sinks(cell source, pt_map pts, bool fresh_p)
1166 {
1167  list sinks = generic_stub_source_to_sinks(source, pts, false, fresh_p);
1168  return sinks;
1169 }
1170 
1171 list array_stub_source_to_sinks(cell source, pt_map pts, bool fresh_p)
1172 {
1173  list sinks = generic_stub_source_to_sinks(source, pts, true, fresh_p);
1174  return sinks;
1175 }
1176 
1177 list generic_stub_source_to_sinks(cell source, pt_map pts, bool array_p, bool fresh_p)
1178 {
1179  list sinks = NIL;
1180  bool null_initialization_p =
1181  get_bool_property("POINTS_TO_NULL_POINTER_INITIALIZATION");
1182  //type ost = ultimate_type(entity_type(v));
1183  bool to_be_freed; // FI: memory leak for the time being
1184  type rt = cell_to_type(source, &to_be_freed); // reference type
1185  if(pointer_type_p(rt)) {
1186  // bool array_p = array_type_p(rt); FI: always false if pointer_type_p(rt)
1187  type nst = type_to_pointed_type(rt);
1188  points_to pt = create_k_limited_stub_points_to(source, nst, array_p, pts);
1189  pts = add_arc_to_pt_map_(pt, pts);
1191  sinks = source_to_sinks(source, pts, fresh_p);
1192  if(null_initialization_p) {
1193  // FI: I'm lost here... both with the meaning of null
1194  // initialization_p and with the insertion of a
1195  // corresponding arc in "pts"
1196  list ls = null_to_sinks(source, pts);
1197  sinks = gen_nconc(ls, sinks);
1198  }
1199  }
1200  else if(struct_type_p(rt)) {
1201  // FI FI FI - to be really programmed with the field type
1202  // FI->AM: I am really confused about what I am doing here...
1203  variable vrt = type_variable(rt);
1204  basic b = variable_basic(vrt);
1205  entity se = basic_derived(b);
1206  type st = entity_type(se);
1207  pips_assert("se is an internal struct", type_struct_p(st));
1208  list fl = type_struct(st);
1209  FOREACH(ENTITY, f, fl) {
1210  type ft = entity_type(f);
1211  type uft = ultimate_type(ft);
1212  bool array_p = array_type_p(ft); // not consistent with ultimate_type()
1213  points_to pt = create_k_limited_stub_points_to(source, uft, array_p, pts);
1214  pts = add_arc_to_pt_map_(pt, pts);
1216  sinks = source_to_sinks(source, pts, fresh_p);
1217  }
1218  }
1219  else if(array_type_p(rt)) {
1220  if(array_of_pointers_type_p(rt)) {
1221  cell ns = copy_cell(source);
1225  type nspt = type_to_pointed_type(nst);
1226  bool array_p = true;
1227  points_to pt = create_k_limited_stub_points_to(ns, nspt, array_p, pts);
1228  pts = add_arc_to_pt_map_(pt, pts);
1230  // sinks = source_to_sinks(source, pts, false); should be ns instead of source
1232  sinks = source_to_sinks(source, pts, fresh_p);
1233  //sinks = source_to_sinks(ns, pts, false);
1234  //sinks = CONS(CELL, copy_cell(points_to_sink(pt)), NIL);
1235  // FI: this is usually dealt with at the source_to_sinks() level...
1236  list nsinks = points_to_cell_null_initialization(ns, pts);
1237  sinks = gen_nconc(sinks, nsinks);
1238  }
1239  else {
1240  reference r = cell_any_reference(source);
1241  entity v = reference_variable(r);
1242  printf("Entity \"%s\"\n", entity_local_name(v));
1243  pips_internal_error("Not implemented yet.\n");
1244  }
1245  }
1246  else {
1247  /* The source type cannot contain a pointer field: for instance,
1248  int or char */
1249  fprintf(stderr, "Type of source: \"");
1250  print_type(rt);
1251  fprintf(stderr, "\"\n");
1252  pips_internal_error("Type of source is incompatible with a source\n");
1253  }
1254  return sinks;
1255 }
1256 ␌
1257 /* If the subscripts of the effective cell source "ec" are more
1258  * precise than the subscripts of the cell "fc" found in the points-to
1259  * set, update the subscript of the sink cell "sc" accordingly.
1260  *
1261  * For instance, if "ec==q[0]" and "fc=q[*]" and "sc=_q_1[*]",
1262  * transform "sc" into "_q_1[0]".
1263  *
1264  * Also, if "ec==_nl_1[next]" and "fc=_nl_1" and "sc=_nl_1",
1265  * transform "sc" into "_nl_1[next]"
1266  *
1267  * This function has not been designed properly. It is extended as
1268  * needed...
1269  */
1271 {
1272  reference rsc = cell_any_reference(sc);
1273  reference rec = cell_any_reference(ec);
1274  reference rfc = cell_any_reference(fc);
1275  list slrsc = reference_indices(rsc);
1276 
1277  if(true || !ENDP(slrsc)) { // The first loop will be skipped
1278  list slrec = reference_indices(rec);
1279  list slrfc = reference_indices(rfc);
1280  list cslrsc = slrsc;
1281  list cslrec = slrec;
1282  list cslrfc = slrfc;
1283  /* Take care of subscripts */
1284  for( ; !ENDP(cslrsc) && !ENDP(cslrec) && !ENDP(cslrfc);
1285  POP(cslrsc), POP(cslrec), POP(cslrfc)) {
1286  expression ecs = EXPRESSION(CAR(cslrec));
1287  expression fcs = EXPRESSION(CAR(cslrfc));
1288  // FI: a less crude test would save some work, but this is not
1289  // the point right now...
1290  if(unbounded_expression_p(fcs)) {
1291  free_expression(EXPRESSION(CAR(cslrsc)));
1292  EXPRESSION_(CAR(cslrsc)) = copy_expression(ecs);
1293  }
1294  }
1295  if(!ENDP(cslrec)) {
1296  //pips_assert("cslrsc and cslrfc are empty",
1297  // ENDP(cslrsc) && ENDP(cslrfc));
1298  if(ENDP(cslrsc) && ENDP(cslrfc)) {
1299  /* Take care of fields */
1300  list nsl = gen_full_copy_list(cslrec);
1301  reference_indices(rsc) = gen_nconc(reference_indices(rsc), nsl);
1302  }
1303  else {
1304  /* We are in trouble for the time being. Here is an example:
1305  *
1306  * Arc is: "p[*]->*HEAP*_l_72". Where does p[0] point tp?
1307  */
1308  ; // Keep the current target unchanged
1309  }
1310  }
1311  }
1312 }
1313 ␌
1314 /* If required according to the property, create a new arc from cell
1315  * "c" to "null". Cell "c" is absorbed not by the points_to created and
1316  * added to set "pts".
1317  */
1319 {
1320  list sinks = NIL;
1321  bool null_initialization_p =
1322  get_bool_property("POINTS_TO_NULL_POINTER_INITIALIZATION");
1323  if(null_initialization_p) {
1324  sinks = null_to_sinks(c, pts);
1325  }
1326  return sinks;
1327 }
1328 ␌
1330 {
1331  list sinks = NIL;
1332  bool uninitialized_dereferencing_p =
1333  get_bool_property("POINTS_TO_UNINITIALIZED_POINTER_DEREFERENCING");
1334 
1335  if(uninitialized_dereferencing_p) {
1336  reference r = cell_any_reference(source);
1337  entity v = reference_variable(r);
1338  pips_user_warning("Possibly undefined pointer \"%s\" is dereferenced.\n",
1339  entity_local_name(v));
1340  sinks = anywhere_source_to_sinks(source, pts);
1341  }
1342 
1343  return sinks;
1344 }
1345 
1347 {
1348  list sinks = NIL;
1349  bool null_dereferencing_p =
1350  get_bool_property("POINTS_TO_NULL_POINTER_DEREFERENCING");
1351 
1352  if(null_dereferencing_p) {
1353  reference r = cell_any_reference(source);
1354  entity v = reference_variable(r);
1355  pips_user_warning("Possibly null pointer \"%s\" is dereferenced.\n",
1356  entity_local_name(v));
1357  sinks = anywhere_source_to_sinks(source, pts);
1358  }
1359 
1360  return sinks;
1361 }
1362 
1363 /* Creation of a stub for a formal parameter or for a reference based
1364  * on a formal parameter. The formal parameter may be a pointer, an
1365  * array of something or a struct of something and so on recursively.
1366  *
1367  * New dimensions may have to be added to the sink type if the source
1368  * entity type is an array or if the types are assumed not strict for
1369  * pointer arithmetic. This is a general issue for stub generation and
1370  * dealt with at a lower level.
1371  *
1372  * Because references must be considered, it is not clear that formal
1373  * parameters must be handled differently from stubs or global
1374  * variables. The initial decision was made, I believe, because they
1375  * were assumed references in a very simple way, for instance as
1376  * simple direct references.
1377  *
1378  * Test cases: argv03.c
1379  */
1380 list formal_source_to_sinks(cell source, pt_map pts, bool fresh_p)
1381 {
1382  list sinks = NIL;
1383 
1384  bool null_initialization_p =
1385  get_bool_property("POINTS_TO_NULL_POINTER_INITIALIZATION");
1386  // bool strict_p = get_bool_property("POINTS_TO_STRICT_POINTER_TYPES");
1387 
1388  reference r = cell_any_reference(source);
1389  entity v = reference_variable(r);
1390  //type vt = compute_basic_concrete_type(entity_type(v));
1392  //bool to_be_freed;
1393  //type source_t =
1394  // compute_basic_concrete_type(points_to_cell_to_type(source, &to_be_freed));
1395  type source_t = points_to_cell_to_concrete_type(source);
1396 
1397  pips_assert("The source type is a pointer type", C_pointer_type_p(source_t));
1399 
1400  // FI: the type retrieval must be improved for arrays & Co
1401  // FI: This is not going to work with typedefs...
1402  // FI: You need array_p to depend on the dimensionality of the
1403  // reference as it may have arrays at several level, intertwinned with
1404  // structs.
1405  bool array_p = array_type_p(vt);
1406  // Should be points_to_cell_dimension(), counting the number of
1407  // numerical or unbounded dimensions.
1408 
1409  // Beware of void *: it is hard to declare an array of "void", make it "char"
1410  // But this is performed at a lower level
1411  /*
1412  type ast = type_undefined;
1413  if(type_void_p(st))
1414  ast = make_scalar_integer_type(DEFAULT_CHARACTER_TYPE_SIZE);
1415  else
1416  ast = copy_type(st);
1417  */
1418 
1419  points_to pt = create_k_limited_stub_points_to(source, st, array_p, pts);
1420 
1421  //free_type(ast);
1422 
1423  if(null_initialization_p) {
1426  }
1427  pts = add_arc_to_pt_map_(pt, pts);
1429  sinks = source_to_sinks(source, pts, fresh_p);
1430  if(null_initialization_p){
1431  list ls = null_to_sinks(source, pts);
1432  sinks = gen_nconc(ls, sinks);
1433  }
1434 
1435  return sinks;
1436 }
1437 
1438 list global_source_to_sinks(cell source, pt_map pts, bool fresh_p)
1439 {
1440  bool null_initialization_p =
1441  get_bool_property("POINTS_TO_NULL_POINTER_INITIALIZATION");
1442  reference r = cell_any_reference(source);
1443  entity v = reference_variable(r);
1444  type t = entity_type(v);
1445  list sinks = NIL;
1447  type st = type_undefined;
1449 
1450  bool strict_p = get_bool_property("POINTS_TO_STRICT_POINTER_TYPES");
1451  if(scalar_type_p(ist) && !strict_p) {
1452  /* Add an implicit dimension for pointer arithmetic */
1453  st = type_to_array_type(ist);
1454  }
1455  else
1456  st = copy_type(ist);
1457 
1458  if(const_variable_p(v)) {
1460  sinks = expression_to_points_to_sinks(init, pts);
1462  /* Add these new arcs to the context */
1463  bool exact_p = gen_length(sinks)==1;
1464  FOREACH(CELL, sink, sinks) {
1465  cell nsource = copy_cell(source);
1466  cell nsink = copy_cell(sink);
1467  approximation na = exact_p? make_approximation_exact():
1469  points_to npt = make_points_to(nsource, nsink, na,
1471  pts = add_arc_to_pt_map_(npt, pts);
1473  }
1474  }
1475  else {
1476  /* Do we have to ignore an initialization? */
1477  value val = entity_initial(v);
1478  if(!value_unknown_p(val))
1479  pips_user_warning("Initialization of global variable \"%s\" is ignored "
1480  "because the \"const\" qualifier is not used.\n",
1481 
1482  entity_user_name(v));
1483  //bool array_p = array_type_p(st);
1484  bool array_p = array_type_p(t); // array_p is related to the source
1485  pt = create_k_limited_stub_points_to(source, st, array_p, pts);
1486 
1487  // FI: cut-and-pasted from line 945
1488  if(null_initialization_p) {
1491  }
1492  pts = add_arc_to_pt_map_(pt, pts);
1494  sinks = source_to_sinks(source, pts, fresh_p);
1495  if(null_initialization_p){
1496  list ls = null_to_sinks(source, pts);
1497  sinks = gen_nconc(ls, sinks);
1498  }
1499  }
1500 
1501  return sinks;
1502 }
1503 ␌
1504 /* This function is designed to work properly for the translation of
1505  * effects at call sites. ptm is assumed to be a translation
1506  * mapping.
1507  *
1508  * Knowing that v(o_sl) is translated into w(d_sl), what is the
1509  * translation of v(sl), w[tsl], assuming that o_sl, d_sl and sl are all
1510  * subscript lists?
1511  *
1512  * We assume that |o_sl|<|sl| because otherwise v[o_sl] would not be a
1513  * constant memory location (?). We assume that |o_sl|<|d_sl| because
1514  * we do not modelize sharing.
1515  *
1516  * tsl is the result of the concatenation of three subscripts lists: a
1517  * prefix made of the first subscripts of d_sl that are not covered by
1518  * sl, the other subscripts of d_sl, updated according to the
1519  * subscript values in sl, and a suffix, the subscripts in sl that
1520  * have not equivalent in o_sl.
1521  *
1522  * Update the last subscripts. E.g. _x_3[*] and _x_3[0] -> y[i][0]
1523  * leads to y[i][*] (see EffectsWithPointsTo/call05.c or call01.c).
1524  *
1525  * Update the last subscripts. E.g. _q_2[0][one] and _q_2[0] -> s leads
1526  * to s[one] (see EffectsWithPointsTo/call05.c).
1527  *
1528  * Update the last subscripts. E.g. _x_3[4] and _x_3[0] -> y[*][1]
1529  * leads to y[*][5]... A proof is needed to justify the subscript
1530  * addition... if only to show that _x_3[0] is acceptable to claim
1531  * something about _x_[4]... (see EffectsWithPointsTo.sub/call08,c).
1532  *
1533  * Same thing with _x_3[i] and _x_3[0] -> y[*][j]?
1534  *
1535  * This functions is similar to what must be done to compute the sink
1536  * or the source of an expression, but here both the subscript list sl
1537  * and the sinks of the points-to arcs in ptm do not have to be
1538  * constant paths.
1539  */
1541 {
1542  // list of translated cells corresponding to the reference v[sl]
1543  list tl = NIL;
1544  set ptm_s = points_to_graph_set(ptm);
1545  SET_FOREACH(points_to, pt, ptm_s) {
1546  cell d = points_to_sink(pt);
1547  /* null and undefined targets are not possible */
1548  if(!null_cell_p(d) && !nowhere_cell_p(d)) {
1549  cell o = points_to_source(pt);
1550  reference o_r = cell_any_reference(o);
1551  entity o_v = reference_variable(o_r);
1552  if(o_v == v) {
1553  /* Are the subscript lists compatible? */
1554  list o_sl = reference_indices(o_r);
1555  list csl = sl, co_sl = o_sl;
1556  bool compatible_p = true;
1557  while(!ENDP(csl) && !ENDP(co_sl)) {
1558  expression sl_e = EXPRESSION(CAR(csl));
1559  expression o_sl_e = EXPRESSION(CAR(co_sl));
1560  if(unbounded_expression_p(sl_e)
1561  || unbounded_expression_p(o_sl_e)
1562  || expression_equal_p(sl_e, o_sl_e))
1563  ;
1566  /* Offset to be applied... */
1567  ;
1568  else {
1569  compatible_p = false;
1570  break;
1571  }
1572  POP(csl), POP(co_sl);
1573  }
1574  if(compatible_p && ENDP(csl) && ENDP(co_sl)
1575  && expression_lists_equal_p(sl, o_sl)) {
1576  /* We have an equality between the effect and the origin */
1578  if(!points_to_cell_in_list_p(tc, tl))
1579  tl = CONS(CELL, tc, tl);
1580  else
1581  free_cell(tc);
1582  }
1583  else if(compatible_p) {
1584  reference d_r = cell_any_reference(d);
1585  list d_sl = reference_indices(d_r);
1586  /* The subscripts left in csl must be appended to the new sink */
1587  int nsl = (int) gen_length(sl);
1588  int no_sl = (int) gen_length(o_sl);
1589  int nd_sl = (int) gen_length(d_sl);
1590  int np = nd_sl-no_sl; // #subscripts linked to the destination only
1591  // np may b negative because the source has a [0] subscript
1592  // that is non-significant
1593  int ns = nsl-no_sl; // #subscripts linked to the new source only
1594  int nb = no_sl; // #subscripts to update for body, unless np is <0
1595  pips_assert("the suffix and the body have positive length",
1596  ns>=0 && nb>=0);
1597  int i = 0;
1598  // The new subscript list is built backwards
1599  list tsl = NIL;
1600  list cd_sl = d_sl;
1601  /* Build the prefix */
1602  for(i=0; i<np; i++) {
1603  expression se = EXPRESSION(CAR(cd_sl));
1604  tsl = CONS(EXPRESSION,copy_expression(se), tsl);
1605  POP(cd_sl);
1606  }
1607  /* Build the body: depending on the subscripts in sl and o_sl,
1608  update or not the susbcripts in cd_sl */
1609  co_sl = o_sl;
1610  csl = sl;
1611  /* Skip subscripts not reproduced in the destination */
1612  while(np<0) {
1613  POP(csl), np++, nb--;
1614  }
1615  for(i=0;i<nb; i++) {
1616  expression sl_e = EXPRESSION(CAR(csl));
1617  expression d_sl_e = EXPRESSION(CAR(cd_sl));
1618  if(unbounded_expression_p(sl_e))
1619  tsl = CONS(EXPRESSION,copy_expression(sl_e), tsl);
1620  else if(unbounded_expression_p(d_sl_e))
1621  tsl = CONS(EXPRESSION,copy_expression(d_sl_e), tsl);
1622  else if(zero_expression_p(sl_e))
1623  tsl = CONS(EXPRESSION,copy_expression(d_sl_e), tsl);
1624  else if(zero_expression_p(d_sl_e))
1625  tsl = CONS(EXPRESSION,copy_expression(sl_e), tsl);
1626  else {
1627  value sl_v = EvalExpression(sl_e);
1628  value d_sl_v = EvalExpression(d_sl_e);
1630  if(value_constant_p(sl_v) && value_constant_p(d_sl_v)) {
1631  constant sl_c = value_constant(sl_v);
1632  constant d_sl_c = value_constant(d_sl_v);
1633  if(constant_int_p(sl_c) && constant_int_p(d_sl_c)) {
1634  // Possible overflow
1635  int nic = constant_int(sl_c)+constant_int(d_sl_c);
1636  ne = int_to_expression(nic);
1637  }
1638  }
1639  if(expression_undefined_p(ne))
1641  copy_expression(d_sl_e),
1642  copy_expression(sl_e));
1643  tsl = CONS(EXPRESSION, ne, tsl);
1644  }
1645  POP(csl);
1646  POP(co_sl);
1647  POP(cd_sl);
1648  }
1649  /* Build the suffix */
1650  while(!ENDP(csl)) {
1651  expression sl_e = EXPRESSION(CAR(csl));
1652  tsl = CONS(EXPRESSION,copy_expression(sl_e), tsl);
1653  POP(csl);
1654  }
1655  tsl = gen_nreverse(tsl);
1656  /* Check the resulting length */
1657  int ntsl = (int) gen_length(tsl);
1658  pips_assert("The resulting", ntsl==np+nb+ns);
1659  entity d_v = reference_variable(d_r);
1660  type d_v_t = entity_basic_concrete_type(d_v);
1662  if(type_functional_p(d_v_t)) {
1663  /* Do no index constant character strings */
1664  tr = make_reference(d_v, NIL);
1665  gen_free_list(tsl);
1666  }
1667  else
1668  tr = make_reference(d_v, tsl);
1669  cell tc = make_cell_reference(tr);
1670  if(!points_to_cell_in_list_p(tc, tl))
1671  tl = CONS(CELL, tc, tl);
1672  else
1673  free_cell(tc);
1674  }
1675  }
1676  }
1677  }
1678  return tl;
1679 }
1680 
1681 /* FI: easier it fresh_p is true... */
1683  list sl,
1684  pt_map ptm,
1685  bool fresh_p)
1686 {
1687  pips_assert("fresh_p must be set to true", fresh_p);
1688  list translations = NIL;
1689  // cell n_c = make_cell_reference(n_r); // FI: memory leak
1690  //list atl = points_to_source_to_sinks(n_c, ptm, fresh_p); // Address Translation List?
1691  // list atl = points_to_source_to_any_sinks(n_c, ptm, fresh_p); // Address Translation List?
1692  list atl = NIL;
1693  entity v = reference_variable(n_r);
1694  // matching list of points-to arcs:
1695  //list ml = source_entity_to_points_to(v, sl, ptm);
1696  list ml = reference_to_points_to_translations(v, sl, ptm);
1697  return ml;
1698 
1699  if(ENDP(ml)) {
1700  if(ENDP(sl)) {
1701  pips_internal_error("Reference \"n_r\" cannot be translated with \"ptm\".\n");
1702  }
1703  else {
1704  /* Try to use an extra subscript */
1705  expression ns = EXPRESSION(CAR(sl));
1708  translations = points_to_reference_to_translation(n_r, CDR(sl), ptm, fresh_p);
1709  }
1710  }
1711  else {
1712  /* We've got one translation at least. Now, we must update the subscripts. */
1713  FOREACH(CELL, c, atl) {
1714  if(!null_cell_p(c) && !nowhere_cell_p(c)) {
1715  reference c_r = cell_any_reference(c);
1716  /* We assume that c has at least as many subscripts as n_r */
1717  int c_d = (int) gen_length(reference_indices(c_r));
1718  int r_d = (int) gen_length(reference_indices(n_r))+gen_length(sl);
1719  //pips_assert("The target dimension is larger than the source dimension",
1720  // c_d>=r_d);
1721  int o = c_d-r_d;
1722  if(o==0) {
1724  gen_full_copy_list(sl));
1725  }
1726  else if(o>0) {
1727  /* Update the last subscripts. E.g. _x_3[*] and _x_3[0]
1728  ->y[i][0] leads to y[i][*] (see EffectsWithPointsTo/call05.c) */
1729  list csl = reference_indices(c_r);
1730  list acsl = gen_nthcdr(o-1, csl);
1731  CDR(acsl) = gen_nconc(reference_indices(n_r),
1732  gen_full_copy_list(sl));
1733  }
1734  else {
1735  /* Update the last subscripts. E.g. _q_2[0][one] and _q_2[0]
1736  ->s leads to s[one] (see EffectsWithPointsTo/call05.c) */
1737  // FI: it should be more complex, but I'll wait for more examples...
1739  }
1740  translations = atl; // FI: we may not need to variables...
1741  }
1742  }
1743  }
1744  return translations;
1745 }
1746 
1747 /* Use "ptm" as a translation map
1748  *
1749  * Must be similar to a function written by Beatrice to evaluate a
1750  * complex reference according to points-to information. In her case,
1751  * it is not a translation, but an evaluation of the possibly many
1752  * dereferencements contained in the reference.
1753  *
1754  * Try to translate a prefix of the source reference and substitue it
1755  * when a translation is found. No need to translate further down,
1756  * unlike Beatrice's function.
1757  *
1758  * fresh_p might be useless because new cells always must be generated.
1759  */
1761 {
1762  //list translations = points_to_source_to_sinks(source, ptm, fresh_p);
1763  reference r = cell_any_reference(source);
1764  entity v = reference_variable(r);
1765  list translations = NIL;
1766 
1767  if(ENDP(translations)) {
1768  /* Outdated comment: The cell source is not a source in ptm, but a
1769  related cell may be the source */
1770  list sl = reference_indices(r);
1771  reference n_r = make_reference(v, NIL);
1772  translations = points_to_reference_to_translation(n_r, sl, ptm, fresh_p);
1773  }
1774 
1775  ifdebug(8) {
1776  bool to_be_freed;
1777  type source_t = points_to_cell_to_type(source, &to_be_freed);
1778  type source_et = compute_basic_concrete_type(source_t);
1779  FOREACH(CELL, c, translations) {
1780  if(!null_cell_p(c) && !nowhere_cell_p(c) && !anywhere_cell_p(c)) {
1781  bool c_to_be_freed;
1782  type c_t = points_to_cell_to_type(c, &c_to_be_freed);
1783  type c_et = compute_basic_concrete_type(c_t);
1784  if(!overloaded_type_p(c_et) && !type_equal_p(source_et, c_et)
1785  /* Beware of constant strings... */
1786  && !type_functional_p(c_et))
1787  pips_internal_error("Type mismatch after translation.\n");
1788  if(c_to_be_freed) free_type(c_t);
1789  }
1790  }
1791  if(to_be_freed) free_type(source_t);
1792  }
1793 
1794  return translations;
1795 }
1796 ␌
1797 /* Build the sinks of source "source" according to the points-to
1798  * graphs. If "source" is not found in the graph, return an empty list
1799  * "sinks". If "fresh_p", allocate copies. If not, return pointers to
1800  * the destination vertices in "ptm".
1801  *
1802  * It is not clear how much the abstract address lattice must be used
1803  * to retrieve sinks... If source = a[34], clearly a[*] is an OK
1804  * equivalent source if a[34] is not a vertex of "ptm".
1805  *
1806  * If !strict_p, "a[34]" is considered a source for "a[*]". This
1807  * should always be the case. So strict_p should always be false.
1808  *
1809  * If all_p, look for all possible sinks. For instance, if a[34] and
1810  * a[*] have different sinks, return their union. If !all_p, stop the
1811  * search if a[34] has sinks. This should now be obsolete thanks to
1812  * exact_p. So all_p should always be true.
1813  *
1814  * effective_p: you only want sinks that are not NULL and not
1815  * UNDEFINED/NOWHERE. For instance, because you know you will
1816  * dereference it.
1817  *
1818  * Note: we must also take into account the approximations of the arcs...
1819  *
1820  * This is a key point of Amira's dissertation, but it has not been
1821  * handled properly yet...
1822  */
1824  bool fresh_p,
1825  bool strict_p,
1826  bool all_p,
1827  bool effective_p)
1828 {
1829  list sinks = NIL;
1830  set pts = points_to_graph_set(ptm);
1831 
1832  /* 1. See if cell "source" is the starting vertex of a points-to arc. */
1833  bool exact_p = false;
1834  SET_FOREACH( points_to, pt, pts) {
1835  if(cell_equal_p(source, points_to_source(pt))) {
1836  cell sink = points_to_sink(pt);
1837  if(!effective_p || (!nowhere_cell_p(sink) && !null_cell_p(sink))) {
1839  cell sc = fresh_p? copy_cell(sink) : sink;
1840  sinks = CONS(CELL, sc, sinks);
1842  if(exact_p)
1843  pips_internal_error("Two contradictory arcs in ptm\n");
1844  else
1845  exact_p = true;
1846  }
1847  }
1848  }
1849  }
1850 
1851  /* 2. Much harder... See if source is contained in one of the many
1852  abstract sources. Step 1 is subsumed by Step 2... but is much faster. */
1853  if(ENDP(sinks) || (all_p && !exact_p)) {
1854  SET_FOREACH(points_to, pt, pts) {
1855  if(cell_included_p(source, points_to_source(pt))) {
1856  cell sink = points_to_sink(pt);
1857  if(!effective_p || (!nowhere_cell_p(sink) && !null_cell_p(sink))) {
1858  // FI: memory leak forced because of refine_points_to_cell_subscripts
1859  cell sc = (true||fresh_p)? copy_cell(sink) : sink;
1860  // FI->AM: if "source" is stricly included in
1861  // "points_to_source(pt)", the subscript expression of sc
1862  // might have to be cleaned up
1863  //
1864  // Which implies to allocate a new copy of sc no matter what
1865  // fresh_p prescribes...
1867  if(!points_to_cell_in_list_p(sc, sinks))
1868  sinks = CONS(CELL, sc, sinks);
1869  }
1870  }
1871  }
1872  }
1873 
1874  /* 3. Much harder... See if source contains one of the many
1875  abstract sources. */
1876  if((ENDP(sinks) && !strict_p) || all_p) {
1877  SET_FOREACH(points_to, pt, pts) {
1878  if(cell_included_p(points_to_source(pt), source)) {
1879  cell sink = points_to_sink(pt);
1880  if(!effective_p || (!nowhere_cell_p(sink) && !null_cell_p(sink))) {
1881  // FI: memory leak forced because of refine_points_to_cell_subscripts
1882  cell sc = (true||fresh_p)? copy_cell(sink) : sink;
1883  // FI->AM: if "source" is stricly included in
1884  // "points_to_source(pt)", the subscript expression of sc
1885  // might have to be cleaned up
1886  //
1887  // Which implies to allocate a new copy of sc no matter what
1888  // fresh_p prescribes...
1890  if(!points_to_cell_in_list_p(sc, sinks))
1891  sinks = CONS(CELL, sc, sinks);
1892  }
1893  }
1894  }
1895  }
1896 
1897  return sinks;
1898 }
1899 
1900 /* Build the sinks of source "source" according to the points-to
1901  * graphs. If "source" is not found in the graph, return an empty list
1902  * "sinks". If "fresh_p", allocate copies. If not, return pointers to
1903  * the destination vertices in "ptm".
1904  *
1905  * It is not clear how much the abstract address lattice must be used
1906  * to retrieve sinks... If source = a[34], clearly a[*] is an OK
1907  * equivalent source if a[34] is not a vertex of "ptm".
1908  */
1909 list points_to_source_to_sinks(cell source, pt_map ptm, bool fresh_p)
1910 {
1911  //return generic_points_to_source_to_sinks(source, ptm, fresh_p, true, false, false);
1912  return generic_points_to_source_to_sinks(source, ptm, fresh_p, false, true, false);
1913 }
1914 
1916 {
1917  return generic_points_to_source_to_sinks(source, ptm, fresh_p, true, false, true);
1918 }
1919 
1920 /* May not retrieve all sinks of the source.
1921  *
1922  * This happens with arrays of pointers. See EffectsWithPointers/call22.c
1923  */
1925 {
1926  return generic_points_to_source_to_sinks(source, ptm, fresh_p, false, false, false);
1927 }
1928 
1929 /* Retrieve all possible sinks of the source.
1930  *
1931  *
1932  */
1933 list points_to_source_to_any_sinks(cell source, pt_map ptm, bool fresh_p)
1934 {
1935  return generic_points_to_source_to_sinks(source, ptm, fresh_p, false, true, false);
1936 }
1937 ␌
1938 /* Build the sources of sink "sink" according to the points-to
1939  * graphs. If "sink" is not found in the graph, return an empty list
1940  * "sources". If "fresh_p", allocate copies. If not, return pointers to
1941  * the destination vertices in "ptm".
1942  *
1943  * It is not clear how much the abstract address lattice must be used
1944  * to retrieve sources... If source = a[34], clearly a[*] is an OK
1945  * equivalent source if a[34] is not a vertex of "ptm".
1946  */
1947 list points_to_sink_to_sources(cell sink, pt_map ptm, bool fresh_p)
1948 {
1949  list sources = NIL;
1950  set pts = points_to_graph_set(ptm);
1951 
1952  /* 1. See if cell "sink" is the destination vertex of a points-to arc. */
1953  SET_FOREACH( points_to, pt, pts) {
1954  if(cell_equal_p(sink, points_to_sink(pt))) {
1955  cell sc = fresh_p? copy_cell(points_to_source(pt)) : points_to_source(pt);
1956  sources = CONS(CELL, sc, sources);
1957  }
1958  }
1959 
1960 
1961  /* 2. Much harder... See if sink is contained in one of the many
1962  abstract sinks or if its address can be obtained from the address
1963  of another sink cell thanks to pointer arithmetic or
1964  indexing. Step 1 is subsumed by Step 2... but is much faster. */
1965  if(ENDP(sources)) {
1966  SET_FOREACH(points_to, pt, pts) {
1967  if(cell_included_p(sink, points_to_sink(pt))
1968  /* FI: I am not sure that using pointer arithmetics to
1969  declare equivalence is a good idea. */
1970  || cell_equivalent_p(sink, points_to_sink(pt))) {
1971  // FI: memory leak forced because of refine_points_to_cell_subscripts
1972  cell sc = (true||fresh_p)? copy_cell(points_to_source(pt)) : points_to_source(pt);
1973  // FI: I do not remember what this is for...
1974  // FI: does not seem right; for instance:
1975  // sources(_ll_1_2__1[next]) may not exist while "_ll_1[next]"
1976  // with points to arc "_ll_1[next]->_ll_1_2__1" might be acceptable
1977  // refine_points_to_cell_subscripts(sc, sink, points_to_sink(pt));
1978  sources = CONS(CELL, sc, sources);
1979  }
1980  }
1981  }
1982 
1983  return sources;
1984 }
1985 
1986 /* Return the points-to "fpt" ending in cell "sink" if it
1987  exists. Return points-to_undefined otherwise. */
1989 {
1991  set pts = points_to_graph_set(ptm);
1992 
1993  /* 1. See if cell "sink" is the destination vertex of a points-to arc. */
1994  SET_FOREACH( points_to, pt, pts) {
1995  if(cell_equal_p(sink, points_to_sink(pt))) {
1996  fpt = pt;
1997  break;
1998  }
1999  }
2000  return fpt;
2001 }
2002 
2003 /* Use "sn" as a source name to derive a list of sink cells according
2004  * to the points-to graph ptm.
2005  *
2006  * Allocate copies of the sink cells if "fresh_p".
2007  */
2008 list points_to_source_name_to_sinks(string sn, pt_map ptm, bool fresh_p)
2009 {
2010  list sinks = NIL;
2011  set pts = points_to_graph_set(ptm);
2012 
2013  SET_FOREACH( points_to, pt, pts) {
2014  cell c = points_to_source(pt);
2015  string cn = points_to_cell_name(c);
2016  if(strcmp(sn, cn)==0) {
2017  cell sc = fresh_p? copy_cell(points_to_sink(pt)) : points_to_sink(pt);
2018  sinks = CONS(CELL, sc, sinks);
2019  }
2020  free(cn);
2021  }
2022 
2023  return sinks;
2024 }
2025 
2026 cell points_to_source_name_to_source_cell(string sn, pt_map ptm, bool fresh_p)
2027 {
2028  cell rc = cell_undefined;
2029  set pts = points_to_graph_set(ptm);
2030 
2031  SET_FOREACH(points_to, pt, pts) {
2032  cell c = points_to_source(pt);
2033  string cn = points_to_cell_name(c);
2034  if(strcmp(sn, cn)==0) {
2035  rc = fresh_p? copy_cell(c) : c;
2036  break;
2037  }
2038  free(cn);
2039  }
2040 
2041  return rc;
2042 }
2043 
2044 /* Build the union of the sinks of cells in "sources" according to the
2045  * points-to graphs "ptm". Allocate new cells if "fresh_p". No
2046  * specific order in the returned list.
2047  *
2048  * If effective_p, eliminate NULL and NOWHERE/UNDEFINED as targets
2049  */
2050 list generic_points_to_sources_to_sinks(list sources, pt_map ptm, bool fresh_p, bool effective_p)
2051 {
2052  list sinks = NIL;
2053  FOREACH(CELL, source, sources) {
2054  list subl = generic_points_to_source_to_sinks(source, ptm, fresh_p, true, false, effective_p);
2055  sinks = gen_nconc(sinks, subl); // to ease debugging... Could be CONS
2056  }
2057 
2058  return sinks;
2059 }
2060 
2061 list points_to_sources_to_sinks(list sources, pt_map ptm, bool fresh_p)
2062 {
2063  return generic_points_to_sources_to_sinks(sources, ptm, fresh_p, false);
2064 }
2065 
2067 {
2068  return generic_points_to_sources_to_sinks(sources, ptm, fresh_p, true);
2069 }
2070 
2071 /* Build the list of arcs whose source is "source" according to the points-to
2072  * graphs "ptm". If "source" is not found in the graph, return an empty list
2073  * "sinks". If "fresh_p", allocate copies. If not, return pointers to
2074  * the arcs in "ptm".
2075  *
2076  * It is not clear how much the abstract address lattice must be used
2077  * to retrieve sinks... If source = a[34], clearly a[*] is an OK
2078  * equivalent source if a[34] is not a vertex of "ptm". Currently, we
2079  * assume that the origin vertex must be exactly "source".
2080  */
2081 list points_to_source_to_arcs(cell source, pt_map ptm, bool fresh_p)
2082 {
2083  list arcs = NIL;
2084  set pts = points_to_graph_set(ptm);
2085 
2086  /* See when the cell "source" is the starting vertex of a points-to arc. */
2087  SET_FOREACH( points_to, pt, pts) {
2088  if(cell_equal_p(source, points_to_source(pt))) {
2089  points_to pta = fresh_p? copy_points_to(pt) : pt;
2090  arcs = CONS(POINTS_TO, pta, arcs);
2091  }
2092  }
2093 
2094  return arcs;
2095 }
2096 ␌
2098 {
2101  return n;
2102 }
2103 
2105 {
2106  list sl = reference_indices(r);
2108  return n;
2109 }
2110 
2112 {
2113  int count = 0;
2114  FOREACH(EXPRESSION, s, sl) {
2115  if(unbounded_expression_p(s))
2116  count++;
2117  }
2118  return count;
2119 }
2120 
2121 /* Is there at least one cell "sink" in list "sinks" whose subscripts
2122  * fully match the subscripts in cell "source"?
2123  *
2124  * It is easy in a one-D setting. If "p" is an array or a presumed
2125  * array and if the source is "p[*]" then sinks "{a[1], a[2]}" are not
2126  * sufficient. Something else is needed such as "a[*]" or "b[*]" or
2127  * "undefined".
2128  *
2129  * FI: As a first cut, the numbers of unbounded subscripts in references
2130  * are counted and compared.
2131  */
2133 {
2134  bool match_p = false;
2135  reference source_r = cell_any_reference(source);
2136  list source_sl = reference_indices(source_r);
2137 
2138  if(ENDP(sinks)) {
2139  match_p = false;
2140  }
2141  else if(ENDP(source_sl)) {
2142  match_p = true; // no issue
2143  }
2144  else {
2145  int n_us_in_source =
2147  FOREACH(CELL, sink, sinks) {
2148  reference sink_r = cell_any_reference(sink);
2149  list sink_sl = reference_indices(sink_r);
2150  int n_us_in_sink =
2152  if(n_us_in_sink >= n_us_in_source) {
2153  match_p = true;
2154  break;
2155  }
2156  }
2157  }
2158 
2159  return match_p;
2160 }
2161 
2162 ␌
2163 /*
2164  * A set of functions to find the sinks associated to a source cell
2165  * according to a points-to relation:
2166  *
2167  * - source_to_sinks(): the source has to be an "effective" pointer;
2168  * its evaluation requires a dereferencing.
2169  *
2170  * - extended_source_to_sinks(): special handling for NULL and undefined?
2171  *
2172  * - extended_sources_to_sinks(): same as previous one, but for a set of cells
2173  *
2174  * - any_source_to_sinks(): the source does not have to be of type
2175  * pointer; indirect sinks of struct and arrays are computed
2176  *
2177  * - pointer_source_to_sinks(): the source is of pointer type, but may
2178  * be a partially subscripted array, i.e. not an "effective"
2179  * pointer because no dereferencing is involved.
2180  */
2181 
2182 /* Return a list of cells, "sinks", that are sink for some arc whose
2183  * source is "source" or related to "source" in set "pts". If no such
2184  * arc is found, add new points-to stubs and new arcs in "pts" when
2185  * global, formal or virtual variables are used in "source". Manage
2186  * fix point detection to avoid creating an infinite number of such
2187  * points-to stubs when recursive data structures are accessed in
2188  * loops.
2189  *
2190  * If "fresh_p" is set to true, no sharing is created between list
2191  * "sinks" and reference "source" or points-to set "pts". Else, the
2192  * cells in list "sinks" are the cells in arcs of the points-to set.
2193  *
2194  * FI: I am not sure the above paragraph is properly implemented.
2195  *
2196  * This function is based on several other simpler functions:
2197  *
2198  * * points_to_source_to_sinks()
2199  *
2200  * * anywhere_source_to_sinks(), nowhere_source_to_sinks() and
2201  * null_source_to_sinks()
2202  *
2203  * * formal_source_to_sinks()
2204  *
2205  * * global_source_to_sinks()
2206  *
2207  * * stub_source_to_sinks()
2208  *
2209  * This function should never return an empty list. The caller should
2210  * handle it as a bug in the analyzed code.
2211  *
2212  * Function added by FI. It is recursive via...
2213  */
2214 list source_to_sinks(cell source, pt_map pts, bool fresh_p)
2215 {
2216  list sinks = NIL;
2217  if(pt_map_undefined_p(pts)) {
2218  if(false && get_bool_property("ALIASING_ACROSS_TYPES")) {
2219  // make_untyped_anywhere_cell()
2221  reference r = make_reference(a, NIL);
2222  cell c = make_cell_reference(r);
2223  sinks = CONS(CELL, c, NIL);
2224  }
2225  else {
2227  type ct = type_to_pointed_type(t); // FI: assumed concrete...
2228  sinks = CONS(CELL, make_anywhere_cell(ct), NIL);
2229  }
2230  }
2231  else if(!points_to_graph_bottom(pts)) {
2232  //bool to_be_freed;
2233  type source_t = points_to_cell_to_concrete_type(source);
2234  //type source_t = points_to_cell_to_type(source, & to_be_freed);
2235  //type c_source_t = compute_basic_concrete_type(source_t);
2236  bool ok_p = C_pointer_type_p(source_t)
2237  || overloaded_type_p(source_t) // might be a pointer
2238  || null_cell_p(source);
2239  //if(to_be_freed) free_type(source_t);
2240 
2241  /* Can we expect a sink? */
2242  if(!ok_p) {
2243  // Likely typing error in source code
2245  pips_user_warning("Typing error in a pointer assignment or a dereferencing with \"%s\" at line %d.\n",
2246  entity_user_name(v),
2248  // Return an empty list
2249  }
2250  else if(nowhere_cell_p(source)) {
2251  sinks = nowhere_source_to_sinks(source, pts);
2252  }
2253  else if(anywhere_cell_p(source) || cell_typed_anywhere_locations_p(source)) {
2254  sinks = anywhere_source_to_sinks(source, pts);
2255  }
2256  else if(null_pointer_value_cell_p(source)) {
2257  sinks = null_source_to_sinks(source, pts);
2258  }
2259  else {
2260  /* 0. Is the source a pointer? You would expect a yes, but C
2261  pointer arithmetics requires some strange typing. We assume it
2262  is an array of pointers. */
2263  //bool to_be_freed;
2264  //type ct = points_to_cell_to_type(source, &to_be_freed);
2265  //if(array_type_p(ct)) {
2266  if(array_type_p(source_t)) {
2267  basic ctb = variable_basic(type_variable(source_t));
2268  // FI->AM: I am not happy at all with his
2269  if(basic_pointer_p(ctb)) {
2270  ;
2271  }
2272  else {
2273  cell sc = copy_cell(source);
2274  sinks = CONS(CELL, sc, sinks);
2275  }
2276  }
2277  //if(to_be_freed) free_type(ct);
2278 
2279  /* 1. Try to find the source in the points-to information */
2280  if(ENDP(sinks))
2281  sinks = points_to_source_to_sinks(source, pts, fresh_p);
2282 
2283  /* 2. If the previous step has failed, build a new sink if the
2284  * source is a formal parameter, a global variable, a C file local
2285  * global variable (static) or a stub.
2286  *
2287  * We may need a stub even if sinks is not empty when the source
2288  * contains "*" subscript(s) and when none of the sinks contains
2289  * such a subscript, or, more precisely when star subscripts do
2290  * not match, matching being not yet clearly defined.
2291  */
2292  if(ENDP(sinks) || !sinks_fully_matches_source_p(source, sinks)) {
2293  reference r = cell_any_reference(source);
2294  entity v = reference_variable(r);
2295  list n_sinks = NIL;
2296  if(formal_parameter_p(v)) {
2297  n_sinks = formal_source_to_sinks(source, pts, fresh_p);
2298  }
2299  /* Must be checked before globals because stubs for global
2300  variables are themselves global. */
2301  else if(entity_stub_sink_p(v)) {
2302  n_sinks = stub_source_to_sinks(source, pts, fresh_p);
2303  }
2304  else if(top_level_entity_p(v) || static_global_variable_p(v)) {
2305  n_sinks = global_source_to_sinks(source, pts, fresh_p);
2306  }
2307  else if(entity_typed_anywhere_locations_p(v)) {
2308  pips_internal_error("This case should have been handled above.\n");
2309  }
2310  sinks = gen_nconc(sinks, n_sinks);
2311 
2312  /* 3. Still no sinks? Check the lattice structure... */
2313  if(ENDP(sinks)) {
2314  type source_t = entity_basic_concrete_type(v);
2315  cell tac = make_anywhere_points_to_cell(source_t);// typed anywhere cell
2316  sinks = points_to_source_to_sinks(tac, pts, fresh_p);
2317  if(ENDP(sinks)) {
2319  reference ar = make_reference(a, NIL);
2320  cell ac = make_cell_reference(ar);// untyped anywhere cell
2321  sinks = points_to_source_to_sinks(ac, pts, fresh_p);
2322  free_cell(ac);
2323  }
2324  /* FI: it seems easier to maintain the consistency between the
2325  sinks and the arcs for the global consistency of the
2326  points-to processing. Otherwise, we may have to check for
2327  special cases like undefined or anywhere. */
2328  FOREACH(CELL, c, sinks) {
2329  points_to npt = make_points_to(copy_cell(source),
2330  copy_cell(c),
2333  add_arc_to_pt_map(npt, pts);
2334  }
2335  free_cell(tac);
2336  }
2337 
2338  if(ENDP(sinks)) {
2339  /* A bug somewhere up... */
2340  reference r = cell_any_reference(source);
2341  print_reference(r);
2342  pips_user_warning("\nUninitialized or null pointer dereferenced: "
2343  "Sink missing for a source based on \"%s\".\n"
2344  "Update points-to property POINTS_TO_UNINITIALIZED_POINTER_DEREFERENCING and/or POINTS_TO_UNINITIALIZED_NULL_DEREFERENCING according to needs.\n",
2345  entity_user_name(v));
2346  clear_pt_map(pts);
2347  points_to_graph_bottom(pts) = true;
2348  // FI: it is not a pips error but a user error (in theory)
2349  // pips_internal_error("Dereferencing of an unitialized pointer.\n");
2350  }
2351  }
2352  }
2353  }
2354  // FI: use gen_nreverse() to simplify debbugging? Not meaningful
2355  // with SET_FOREACH
2356  return sinks;
2357 }
2358 
2360 {
2361  list sinks = NIL;
2362  bool null_dereferencing_p
2363  = get_bool_property("POINTS_TO_NULL_POINTER_DEREFERENCING");
2364  bool nowhere_dereferencing_p
2365  = get_bool_property("POINTS_TO_UNINITIALIZED_POINTER_DEREFERENCING");
2366  if( (null_dereferencing_p || !null_cell_p(sc))
2367  && (nowhere_dereferencing_p || !nowhere_cell_p(sc))) {
2368  /* Do not create sharing between elements of "in" and
2369  elements of "sinks". */
2370  cell nsc = copy_cell(sc);
2371  list starpointed = source_to_sinks(nsc, in, true);
2372  free_cell(nsc);
2373 
2374  if(ENDP(starpointed)) {
2375  reference sr = cell_any_reference(sc);
2376  entity sv = reference_variable(sr);
2377  string words_to_string(list);
2378  pips_internal_error("No pointed location for variable \"%s\" and reference \"%s\"\n",
2379  entity_user_name(sv),
2380  reference_to_string(sr));
2381  }
2382  sinks = gen_nconc(sinks, starpointed);
2383  }
2384  // FI: I'd like a few else clauses to remove arcs that
2385  // cannot exist if the code is correct. E.g. p->i, p->NULL
2386  // if card(cl)==1, remove arc(c->sc)?
2387  return sinks;
2388 }
2389 
2390 /* Same as extended_source_to_sinks, but for a set of cells, "pointed". */
2392 {
2393  list sinks = NIL;
2394  /* Dereference the pointer(s) to find the sinks, memory(memory(p)) */
2395  FOREACH(CELL, sc, pointed) {
2396  list starpointed = extended_source_to_sinks(sc, in);
2397  sinks = gen_nconc(sinks, starpointed);
2398  }
2399  return sinks;
2400 }
2401 
2402 /* Generalization of source_to_sinks(). The source does not have to be
2403  a pointer. */
2404 list any_source_to_sinks(cell source, pt_map pts, bool fresh_p)
2405 {
2406  list sinks = NIL;
2407  bool to_be_freed;
2408  type source_t = points_to_cell_to_type(source, & to_be_freed);
2409  type c_source_t = compute_basic_concrete_type(source_t);
2410 
2411  if(pointer_type_p(c_source_t))
2412  sinks = source_to_sinks(source, pts, fresh_p);
2413  else if(struct_type_p(c_source_t)) {
2414  list fl = derived_type_to_fields(c_source_t);
2415  FOREACH(ENTITY, f, fl) {
2417  if(pointer_type_p(f_t) || struct_type_p(f_t)
2418  || array_of_pointers_type_p(f_t)
2419  || array_of_struct_type_p(f_t)) {
2420  cell n_source = copy_cell(source);
2422  sinks = any_source_to_sinks(n_source, pts, fresh_p);
2423  free_cell(n_source);
2424  }
2425  }
2426  }
2427  else if(array_of_pointers_type_p(c_source_t)) {
2428  cell n_source = copy_cell(source);
2430  sinks = source_to_sinks(source, pts, fresh_p);
2431  free_cell(n_source);
2432  }
2433  else if(array_of_struct_type_p(c_source_t)) {
2434  cell n_source = copy_cell(source);
2436  sinks = any_source_to_sinks(source, pts, fresh_p);
2437  free_cell(n_source);
2438  }
2439 
2440  return sinks;
2441 }
2442 
2443 /* Returns the sinks for a source cell "sc" of type pointer according
2444  * to the points-to relation "in".
2445  *
2446  * This is an extension of extended_source_to_sinks() that also take
2447  * into account partially subscribed arrays. Such references end up
2448  * with a pointer type, but "in" is not involved in the
2449  * dereferencing... since no dereferencing is necessary. An extra 0
2450  * subscript must be added.
2451  *
2452  * FI: This issue is also dealt elsewhere, but I do not know where nor
2453  * how often.
2454  */
2456 {
2457  list sinks = NIL;
2458  reference r = cell_any_reference(sc);
2459  entity v = reference_variable(r);
2461  if(array_type_p(t)) {
2462  // FI: pointers count for 1 in array depth
2463  // With a array of pointers, a dereferencing 0 subscript is added
2464  // int dn = (int) type_depth(t);
2466  list sl = reference_indices(r);
2467  int sn = (int) gen_length(sl);
2468  if(sn<dn) {
2469  cell sink = copy_cell(sc);
2470  reference sink_r = cell_any_reference(sink);
2471  reference_indices(sink_r) = gen_nconc(reference_indices(sink_r),
2473  sinks = CONS(CELL, sink, NIL);
2474  }
2475  }
2476  if(ENDP(sinks))
2477  sinks = extended_source_to_sinks(sc, in);
2478  return sinks;
2479 }
2480 ␌
2481 /* Return all cells in points-to set "pts" who source is based on entity "e".
2482  *
2483  * Similar to points_to_source_to_sinks, but much easier and shorter.
2484  */
2485 list variable_to_sinks(entity e, pt_map ptm, bool fresh_p)
2486 {
2487  list sinks = NIL;
2488  set pts = points_to_graph_set(ptm);
2489  SET_FOREACH( points_to, pt, pts) {
2490  cell source = points_to_source(pt);
2491  reference sr = cell_any_reference(source);
2492  entity v = reference_variable(sr);
2493  if(e==v) {
2494  cell sc = fresh_p? copy_cell(points_to_sink(pt)) : points_to_sink(pt);
2495  sinks = CONS(CELL, sc, sinks);
2496  }
2497  }
2498  return sinks;
2499 
2500 }
2501 
2502 /* Create a list of null sinks and add a new null points-to relation to pts.
2503  * pts is modified by side effect.
2504  */
2506 {
2507  cell nsource = copy_cell(source);
2509  points_to npt = make_points_to(nsource, nsink,
2512  ptm = add_arc_to_pt_map_(npt, ptm);
2514  list sinks = CONS(CELL, copy_cell(nsink), NIL);
2515  return sinks;
2516 }
2517 
2518 /* Same as source_to_sinks, but for a list of cells. */
2519 list sources_to_sinks(list sources, pt_map ptm, bool fresh_p)
2520 {
2521  list sinks = NIL;
2522  FOREACH(CELL, c, sources) {
2523  list cl = source_to_sinks(c, ptm, fresh_p);
2524  sinks = gen_nconc(sinks, cl);
2525  }
2526  return sinks;
2527 }
2528 
2530 {
2532  list sinks = source_to_sinks(source, in, fresh_p);
2533  free_cell(source);
2534  return sinks;
2535 }
2536 
2537 /* Merge two points-to sets
2538  *
2539  * This function is required to compute the points-to set resulting of
2540  * an if control statements.
2541  *
2542  * A new set is allocated but it reuses the elements of "s1" and "s2".
2543  */
2546  points_to_rank);
2547 
2548  pips_assert("Consistent set s1", consistent_points_to_set(s1));
2549  pips_assert("Consistent set s2", consistent_points_to_set(s2));
2550 
2551  if(set_empty_p(s1))
2552  set_assign(Merge_set, s2);
2553  else if(set_empty_p(s2))
2554  set_assign(Merge_set, s1);
2555  else {
2557  points_to_rank);
2559  points_to_rank);
2560  set Intersection_set = set_generic_make(set_private, points_to_equal_p,
2561  points_to_rank);
2563  points_to_rank);
2564 
2565  Intersection_set = set_intersection(Intersection_set, s1, s2);
2566  Union_set = set_union(Union_set, s1, s2);
2567 
2568  SET_FOREACH ( points_to, i, Intersection_set ) {
2571  Definite_set = set_add_element(Definite_set,Definite_set,
2572  (void*) i );
2573  }
2574 
2575  SET_FOREACH ( points_to, j, Union_set ) {
2576  if ( ! set_belong_p(Definite_set, (void*)j) ) {
2580  Possible_set = set_add_element(Possible_set, Possible_set,(void*) pt);
2581  }
2582  }
2583 
2584  Merge_set = set_clear(Merge_set);
2585  Merge_set = set_union(Merge_set, Possible_set, Definite_set);
2586 
2587  set_clear(Intersection_set);
2588  set_clear(Union_set);
2589  set_clear(Possible_set);
2590  set_clear(Definite_set);
2591  set_free(Definite_set);
2592  set_free(Possible_set);
2593  set_free(Intersection_set);
2594  set_free(Union_set);
2595  }
2596 
2597  pips_assert("Consistent merged set", consistent_points_to_set(Merge_set));
2598 
2599  return Merge_set;
2600 }
2601 
2602 /* Change the all the exact points-to relations to may relations */
2604 {
2605  SET_FOREACH ( points_to, pt, s ) {
2608  }
2609  return s;
2610 }
2611 
2612 
2613 bool cell_in_list_p(cell c, const list lx)
2614 {
2615  list l = (list) lx;
2616  for (; !ENDP(l); POP(l))
2617  if (points_to_compare_cell(CELL(CAR(l)), c)) return true; /* found! */
2618 
2619  return false; /* else no found */
2620 }
2621 
2622 /* Check if a cell c appears as source or sink in points-to set pts
2623  *
2624  * If set pts is undefined, it is assumed that cell c is in it.
2625  */
2627 {
2628  bool in_p = false;
2629  if(set_undefined_p(pts)) {
2630  in_p = true;
2631  }
2632  else {
2633  SET_FOREACH(points_to, pt, pts) {
2634  cell s = points_to_source(pt);
2635  in_p = points_to_compare_cell(s,c);
2636  if(!in_p) {
2637  cell d = points_to_sink(pt);
2638  in_p = points_to_compare_cell(d,c);
2639  }
2640  if(in_p)
2641  break;
2642  }
2643  }
2644  return in_p;
2645 }
2646 
2648 {
2649  list l = (list) lx;
2650  for (; !ENDP(l); POP(l))
2651  if (points_to_equal_p(POINTS_TO(CAR(l)), pt)) return true; /* found! */
2652 
2653  return false; /* else no found */
2654 }
2655 
2656 /* */
2658 {
2659  if(c1==c2)
2660  return true;
2661 
2662  int i = 0;
2663  reference r1 = cell_to_reference(c1);
2664  reference r2 = cell_to_reference(c2);
2665  entity v1 = reference_variable(r1);
2666  entity v2 = reference_variable(r2);
2667  list sl1 = NIL, sl2 = NIL;
2668  extern const char* entity_minimal_user_name(entity);
2669 
2671  if(i==0) {
2672  sl1 = reference_indices(r1);
2673  sl2 = reference_indices(r2);
2674  int i1 = gen_length(sl1);
2675  int i2 = gen_length(sl2);
2676 
2677  i = i2>i1? 1 : (i2<i1? -1 : 0);
2678 
2679  for(;i==0 && !ENDP(sl1); POP(sl1), POP(sl2)){
2680  expression se1 = EXPRESSION(CAR(sl1));
2681  expression se2 = EXPRESSION(CAR(sl2));
2683  int i1 = expression_to_int(se1);
2684  int i2 = expression_to_int(se2);
2685  i = i2>i1? 1 : (i2<i1? -1 : 0);
2686  }else{
2687  string s1 = expression_to_string(se1);
2688  string s2 = expression_to_string(se2);
2689  i = strcmp(s1, s2);
2690  }
2691  }
2692  }
2693 
2694  return (i== 0 ? true: false) ;
2695 }
2696 
2697 /* */
2698 bool points_to_compare_ptr_cell(const void * vcel1, const void * vcel2)
2699 {
2700  int i = 0;
2701  cell c1 = *((cell *)vcel1);
2702  cell c2 = *((cell *)vcel2);
2703  reference r1 = cell_to_reference(c1);
2704  reference r2 = cell_to_reference(c2);
2705  entity v1 = reference_variable(r1);
2706  entity v2 = reference_variable(r2);
2707  list sl1 = NIL, sl2 = NIL;
2708  extern const char* entity_minimal_user_name(entity);
2709  string n1 = entity_abstract_location_p(v1)?
2711  string n2 = entity_abstract_location_p(v2)?
2713  i = strcmp(n1, n2);
2714  if(i==0) {
2715  sl1 = reference_indices(r1);
2716  sl2 = reference_indices(r2);
2717  int i1 = gen_length(sl1);
2718  int i2 = gen_length(sl2);
2719 
2720  i = i2>i1? 1 : (i2<i1? -1 : 0);
2721 
2722  for(;i==0 && !ENDP(sl1); POP(sl1), POP(sl2)){
2723  expression se1 = EXPRESSION(CAR(sl1));
2724  expression se2 = EXPRESSION(CAR(sl2));
2726  int i1 = expression_to_int(se1);
2727  int i2 = expression_to_int(se2);
2728  i = i2>i1? 1 : (i2<i1? -1 : 0);
2729  }else{
2730  string s1 = expression_to_string(se1);
2731  string s2 = expression_to_string(se2);
2732  i = strcmp(s1, s2);
2733  }
2734  }
2735  }
2736 
2737  return i;
2738 }
2739 
2740 
2741 /* Order the two points-to relations according to the alphabetical
2742  * order of the underlying variables. Return -1, 0, or 1.
2743  */
2744 int points_to_compare_location(void * vpt1, void * vpt2) {
2745  int i = 0;
2746  points_to pt1 = *((points_to *) vpt1);
2747  points_to pt2 = *((points_to *) vpt2);
2748 
2749  cell c1so = points_to_source(pt1);
2750  cell c2so = points_to_source(pt2);
2751  cell c1si = points_to_sink(pt1);
2752  cell c2si = points_to_sink(pt2);
2753 
2754  // FI: bypass of GAP case
2755  reference r1so = cell_to_reference(c1so);
2756  reference r2so = cell_to_reference(c2so);
2757  reference r1si = cell_to_reference(c1si);
2758  reference r2si = cell_to_reference(c2si);
2759 
2760  entity v1so = reference_variable(r1so);
2761  entity v2so = reference_variable(r2so);
2762  entity v1si = reference_variable(r1si);
2763  entity v2si = reference_variable(r2si);
2764  list sl1 = NIL, sl2 = NIL;
2765  // FI: memory leak? generation of a new string?
2766  extern const char* entity_minimal_user_name(entity);
2767 
2768  i = strcmp(entity_minimal_user_name(v1so), entity_minimal_user_name(v2so));
2769  if(i==0) {
2771  if(i==0) {
2772  sl1 = reference_indices(r1so);
2773  sl2 = reference_indices(r2so);
2774  int i1 = gen_length(sl1);
2775  int i2 = gen_length(sl2);
2776 
2777  i = i2>i1? 1 : (i2<i1? -1 : 0);
2778 
2779  if(i==0) {
2780  list sli1 = reference_indices(r1si);
2781  list sli2 = reference_indices(r2si);
2782  int i1 = gen_length(sli1);
2783  int i2 = gen_length(sli2);
2784 
2785  i = i2>i1? 1 : (i2<i1? -1 : 0);
2786  if(i==0) {
2787  for(;i==0 && !ENDP(sl1); POP(sl1), POP(sl2)){
2788  expression se1 = EXPRESSION(CAR(sl1));
2789  expression se2 = EXPRESSION(CAR(sl2));
2791  int i1 = expression_to_int(se1);
2792  int i2 = expression_to_int(se2);
2793  i = i2>i1? 1 : (i2<i1? -1 : 0);
2794  if(i==0){
2795  for(;i==0 && !ENDP(sli1); POP(sli1), POP(sli2)){
2796  expression sei1 = EXPRESSION(CAR(sli1));
2797  expression sei2 = EXPRESSION(CAR(sli2));
2798  if(expression_constant_p(sei1) && expression_constant_p(sei2)){
2799  int i1 = expression_to_int(sei1);
2800  int i2 = expression_to_int(sei2);
2801  i = i2>i1? 1 : (i2<i1? -1 : 0);
2802  }else{
2803  string s1 = expression_to_string(se1);
2804  string s2 = expression_to_string(se2);
2805  i = strcmp(s1, s2);
2806  }
2807  }
2808  }
2809  }else{
2810  string s1 = expression_to_string(se1);
2811  string s2 = expression_to_string(se2);
2812  i = strcmp(s1, s2);
2813  }
2814  }
2815  }
2816  }
2817  }
2818  }
2819  return i;
2820 }
2821 ␌
2822 bool consistent_points_to_arc_p(points_to a, bool constant_subscript_p)
2823 {
2824  bool consistent_p = true;
2825 
2826  consistent_p = consistent_p && points_to_consistent_p(a);
2827  cell s = points_to_source(a);
2828  reference sr = cell_any_reference(s);
2829  if(constant_subscript_p) {
2830  consistent_p = consistent_p && store_independent_points_to_reference_p(sr);
2831  if(!consistent_p)
2832  pips_internal_error("Store dependent points-to source.\n");
2833  }
2834  else {
2835  consistent_p = consistent_p && !memory_dereferencing_p(sr);
2836  if(!consistent_p)
2837  pips_internal_error("Dereferencing points-to source.\n");
2838  }
2839 
2840  /*FI: two issue:
2841  *
2842  * - st should be the type of the variable entity used in the source
2843  * (or the destination)
2844  *
2845  * - type_depth() is the maximal depth value; the depth depends on
2846  * the fields followed in a struct. A more careful analysis of the
2847  * subscript would be needed to check the subscripts.
2848  */
2849 #if false
2851  int sn = type_depth(st);
2852  list ssl = reference_indices(sr);
2853  consistent_p = sn==(int) gen_length(ssl);
2854 
2855  if(!consistent_p)
2856  pips_internal_error("Unexpected number of subscripts for points-to source.\n");
2857 #endif
2858 
2859  cell d = points_to_sink(a);
2860  reference dr = cell_any_reference(d);
2861  if(constant_subscript_p) {
2862  consistent_p = consistent_p && store_independent_points_to_reference_p(dr);
2863  if(!consistent_p)
2864  pips_internal_error("Store dependent points-to sink.\n");
2865  }
2866  else {
2867  // memory_dereferencing_p() could be replaced by
2868  // effect_reference_dereferencing_p()
2869  consistent_p = consistent_p && !memory_dereferencing_p(dr);
2870  // consistent_p = consistent_p && !effect_reference_dereferencing_p(dr);
2871  if(!consistent_p)
2872  pips_internal_error("Dereferencing points-to sink.\n");
2873  }
2874 
2875 #if false
2877  int dn = type_depth(dt);
2878  list dsl = reference_indices(dr);
2879  consistent_p = dn<=(int) gen_length(dsl);
2880 
2881  if(!consistent_p)
2882  pips_internal_error("Unexpected number of subscripts for points-to source.\n");
2883 #endif
2884 
2885  return consistent_p;
2886 }
2887 
2889 {
2890  return consistent_points_to_arc_p(a, true);
2891 }
2892 
2894 {
2895  return consistent_points_to_arc_p(a, false);
2896 }
2897 
2898 /* make sure that set "s" does not contain redundant or contradictory
2899  elements */
2901 {
2902  bool consistent_p = true;
2903 
2904  /* Check the consistency of each arc */
2905  SET_FOREACH(points_to, a, s) {
2906  consistent_p = consistent_p && store_independent_points_to_arc_p(a);
2907  }
2908 
2909  /* Check the validity of the approximations */
2910  SET_FOREACH(points_to, pt1, s) {
2912  SET_FOREACH(points_to, pt2, s) {
2913  if(pt1!=pt2) {
2914  //same source
2915  cell c1 = points_to_source(pt1);
2916  cell c2 = points_to_source(pt2);
2917  bool cmp1 = locations_equal_p(c1,c2);
2918 
2919  if(cmp1 && approximation_exact_p(a1)) {
2920  fprintf(stderr,
2921  "Contradictory points-to arcs: incompatible approximation\n");
2922  print_points_to(pt1);
2923  print_points_to(pt2);
2924  consistent_p = false;
2925  }
2926 
2927  // same sink
2928  cell c3 = points_to_sink(pt1);
2929  cell c4 = points_to_sink(pt2);
2930  bool cmp2 = locations_equal_p(c3,c4);
2931  if(cmp1&&cmp2) {
2932  // same approximation
2935  // FI: must is forgotten...
2936  //bool cmp3 = (approximation_exact_p(a1) && approximation_exact_p(a2))
2937  // || ( approximation_may_p(a1) && approximation_may_p(a2));
2938  // FI: should we identify "exact" and "must"?
2939  bool cmp3 = (approximation_tag(a1)==approximation_tag(a2));
2940  if(cmp3) {
2941  fprintf(stderr, "Redundant points-to arc:\n");
2942  print_points_to(pt1);
2943  consistent_p = false;
2944  }
2945  else {
2946  fprintf(stderr, "Contradictory points-to arcs: incompatible approximation\n");
2947  print_points_to(pt1);
2948  print_points_to(pt2);
2949  consistent_p = false;
2950  }
2951  }
2952  }
2953  }
2954  }
2955 
2956  /* Make sure that the element of set "s" belong to "s" (issue with
2957  * side effects performed on subscript expressions).
2958  */
2959  SET_FOREACH(points_to, pt, s) {
2960  if(!set_belong_p(s,pt)) {
2961  fprintf(stderr, "Points-to %p ", pt);
2962  print_points_to(pt);
2963  fprintf(stderr, " is in set s but does not belong to it!\n");
2964  consistent_p = false;
2965  }
2966  }
2967 
2968  /* Check that no sharing exists between arcs at the cell and
2969  reference levels */
2970  if(consistent_p) {
2971  consistent_p = !points_to_set_sharing_p(s);
2972  if(!consistent_p)
2973  fprintf(stderr, "Sharing detected\n");
2974  }
2975  return consistent_p;
2976 }
2977 
2979 {
2980  bool sharing_p = false;
2981 
2982  SET_FOREACH(points_to, pt1, s) {
2983  cell source_1 = points_to_source(pt1);
2984  cell sink_1 = points_to_sink(pt1);
2985  reference source_r1 = cell_any_reference(source_1);
2986  reference sink_r1 = cell_any_reference(sink_1);
2987 
2988  bool found_p = false;
2989  SET_FOREACH(points_to, pt2, s) {
2990  if(pt1==pt2)
2991  found_p = true;
2992  if(found_p && pt1!=pt2) {
2993  cell source_2 = points_to_source(pt2);
2994  cell sink_2 = points_to_sink(pt2);
2995  reference source_r2 = cell_any_reference(source_2);
2996  reference sink_r2 = cell_any_reference(sink_2);
2997 
2998  bool new_sharing_p = false;
2999 
3000  /* Sharing of cells */
3001  if(source_1==source_2) {
3002  new_sharing_p = true;
3003  fprintf(stderr, "Sharing between source_1 and source_2.\n");
3004  }
3005  else if(source_1==sink_2) {
3006  new_sharing_p = true;
3007  fprintf(stderr, "Sharing between source_1 and sink_2.\n");
3008  }
3009  else if(sink_1==source_2) {
3010  new_sharing_p = true;
3011  fprintf(stderr, "Sharing between sink_1 and source_2.\n");
3012  }
3013  else if(sink_1==sink_2) {
3014  new_sharing_p = true;
3015  fprintf(stderr, "Sharing between sink_1 and sink_2.\n");
3016  }
3017 
3018  if(!new_sharing_p) {
3019  /* Sharing of references */
3020  if(source_r1==source_r2) {
3021  new_sharing_p = true;
3022  fprintf(stderr, "Sharing between source_r1 and source_r2.\n");
3023  }
3024  else if(source_r1==sink_r2) {
3025  new_sharing_p = true;
3026  fprintf(stderr, "Sharing between source_r1 and sink_r2.\n");
3027  }
3028  else if(sink_r1==source_r2) {
3029  new_sharing_p = true;
3030  fprintf(stderr, "Sharing between sink_r1 and source_r2.\n");
3031  }
3032  else if(sink_r1==sink_r2) {
3033  new_sharing_p = true;
3034  fprintf(stderr, "Sharing between sink_r1 and sinke_r2.\n");
3035  }
3036  }
3037  if(new_sharing_p) {
3038  fprintf(stderr, "For pt1 ");
3039  dump_points_to(pt1);
3040  fprintf(stderr, "\nand pt2 ");
3041  dump_points_to(pt2);
3042  }
3043  sharing_p = sharing_p || new_sharing_p;
3044  }
3045  }
3046  }
3047  return sharing_p;
3048 }
3049 ␌
3050 /* When arcs have been removed from a points-to relation, the
3051  * approximations of remaining arcs may not correspond to the new
3052  * points-to relation. A may approximation may have become an exact
3053  * approximation.
3054  *
3055  * The semantics of the approximation and its many constraints must be
3056  * taken into account. But they are not (yet) well formaly
3057  * defined... The conditions here are:
3058  *
3059  * 1. One out-going arc
3060  *
3061  * 2. The source cannot be an abstract location because the concrete
3062  * is not well known. Same thing for the sink.
3063  *
3064  * 3. The source must be atomic, i.e. t[*] does not qualify because
3065  * many concrete locations exist. Same thing for the source.
3066  *
3067  * 4. What do we want to do with stubs? In an intraprocedural
3068  * analysis, the concrete location is well defined. In an
3069  * interprocedural analysis, depending on the call site, the stub
3070  * may exist or not, or the concrete locations can be many. Also,
3071  * the implementation is no symetrical: sinks are not
3072  * tested. However, at run-time, the atomic stubs correspond to one
3073  * concrete location, and if they are part of a exact/must arc, the
3074  * call site must provide a corresponding concrete location. The
3075  * arc will later be converted to a may arc if the translation is
3076  * not exact.
3077  *
3078  * Another question: is it OK to fix a lack of precision later or
3079  * wouldn't it ne better to maintain the proper approximation on the
3080  * fly, when more information is available?
3081  *
3082  * Note about the implementation: Because of points-to set
3083  * implementation, you cannot change approximations by side effects.
3084  */
3086 {
3087  set pts = points_to_graph_set(ptm);
3088  SET_FOREACH(points_to, pt, pts) {
3090  if(!approximation_exact_p(a)) {
3091  cell source = points_to_source(pt);
3092  if(!cell_abstract_location_p(source) // Represents may locations
3093  /* && !stub_points_to_cell_p(source)*/ // May not exist... See above
3094  && generic_atomic_points_to_cell_p(source, false)) {
3095  list sinks = points_to_source_to_any_sinks(source, ptm, false);
3096  if(gen_length(sinks)==1) {
3097  cell sink = points_to_sink(pt);
3098  if(!cell_abstract_location_p(sink)
3099  && generic_atomic_points_to_cell_p(sink, false)) {
3100  points_to npt = make_points_to(copy_cell(source),
3101  copy_cell(sink),
3104  remove_arc_from_pt_map(pt, ptm);
3105  (void) add_arc_to_pt_map(npt, ptm);
3106  }
3107  }
3108  gen_free_list(sinks);
3109  }
3110  }
3111  }
3112 }
3113 ␌
3114 void remove_points_to_arcs(cell source, cell sink, pt_map pt)
3115 {
3116  points_to a = make_points_to(copy_cell(source), copy_cell(sink),
3119  remove_arc_from_pt_map(a, pt);
3120  free_points_to(a);
3121 
3122  a = make_points_to(copy_cell(source), copy_cell(sink),
3125  remove_arc_from_pt_map(a, pt);
3126  free_points_to(a);
3127 }
3128 
3129 
3130 
3131 /* Compute A = A inter B: complexity in O(n2) */
3132 void
3134 {
3135  if (ENDP(*a))
3136  return ;
3137  if (!points_to_cell_in_list_p(CELL(CAR(*a)),b)) {
3138  /* This element of a is not in list b: delete it: */
3139  cons *aux = *a;
3140 
3141  *a = CDR(*a);
3142  free(aux);
3144  }
3145  else
3146  points_to_cell_list_and(&CDR(*a), b);
3147 }
3148 /* Free several sets in one call. Useful when many sets are used
3149  simultaneously. */
3151 {
3152  va_list args;
3153 
3154  /* Analyze in args the variadic arguments that may be after t: */
3155  va_start(args, s);
3156  /* Since a variadic function in C must have at least 1 non variadic
3157  argument (here the s), just skew the varargs analysis: */
3158  do {
3160  /* Get the next argument */
3161  //s = va_arg(args, points_to_graph);
3162  s = va_arg(args, pt_map);
3163  } while(s!=NULL);
3164  /* Release the variadic analysis */
3165  va_end(args);
3166 }
3167 
3168 /* FI: I add functions dealing with points_to_graph variable, i.e. pt_map */
3169 
3171 {
3172  bool b = points_to_graph_bottom(ptm);
3173  if(b) {
3174  // FI: I am in trouble here; what should be the semantics?
3175  pips_debug(1, "Impossible initialization of a bottom graph\n");
3176  pips_internal_error("Mismanaged points-to graph\n");
3177  }
3178  else
3180  return ptm;
3181 }
3182 
3184 {
3186  points_to_graph_set(s2));
3187  pt_map pt_merged = new_pt_map();
3188  points_to_graph_set(pt_merged) = merged;
3190  points_to_graph_bottom(pt_merged) = true;
3191  return pt_merged;
3192 }
3193 
3195 {
3197  points_to_graph_set(in));
3198  return out;
3199 }
3200 
3201 /* All vertices in "sink_l" are assumed to be sinks of vertex "source"
3202  * in points-to graph "in".
3203  *
3204  * These vertices must be replaced by a unique vertex, their minimum
3205  * upper bound in the abstract address lattice. And their own
3206  * out-going arcs must also be rearranged.
3207  *
3208  * Clearly, some abstract addresses high in the lattice should be
3209  * allowed large out-degree numbers.
3210  *
3211  * A newly allocated points-to arc is returned. It could be integrated
3212  * directly in "in", but the integration is performed by a caller.
3213  */
3215 {
3216  pt_map out = in;
3217 
3218  pips_assert("\"in\" is consistent", consistent_pt_map_p(in));
3219 
3220  /* Find the minimal upper bound of "sink_l" */
3222 
3223  /* Compute the sinks of the vertex "mupc" as the union of the sinks
3224  * of cells in "sink_l" and add the corresponding arcs to "out".
3225  */
3226  list iptl = points_to_sources_to_sinks(sink_l, in, true); // indirect points-to
3227  FOREACH(CELL, sink, iptl) {
3228  cell mupcc = copy_cell(mupc);
3229  points_to pta = make_points_to(mupcc, sink,
3232  add_arc_to_pt_map(pta, in);
3233  }
3234  gen_free_list(iptl);
3235 
3236  /* Find the incoming arcs on cells of "sink_l" and replace them by arcs
3237  towards copies of mupc. */
3238  list new = NIL, old = NIL;
3239  FOREACH(CELL, sink, sink_l) {
3240  if(!null_cell_p(sink) && !nowhere_cell_p(sink)) {
3241  /* Finds it sources */
3243  cell oc = points_to_source(pt);
3244  cell dc = points_to_sink(pt);
3245  if(points_to_cell_equal_p(dc, sink)) {
3246  points_to npt = make_points_to(copy_cell(oc), copy_cell(mupc),
3249  //add_arc_to_pt_map(npt, in);
3250  new = CONS(POINTS_TO, npt, new);
3251  // remove_arc_from_pt_map(pt, in);
3252  old = CONS(POINTS_TO, pt, old);
3253  }
3254  }
3255  }
3256  }
3257  FOREACH(POINTS_TO, npt, new)
3258  add_arc_to_pt_map(npt, in);
3259  FOREACH(POINTS_TO, pt, old)
3260  remove_arc_from_pt_map(pt, in);
3261  gen_free_list(new), gen_free_list(old);
3262  // pips_internal_error("not implemented yet.\n");
3263 
3264  /* Find the set of points-to arcs to destroy and remove them from
3265  * the points-to graph "in".
3266  */
3267  list ptal = points_to_source_to_arcs(source, in, false);
3268  FOREACH(POINTS_TO, pta, ptal) {
3269  cell sink = points_to_sink(pta);
3270  if(!null_cell_p(sink) && !nowhere_cell_p(sink))
3271  if(!points_to_cell_equal_p(sink, mupc))
3272  remove_arc_from_pt_map(pta, in);
3273  }
3274  gen_free_list(ptal);
3275 
3276  /* Create an arc from "source" to "mupc" */
3277  points_to pta = make_points_to(source, mupc,
3280  // add_arc_to_pt_map(pta, in); Might be done by the calller?
3281 
3282  pips_assert("\"out\" is consistent", consistent_pt_map_p(out));
3283 
3284  return pta;
3285 }
3286 
3287 /* returns the cell vertex "mod_cell" with the maximal out_degree in
3288  * graph "in", and its out-degree.
3289  *
3290  * When several cells have the same maximal out-degree, return any of
3291  * them.
3292  */
3294 {
3295  hash_table cell_out_degree = hash_table_make(hash_string, 0);
3296 
3298  cell source = points_to_source(pt);
3299  string name = points_to_cell_name(source);
3300  long long int i =
3301  (long long int) hash_get(cell_out_degree, (void *) name);
3302  if(i== (long long int) HASH_UNDEFINED_VALUE) {
3303  i = 1;
3304  hash_put(cell_out_degree, (void *) name, (void *) i);
3305  }
3306  else {
3307  i++;
3308  hash_update(cell_out_degree, (void *) name, (void *) i);
3309  }
3310  }
3311 
3312  long long int m = 0;
3313  HASH_MAP(k, v, {
3314  if((long long int) v > m) {
3315  m = (long long int) v;
3316  *mod_cell = strdup((string) k);
3317  }
3318  }, cell_out_degree);
3319  hash_table_free(cell_out_degree);
3320  return (int) m;
3321 }
3322 
3323 /* For the time being, control the out-degree of the vertices in
3324  * points-to graph "ptg" and fuse the vertex with the maximal
3325  * out-degree to reduce it if it is greater than an expected limit.
3326  *
3327  * Points-to graph "ptg" i modified by side-effects and returned.
3328  */
3330 {
3331  int odl = get_int_property("POINTS_TO_OUT_DEGREE_LIMIT");
3332  int sl = get_int_property("POINTS_TO_SUBSCRIPT_LIMIT");
3333 
3334  /* The out-degree limit must take the subscript limit sl into
3335  account as well as possible NULL and NOWHERE values (+2). The
3336  unbounded susbcript must also be added because it does not
3337  necessarily subsume all integer subscripts (+1). The subscript
3338  limit will kick in anyway later. Subscripts are limited to the
3339  range [-sl,sl], which contains 2*sl+1 values. */
3340  if(odl<2*sl+1+2) odl = 2*sl+1+2+1;
3341 
3342  pips_assert("odl is greater than one", odl>=1);
3343  string mod_cell_name = string_undefined; // maximum out-degree cell
3344  int od = maximal_out_degree_of_points_to_graph(&mod_cell_name, ptg);
3345  if(od>odl) {
3346  ifdebug(1) {
3347  pips_debug(1, "Normalization takes place for graph \"ptg\" with \"od\"=%d and \"odl\"=%d:\n", od, odl);
3348  print_points_to_set("Loop points-to set ptg:\n",
3349  points_to_graph_set(ptg));
3350  }
3351  // FI: not too sure about argument "true"
3352  cell mod_cell = points_to_source_name_to_source_cell(mod_cell_name, ptg, true);
3353  if(cell_undefined_p(mod_cell))
3354  pips_internal_error("Inconsistent result for ptg.\n");
3355  list sink_l = points_to_source_name_to_sinks(mod_cell_name, ptg, false);
3356  points_to pt = fuse_points_to_sink_cells(mod_cell, sink_l, ptg);
3357  add_arc_to_pt_map(pt, ptg);
3358  ifdebug(1) {
3359  pips_debug(1, "After normalization, \"ptg\":\n");
3360  print_points_to_set("Loop points-to set ptg:\n",
3361  points_to_graph_set(ptg));
3362  }
3363  }
3364  return ptg;
3365 }
3366 
3368 {
3370 }
3371 ␌
3372 /* Can cell c be accessed via another cell? */
3374 {
3375  set ptg_s = points_to_graph_set(ptg);
3376  bool unreachable_p = true;
3377 
3378  SET_FOREACH(points_to, pt, ptg_s) {
3379  cell sink = points_to_sink(pt);
3380  /* FI: the CP lattice should be used instead
3381  *
3382  * If "c" is somehow included into "sink", "c" is reachable. For
3383  * instance, if c[*] is reachable than c[1] is reachable too.
3384  *
3385  * But the opposite may be true: if c[1] is reachable, then c[*]
3386  * is reachable.
3387  *
3388  * However, if "struct s" is reachable, then so "s[next]" . But if
3389  * "s[next]" is reachable does not imply that "s" is reachable.
3390  */
3391  //if(points_to_cell_equal_p(c,sink)) {
3392  if(related_points_to_cells_p(c,sink)) {
3393  unreachable_p = false;
3394  break;
3395  }
3396  }
3397 
3398  return unreachable_p;
3399 }
3400 
3401 /* Remove arcs in points-to graph "ptg" when they start from a stub
3402  * cell that is not reachable.
3403  *
3404  * Points-to graph "ptg" is modified by side-effects and returned.
3405  *
3406  * This clean-up should be performed each time a projection is
3407  * performed, and even potentially, each time an arc is removed.
3408  *
3409  * Note: see also freed_pointer_to_points_to() for a recursive
3410  * implementation of the arc elimination. The current clean-up is
3411  * *not* recursive. This function should be called repeatedly till the
3412  * results converge to a fix point...
3413  */
3415 {
3416  set ptg_s = points_to_graph_set(ptg);
3417  list ual = NIL; // unreachable arc list
3418 
3419  pips_assert("pts is consistent before unreachable arc removal",
3420  consistent_pt_map_p(ptg));
3421 
3422  /* Find arcs whose origin vertex is an unreachable stub. */
3423  SET_FOREACH(points_to, pt, ptg_s) {
3424  cell source = points_to_source(pt);
3425  reference r = cell_any_reference(source);
3426  entity e = reference_variable(r);
3427  if(code == 3
3428  || ((code & 1) == 1 && entity_stub_sink_p(e))
3429  || ((code & 2) == 2 && entity_heap_location_p(e))) {
3430  // list S = points_to_source_to_sinks(source, ptg);
3431  list S = points_to_sink_to_sources(source, ptg, false);
3432  if(ENDP(S)) {
3433  if(verbose_p)
3434  pips_user_warning("Unreachable cell \"%s\" removed.\n",
3435  points_to_cell_to_string(source));
3436  ual = CONS(POINTS_TO, pt, ual);
3437  }
3438  gen_free_list(S);
3439  }
3440  }
3441 
3442  /* Remove arcs in ual. */
3443  FOREACH(POINTS_TO, pt, ual) {
3444  remove_arc_from_pt_map(pt, ptg);
3445  }
3446 
3447  //gen_full_free_list(ual);
3448 
3449  pips_assert("pts is consistent after unreachable arc removal",
3450  consistent_pt_map_p(ptg));
3451 
3452  return ptg;
3453 }
3454 
3456 {
3458  return out;
3459 }
3460 
3462 {
3464  return out;
3465 }
3466 
3467 /* This function looks pretty dangerous as variables can be reached by
3468  their names. */
3470 {
3472  return out;
3473 }
3474 ␌
3476 {
3477  bool consistent_p;
3478  set ptg_s = points_to_graph_set(ptg);
3479  if(points_to_graph_bottom(ptg)) {
3480  consistent_p = set_empty_p(ptg_s);
3481  if(!consistent_p)
3482  pips_internal_error("Bottom graph is not empty.\n");
3483  }
3484  else {
3485  consistent_p = consistent_points_to_set(ptg_s);
3486  }
3487  return consistent_p;
3488 }
3489 
3490 /* You know that null and undefined cells in "*pL" are impossible
3491  * because of the operation that is going to be performed on
3492  * it. Remove the corresponding arcs in points-to graph "in". Remove
3493  * the corresponding cells from "*pL".
3494  *
3495  * The search uses pointers. So "*pL" must contain sink cells of arcs of
3496  * "in".
3497  */
3499 {
3500  list fl = NIL;
3501  bool nowhere_ok_p =
3502  get_bool_property("POINTS_TO_UNINITIALIZED_POINTER_DEREFERENCING");
3503  FOREACH(CELL, pc, *pL) {
3504  if(null_cell_p(pc) || (nowhere_cell_p(pc) && !nowhere_ok_p)) {
3506  if(points_to_undefined_p(pt))
3507  pips_internal_error("NULL, returned as a source for an expression, "
3508  "does not appear in the points-to graph.\n");
3509  remove_arc_from_pt_map(pt, in);
3510  fl = CONS(CELL, pc, fl);
3511  }
3512  }
3513  gen_list_and_not(pL, fl);
3514  gen_free_list(fl);
3515 }
3516 ␌
3517 /* Check if points-to arc "spt" belongs to points-to set "pts". */
3519 {
3520  bool in_p = false;
3521  SET_FOREACH(points_to, pt, pts) {
3522  if(points_to_equal_p(spt, pt)) {
3523  in_p = true;
3524  break;
3525  }
3526  }
3527  return in_p;
3528 }
3529 
3532 
3533  if (!statement_unstructured_p(st)) {
3534  points_to_list ptl_in = load_pt_to_list(st);
3535  pt_in = new_pt_map();
3536  if(!points_to_list_bottom(ptl_in)) {
3537  pt_in = graph_assign_list(pt_in, points_to_list_list(ptl_in));
3538 
3539  ifdebug(7) {
3540  pips_debug(7, "\n print_points_to_graph \n");
3541  ifdebug(7) print_points_to_graph(pt_in);
3542  pips_debug(7, "in statement : ");
3543  ifdebug(7) print_statement(st);
3544  }
3545  }
3546  }
3547 
3548  return pt_in;
3549 }
3550 ␌
3551 /* Add a store independent points-to arc: source and destination
3552  * references include no dereferencing nor varying subscript such as
3553  * a[i].
3554  */
3556 {
3557  // consistent_points_to_arc_p() does not return with a non-consistent arc;
3558  bool consistent_p = store_independent_points_to_arc_p(a);
3559  if(consistent_p)
3561  (set) points_to_graph_set(s),
3562  (void *) a);
3563 }
3564 
3566 {
3567  // consistent_points_to_arc_p() does not return with a non-consistent arc;
3568  bool consistent_p = store_independent_points_to_arc_p(a);
3569  if(consistent_p)
3571  (set) points_to_graph_set(s),
3572  (void *) a);
3573  return s;
3574 }
3575 
3577 {
3578  // consistent_points_to_arc_p() does not return with a non-consistent arc;
3579  bool consistent_p = store_independent_points_to_arc_p(a);
3580  if(consistent_p)
3581  s = set_add_element(s, s, (void *) a);
3582  return s;
3583 }
3584 
3586 {
3587  s = set_del_element(s, s, (void *) a);
3588  return s;
3589 }
3590 
3591 /* The source and destination references imply no dereferencing but
3592  * the subscripts may be any kind of expression, such as a[i].
3593  *
3594  * This is not possible in general, but may be useful at a specific
3595  * statement level. This used to handle precisely the backward
3596  * translation at call sites, especially for simple and convex effects
3597  * backward translation.
3598  */
3600 {
3601  // consistent_points_to_arc_p() does not return with a non-consistent arc;
3602  bool consistent_p = dereferencing_free_points_to_arc_p(a);
3603  if(consistent_p)
3604  s = set_add_element(s, s, (void *) a);
3605  return s;
3606 }
3607 
__m64 v2si
Definition: 3dnow.h:7
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 make_descriptor_none(void)
Definition: effects.c:442
cell copy_cell(cell p)
CELL.
Definition: effects.c:246
void free_approximation(approximation p)
Definition: effects.c:135
points_to make_points_to(cell a1, cell a2, approximation a3, descriptor a4)
void free_points_to(points_to p)
points_to copy_points_to(points_to p)
POINTS_TO.
bool points_to_consistent_p(points_to p)
void free_points_to_graph(points_to_graph p)
points_to_graph make_points_to_graph(bool a1, set a2)
type make_type_variable(variable _field_)
Definition: ri.c:2715
type copy_type(type p)
TYPE.
Definition: ri.c:2655
basic copy_basic(basic p)
BASIC.
Definition: ri.c:104
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
reference make_reference(entity a1, list a2)
Definition: ri.c:2083
variable make_variable(basic a1, list a2, list a3)
Definition: ri.c:2895
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
static int count
Definition: SDG.c:519
struct _newgen_struct_entity_ * entity
Definition: abc_private.h:14
bool entity_heap_location_p(entity b)
package abstract location.
#define remove_arc_from_pt_map(a, s)
#define pt_map_undefined_p(pt)
#define consistent_pt_map_p(s)
#define clear_pt_map(pt)
#define new_pt_map()
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
bool entity_typed_anywhere_locations_p(entity e)
Test if an entity is the bottom of the lattice.
entity entity_anywhere_locations()
cell make_anywhere_cell(type t)
void const char const char const int
cell make_nowhere_cell()
This file contains all the operators defining constant paths :
cell make_typed_nowhere_cell(type t)
type cell_to_type(cell, bool *)
Definition: type.c:513
bool cell_equal_p(cell, cell)
CELLS.
Definition: effects.c:1226
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
bool cell_equivalent_p(cell, cell)
Check that memory locations denoted by cell "c1" can be reached by knowing cell "c2" and by using poi...
Definition: effects.c:1311
type points_to_cell_to_type(cell, bool *)
FI: I need more generality than is offered by cell_to_type()
Definition: type.c:665
cell points_to_cells_minimal_upper_bound(list)
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
string approximation_to_string(approximation)
Definition: prettyprint.c:458
type points_to_cell_to_concrete_type(cell)
Definition: type.c:676
bool points_to_cell_equal_p(cell, cell)
Definition: points_to.c:916
bool related_points_to_cells_p(cell, cell)
Definition: points_to.c:165
points_to_list load_pt_to_list(statement)
cell make_null_pointer_value_cell(void)
bool memory_dereferencing_p(reference)
Does the set of locations referenced by r depend on a pointer dereferencing?
Definition: effects.c:92
reference cell_to_reference(cell)
FI: probably to be moved elsewhere in ri-util.
Definition: effects.c:1326
bool cell_included_p(cell, cell)
Check that all memory locations denoted by cell "c1" are included in cell "c2".
Definition: effects.c:1294
bool anywhere_cell_p(cell)
Is it an anywhere cell?
Definition: effects.c:367
bool all_heap_locations_cell_p(cell)
Definition: effects.c:432
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
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
bool cell_abstract_location_p(cell)
Definition: effects.c:273
string effect_reference_to_string(reference)
Definition: prettyprint.c:155
bool null_pointer_value_cell_p(cell)
bool null_cell_p(cell)
Definition: effects.c:466
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 store_independent_points_to_reference_p(reference)
Functions for points-to references, the kind of references used in points-to cells.
Definition: points_to.c:1247
#define cell_undefined_p(x)
Definition: effects.h:431
#define approximation_tag(x)
Definition: effects.h:362
#define cell_undefined
Definition: effects.h:430
#define approximation_exact_p(x)
Definition: effects.h:369
#define CELL(x)
CELL.
Definition: effects.h:424
#define approximation_must_p(x)
Definition: effects.h:366
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
void free(void *)
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
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
#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
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#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
list gen_nthcdr(int n, const list lx)
caution: the first item is 0! was: return( (n<=0) ? l : gen_nthcdr( n-1, CDR( l ))) ; if n>gen_length...
Definition: list.c:700
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
bool statement_unstructured_p(statement)
Definition: statement.c:369
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
_uint hash_string_rank(const void *, size_t)
en s'inspirant vaguement de Fast Hashing of Variable-Length Text Strings Peter K.
Definition: hash.c:642
bool expression_constant_p(expression)
HPFC module by Fabien COELHO.
Definition: expression.c:2453
#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
static entity rank
#define MODULE_SEP_STRING
Definition: naming-local.h:30
const char * entity_minimal_user_name(entity e)
Do not preserve scope information.
Definition: naming.c:223
string bool_to_string(bool)
Definition: string.c:243
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
@ hash_string
Definition: newgen_hash.h:32
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56
set set_generic_make(set_type, hash_equals_t, hash_rank_t)
what about this replacement? #define SET_MAP(the_item, the_code, the_set) \ { SET_FOREACH(void *,...
Definition: set.c:83
bool set_empty_p(const set)
tell whether set s is empty.
Definition: set.c:367
set set_assign_list(set, const list)
assigns a list contents to a set all duplicated elements are lost
Definition: set.c:474
set set_del_element(set, const set, const void *)
Definition: set.c:265
set set_intersection(set, const set, const set)
Definition: set.c:229
#define set_undefined
Definition: newgen_set.h:48
#define SET_MAP(element, code, the_set)
Definition: newgen_set.h:54
set set_assign(set, const set)
Assign a set with the content of another set.
Definition: set.c:129
int set_size(const set)
returns the number of items in s.
Definition: set.c:359
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
void set_free(set)
Definition: set.c:332
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
bool set_belong_p(const set, const void *)
Definition: set.c:194
set set_union(set, const set, const set)
Definition: set.c:211
@ set_private
Definition: newgen_set.h:45
#define set_undefined_p(s)
Definition: newgen_set.h:49
set set_add_element(set, const set, const void *)
Definition: set.c:152
int tag
TAG.
Definition: newgen_types.h:92
#define string_undefined
Definition: newgen_types.h:40
char * string
STRING.
Definition: newgen_types.h:39
struct cons * list
Definition: newgen_types.h:106
uintptr_t _uint
Definition: newgen_types.h:54
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
void add_arc_to_points_to_context(points_to pt)
FI: it should rather work the other way round, with add_arc_to_statement_points_to_context() calling ...
Definition: passes.c:268
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
list expression_to_points_to_sinks(expression, pt_map)
The returned list contains cells used in "in".
Definition: sinks.c:1795
points_to create_stub_points_to(cell, type, bool)
int points_to_context_statement_line_number(void)
Definition: statement.c:120
#define points_to_approximation(x)
#define points_to_undefined_p(x)
#define points_to_undefined
#define points_to_sink(x)
#define points_to_domain_number(x)
#define points_to_graph_undefined
#define points_to_list_list(x)
struct _newgen_struct_points_to_ * points_to
#define points_to_graph_bottom(x)
#define POINTS_TO(x)
POINTS_TO.
#define points_to_list_bottom(x)
#define points_to_graph_set(x)
#define points_to_source(x)
set add_subscript_dependent_arc_to_simple_pt_map(points_to a, set s)
The source and destination references imply no dereferencing but the subscripts may be any kind of ex...
entity location_entity(cell c)
Definition: points_to_set.c:78
bool source_subset_in_set_p(cell source, set s)
test if a cell "source" appears as a source in a set of points-to
set points_to_function_projection(set pts)
"pts" is the points-to relation existing at the return point of a function.
list points_to_source_to_translations(cell source, pt_map ptm, bool fresh_p)
Use "ptm" as a translation map.
pt_map remove_unreachable_heap_vertices_in_points_to_graph(pt_map in, bool verbose_p)
pt_map remove_unreachable_stub_vertices_in_points_to_graph(pt_map in)
cell find_kth_points_to_node_in_points_to_path(list p, type t, int k)
Find the "k"-th node of type "t" in list "p".
void free_points_to_graph_sets(points_to_graph s,...)
Free several sets in one call.
bool arc_in_points_to_set_p(points_to spt, set pts)
Check if points-to arc "spt" belongs to points-to set "pts".
list points_to_sources_to_effective_sinks(list sources, pt_map ptm, bool fresh_p)
list stub_source_to_sinks(cell source, pt_map pts, bool fresh_p)
list generic_points_to_source_to_sinks(cell source, pt_map ptm, bool fresh_p, bool strict_p, bool all_p, bool effective_p)
Build the sinks of source "source" according to the points-to graphs.
bool points_to_compare_cell(cell c1, cell c2)
list nowhere_source_to_sinks(cell source, pt_map pts)
list points_to_source_to_any_sinks(cell source, pt_map ptm, bool fresh_p)
Retrieve all possible sinks of the source.
list sink_to_sources(cell sink, set pts, bool fresh_p)
Build a list of possible cell sources for cell "sink" in points-to graph "pts".
bool consistent_points_to_arc_p(points_to a, bool constant_subscript_p)
void upgrade_approximations_in_points_to_set(pt_map ptm)
When arcs have been removed from a points-to relation, the approximations of remaining arcs may not c...
string points_to_cell_name(cell source)
Create a string which is the cell reference in C syntax.
points_to create_k_limited_stub_points_to(cell source, type t, bool array_p, pt_map in)
Create a new node "sink" of type "t" and a new arc "pt" starting from node "source",...
bool source_in_graph_p(cell source, points_to_graph s)
cell type_compatible_super_cell(type t, cell c)
See if a super-cell of "c" exists witf type "t".
bool node_in_points_to_path_p(cell n, list p)
void dump_points_to(const points_to pt)
list reference_to_points_to_translations(entity v, list sl, pt_map ptm)
This function is designed to work properly for the translation of effects at call sites.
void print_or_dump_points_to_set(string what, set s, bool print_p)
Print a set of points-to for debug.
list sources_to_sinks(list sources, pt_map ptm, bool fresh_p)
Same as source_to_sinks, but for a list of cells.
bool cell_out_of_scope_p(cell c)
Return true if a cell is out of scope.
points_to find_arc_in_points_to_set(cell source, cell sink, pt_map ptm)
The approximation is not taken into account.
pt_map graph_assign_list(pt_map ptm, list l)
FI: I add functions dealing with points_to_graph variable, i.e.
void remove_impossible_arcs_to_null(list *pL, pt_map in)
You know that null and undefined cells in "*pL" are impossible because of the operation that is going...
points_to fuse_points_to_sink_cells(cell source, list sink_l, pt_map in)
All vertices in "sink_l" are assumed to be sinks of vertex "source" in points-to graph "in".
int points_to_cell_to_number_of_unbounded_dimensions(cell c)
list potential_to_effective_memory_leaks(list pmll, set res)
A new list, "emll", is allocated.
list points_to_reference_to_translation(reference n_r, list sl, pt_map ptm, bool fresh_p)
FI: easier it fresh_p is true...
cell points_to_source_name_to_source_cell(string sn, pt_map ptm, bool fresh_p)
static void refine_points_to_cell_subscripts(cell sc, cell ec, cell fc)
If the subscripts of the effective cell source "ec" are more precise than the subscripts of the cell ...
list source_to_sinks(cell source, pt_map pts, bool fresh_p)
Return a list of cells, "sinks", that are sink for some arc whose source is "source" or related to "s...
string points_to_cell_to_string(cell c)
list generic_stub_source_to_sinks(cell source, pt_map pts, bool array_p, bool fresh_p)
list points_to_source_name_to_sinks(string sn, pt_map ptm, bool fresh_p)
Use "sn" as a source name to derive a list of sink cells according to the points-to graph ptm.
list scalar_stub_source_to_sinks(cell source, pt_map pts, bool fresh_p)
list points_to_cell_null_initialization(cell c, pt_map pts)
If required according to the property, create a new arc from cell "c" to "null".
int points_to_reference_to_number_of_unbounded_dimensions(reference r)
set remove_points_to_cells(list cl, set g)
All nodes, i.e.
list reference_to_sinks(reference r, pt_map in, bool fresh_p)
list null_source_to_sinks(cell source, pt_map pts)
set points_to_set_block_projection(set pts, list l, bool main_p, bool body_p)
Remove from "pts" arcs based on at least one local entity in list "l" and preserve those based on sta...
bool store_independent_points_to_arc_p(points_to a)
list points_to_source_to_some_sinks(cell source, pt_map ptm, bool fresh_p)
May not retrieve all sinks of the source.
list points_to_sink_to_sources(cell sink, pt_map ptm, bool fresh_p)
Build the sources of sink "sink" according to the points-to graphs.
set add_arc_to_simple_pt_map(points_to a, set s)
bool points_to_compare_ptr_cell(const void *vcel1, const void *vcel2)
int points_to_compare_location(void *vpt1, void *vpt2)
Order the two points-to relations according to the alphabetical order of the underlying variables.
list pointer_source_to_sinks(cell sc, pt_map in)
Returns the sinks for a source cell "sc" of type pointer according to the points-to relation "in".
bool source_in_set_p(cell source, set s)
test if a cell appear as a source in a set of points-to
int points_to_equal_p(const void *vpt1, const void *vpt2)
returns true if two points-to arcs "vpt1" and "vpt2" are equal.
Definition: points_to_set.c:98
bool dereferencing_free_points_to_arc_p(points_to a)
void points_to_cell_list_and(list *a, const list b)
Compute A = A inter B: complexity in O(n2)
bool points_to_set_sharing_p(set s)
_uint points_to_rank(const void *vpt, size_t size)
create a key which is a concatenation of the source's name, the sink's name and the approximation of ...
list generic_points_to_sources_to_sinks(list sources, pt_map ptm, bool fresh_p, bool effective_p)
Build the union of the sinks of cells in "sources" according to the points-to graphs "ptm".
void remove_points_to_arcs(cell source, cell sink, pt_map pt)
int points_to_subscripts_to_number_of_unbounded_dimensions(list sl)
bool sink_in_set_p(cell sink, set s)
test if a cell appear as a sink in a set of points-to
bool consistent_points_to_graph_p(points_to_graph ptg)
set remove_arc_from_simple_pt_map(points_to a, set s)
set remove_points_to_cell(cell c, set g)
All arcs in relation "g" must be removed or updated if they use the node "c".
bool locations_equal_p(cell acc1, cell acc2)
eturn true if two acces_path are equals
Definition: points_to_set.c:89
string points_to_name(const points_to pt)
create a string which is a concatenation of the source's name, the sink's name and the approximation ...
bool cell_in_points_to_set_p(cell c, set pts)
Check if a cell c appears as source or sink in points-to set pts.
list array_stub_source_to_sinks(cell source, pt_map pts, bool fresh_p)
points_to points_to_sink_to_points_to(cell sink, pt_map ptm)
Return the points-to "fpt" ending in cell "sink" if it exists.
points_to points_to_path_to_k_limited_points_to_path(list p, int k, type t, bool array_p, pt_map in)
"p" is a points-to path ending with a cell that points towards a new cell ot type "t".
list variable_to_sinks(entity e, pt_map ptm, bool fresh_p)
Return all cells in points-to set "pts" who source is based on entity "e".
points_to_graph points_to_cell_source_projection(points_to_graph ptg, cell c)
Remove all arcs in "ptg" starting from "c".
list extended_sources_to_sinks(list pointed, pt_map in)
Same as extended_source_to_sinks, but for a set of cells, "pointed".
pt_map get_points_to_graph_from_statement(statement st)
void print_points_to_set(string what, set s)
pt_map add_arc_to_pt_map_(points_to a, pt_map s)
bool sinks_fully_matches_source_p(cell source, list sinks)
Is there at least one cell "sink" in list "sinks" whose subscripts fully match the subscripts in cell...
list null_to_sinks(cell source, pt_map ptm)
Create a list of null sinks and add a new null points-to relation to pts.
void print_points_to_path(list p)
For debugging.
pt_map generic_remove_unreachable_vertices_in_points_to_graph(pt_map ptg, int code, bool verbose_p)
Remove arcs in points-to graph "ptg" when they start from a stub cell that is not reachable.
list points_to_source_to_sinks(cell source, pt_map ptm, bool fresh_p)
Build the sinks of source "source" according to the points-to graphs.
bool points_to_in_list_p(points_to pt, const list lx)
bool cell_in_list_p(cell c, const list lx)
int maximal_out_degree_of_points_to_graph(string *mod_cell, pt_map in)
returns the cell vertex "mod_cell" with the maximal out_degree in graph "in", and its out-degree.
void print_points_to(const points_to pt)
list any_source_to_sinks(cell source, pt_map pts, bool fresh_p)
Generalization of source_to_sinks().
set points_to_source_projection(set pts, entity e)
Remove all arcs starting from e because e has been assigned a new value.
pt_map points_to_graph_assign(pt_map out, pt_map in)
void dump_points_to_set(string what, set s)
list extended_source_to_sinks(cell sc, pt_map in)
list points_to_sources_to_sinks(list sources, pt_map ptm, bool fresh_p)
void add_arc_to_pt_map(points_to a, pt_map s)
Add a store independent points-to arc: source and destination references include no dereferencing nor...
pt_map remove_unreachable_vertices_in_points_to_graph(pt_map in)
This function looks pretty dangerous as variables can be reached by their names.
list points_to_source_to_arcs(cell source, pt_map ptm, bool fresh_p)
Build the list of arcs whose source is "source" according to the points-to graphs "ptm".
pt_map normalize_points_to_graph(pt_map ptg)
For the time being, control the out-degree of the vertices in points-to graph "ptg" and fuse the vert...
set merge_points_to_set(set s1, set s2)
Merge two points-to sets.
pt_map merge_points_to_graphs(pt_map s1, pt_map s2)
void print_or_dump_points_to(const points_to pt, bool print_p)
print a points-to arc for debug
list formal_source_to_sinks(cell source, pt_map pts, bool fresh_p)
Creation of a stub for a formal parameter or for a reference based on a formal parameter.
bool unreachable_points_to_cell_p(cell c, pt_map ptg)
Can cell c be accessed via another cell?
set exact_to_may_points_to_set(set s)
Change the all the exact points-to relations to may relations.
list points_to_source_to_effective_sinks(cell source, pt_map ptm, bool fresh_p)
list global_source_to_sinks(cell source, pt_map pts, bool fresh_p)
list anywhere_source_to_sinks(cell source, pt_map pts)
source is assumed to be either nowhere/undefined or anywhere, it may be typed or not.
bool consistent_points_to_set(set s)
make sure that set "s" does not contain redundant or contradictory elements
bool type_compatible_with_points_to_cell_p(type t, cell c)
A type "t" is compatible with a cell "c" if any of the enclosing cell "c'" of "c",...
int compare_entities_without_scope(const entity *pe1, const entity *pe2)
cproto-generated files
Definition: points_to_set.c:60
string reference_to_string(reference r)
Definition: expression.c:87
string expression_to_string(expression e)
Definition: expression.c:77
void print_reference(reference r)
Definition: expression.c:142
#define points_to_domain
Definition: print.c:367
#define print_points_to_graph(x)
Definition: print.c:383
#define print_points_to_cell(x)
Definition: print.c:377
void print_type(type)
For debugging.
Definition: type.c:111
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
string type_to_full_string_definition(type)
type.c
Definition: type.c:45
static int tc
Internal variables
Definition: reindexing.c:107
#define PLUS_OPERATOR_NAME
#define binary_intrinsic_expression(name, e1, e2)
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
bool top_level_entity_p(entity e)
Check if the scope of entity e is global.
Definition: entity.c:1130
const char * entity_module_name(entity e)
See comments about module_name().
Definition: entity.c:1092
value EvalExpression(expression e)
Evaluate statically an expression.
Definition: eval.c:108
bool extended_integer_constant_expression_p(expression e)
More extensive than next function.
Definition: expression.c:858
bool zero_expression_p(expression e)
Definition: expression.c:1217
void reference_add_zero_subscripts(reference r, type t)
Definition: expression.c:261
int expression_to_int(expression exp)
================================================================
Definition: expression.c:2205
expression make_zero_expression(void)
Make a zero expression.
Definition: expression.c:1212
bool expression_equal_p(expression e1, expression e2)
Syntactic equality e1==e2.
Definition: expression.c:1347
expression int_to_expression(_int i)
transform an int into an expression and generate the corresponding entity if necessary; it is not cle...
Definition: expression.c:1188
bool unbounded_expression_p(expression e)
Definition: expression.c:4329
bool expression_lists_equal_p(list l1, list l2)
Definition: expression.c:1405
entity any_function_to_return_value(entity m)
Same as function_to_return_value(), but returns value_undefined when m is a C void function or a Fort...
Definition: module.c:516
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 const_variable_p(entity)
Definition: variable.c:1687
type ultimate_type(type)
Definition: type.c:3466
bool array_type_p(type)
Definition: type.c:2942
bool array_of_pointers_type_p(type)
Definition: type.c:3025
bool scalar_type_p(type)
Definition: type.c:2955
type type_to_array_type(type)
convert a type "t" into a newly allocated array type "at" whose elements are of type "t",...
Definition: type.c:5653
bool static_global_variable_p(entity)
Is v a global variable declared local to a C file such "static int i;".
Definition: variable.c:1498
bool type_equal_p(type, type)
Definition: type.c:547
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
list derived_type_to_fields(type)
Definition: type.c:5381
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
expression variable_initial_expression(entity)
Returns a copy of the initial (i.e.
Definition: variable.c:1899
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 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 array_of_struct_type_p(type)
Definition: type.c:3133
bool C_pointer_type_p(type)
Returns OK for "char[]" as well as for "char *".
Definition: type.c:3011
bool variable_static_p(entity)
true if v appears in a SAVE statement, or in a DATA statement, or is declared static i C.
Definition: variable.c:1579
bool concrete_array_pointer_type_equal_p(type, type)
Same as above, but resolve typedefs first.
Definition: type.c:700
#define type_functional_p(x)
Definition: ri.h:2950
#define type_struct(x)
Definition: ri.h:2964
#define type_struct_p(x)
Definition: ri.h:2962
#define functional_result(x)
Definition: ri.h:1444
#define value_constant(x)
Definition: ri.h:3073
#define reference_undefined
Definition: ri.h:2302
#define EXPRESSION_(x)
Definition: ri.h:1220
#define reference_variable(x)
Definition: ri.h:2326
#define basic_derived(x)
Definition: ri.h:640
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define constant_int(x)
Definition: ri.h:850
#define type_functional(x)
Definition: ri.h:2952
#define value_unknown_p(x)
Definition: ri.h:3077
#define type_variable(x)
Definition: ri.h:2949
#define basic_pointer_p(x)
Definition: ri.h:635
#define value_constant_p(x)
Definition: ri.h:3071
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define entity_undefined
Definition: ri.h:2761
#define constant_int_p(x)
Definition: ri.h:848
#define expression_undefined
Definition: ri.h:1223
#define entity_name(x)
Definition: ri.h:2790
#define reference_indices(x)
Definition: ri.h:2328
#define expression_undefined_p(x)
Definition: ri.h:1224
#define variable_dimensions(x)
Definition: ri.h:3122
#define type_undefined
Definition: ri.h:2883
#define type_area_p(x)
Definition: ri.h:2944
#define entity_type(x)
Definition: ri.h:2792
#define type_variable_p(x)
Definition: ri.h:2947
#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 ...
char * strdup()
int printf()
s1
Definition: set.c:247
return(s1)
#define ifdebug(n)
Definition: sg.c:47
int aux
Definition: solpip.c:104
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
string words_to_string(cons *lw)
Definition: print.c:211
char * int2a(int)
util.c
Definition: util.c:42