Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
f890ecdff51000f2a5e6f4da33b08c64459cd68e
[simgrid.git] / src / mc / mc_diff.cpp
1 /* Copyright (c) 2008-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 /* mc_diff - Memory snapshooting and comparison                             */
8
9 #include <array>
10 #include <memory>
11 #include <utility>
12
13 #include "src/xbt/ex_interface.h"   /* internals of backtrace setup */
14 #include "mc/mc.h"
15 #include "xbt/mmalloc.h"
16 #include "mc/datatypes.h"
17 #include "src/mc/malloc.hpp"
18 #include "src/mc/mc_private.h"
19 #include "src/mc/mc_snapshot.h"
20 #include "src/mc/mc_dwarf.hpp"
21 #include "src/mc/Type.hpp"
22
23 #include <xbt/dynar.h>
24
25 using simgrid::mc::remote;
26
27 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_diff, xbt,
28                                 "Logging specific to mc_diff in mc");
29
30 /*********************************** Heap comparison ***********************************/
31 /***************************************************************************************/
32
33 namespace simgrid {
34 namespace mc {
35
36 struct ProcessComparisonState {
37   std::vector<simgrid::mc::IgnoredHeapRegion>* to_ignore = nullptr;
38   std::vector<s_heap_area_t> equals_to;
39   std::vector<simgrid::mc::Type*> types;
40   std::size_t heapsize = 0;
41
42   void initHeapInformation(xbt_mheap_t heap,
43                           std::vector<simgrid::mc::IgnoredHeapRegion>* i);
44 };
45
46 struct StateComparator {
47   s_xbt_mheap_t std_heap_copy;
48   std::size_t heaplimit;
49   std::array<ProcessComparisonState, 2> processStates;
50
51   int initHeapInformation(
52     xbt_mheap_t heap1, xbt_mheap_t heap2,
53     std::vector<simgrid::mc::IgnoredHeapRegion>* i1,
54     std::vector<simgrid::mc::IgnoredHeapRegion>* i2);
55
56   s_heap_area_t& equals_to1_(std::size_t i, std::size_t j)
57   {
58     return processStates[0].equals_to[ MAX_FRAGMENT_PER_BLOCK * i + j];
59   }
60   s_heap_area_t& equals_to2_(std::size_t i, std::size_t j)
61   {
62     return processStates[1].equals_to[ MAX_FRAGMENT_PER_BLOCK * i + j];
63   }
64   Type*& types1_(std::size_t i, std::size_t j)
65   {
66     return processStates[0].types[ MAX_FRAGMENT_PER_BLOCK * i + j];
67   }
68   Type*& types2_(std::size_t i, std::size_t j)
69   {
70     return processStates[1].types[ MAX_FRAGMENT_PER_BLOCK * i + j];
71   }
72 };
73
74 }
75 }
76
77 // TODO, make this a field of ModelChecker or something similar
78 static std::unique_ptr<simgrid::mc::StateComparator> mc_diff_info;
79
80 /*********************************** Free functions ************************************/
81
82 static void heap_area_pair_free(heap_area_pair_t pair)
83 {
84   xbt_free(pair);
85   pair = nullptr;
86 }
87
88 static void heap_area_pair_free_voidp(void *d)
89 {
90   heap_area_pair_free((heap_area_pair_t) * (void **) d);
91 }
92
93 static void heap_area_free(heap_area_t area)
94 {
95   xbt_free(area);
96   area = nullptr;
97 }
98
99 /************************************************************************************/
100
101 static s_heap_area_t make_heap_area(int block, int fragment)
102 {
103   s_heap_area_t area;
104   area.valid = 1;
105   area.block = block;
106   area.fragment = fragment;
107   return area;
108 }
109
110
111 static int is_new_heap_area_pair(xbt_dynar_t list, int block1, int fragment1,
112                                  int block2, int fragment2)
113 {
114
115   unsigned int cursor = 0;
116   heap_area_pair_t current_pair;
117
118   xbt_dynar_foreach(list, cursor, current_pair)
119     if (current_pair->block1 == block1 && current_pair->block2 == block2
120         && current_pair->fragment1 == fragment1
121         && current_pair->fragment2 == fragment2)
122       return 0;
123
124   return 1;
125 }
126
127 static int add_heap_area_pair(xbt_dynar_t list, int block1, int fragment1,
128                               int block2, int fragment2)
129 {
130
131   if (is_new_heap_area_pair(list, block1, fragment1, block2, fragment2)) {
132     heap_area_pair_t pair = nullptr;
133     pair = xbt_new0(s_heap_area_pair_t, 1);
134     pair->block1 = block1;
135     pair->fragment1 = fragment1;
136     pair->block2 = block2;
137     pair->fragment2 = fragment2;
138
139     xbt_dynar_push(list, &pair);
140
141     return 1;
142   }
143
144   return 0;
145 }
146
147 static ssize_t heap_comparison_ignore_size(
148   std::vector<simgrid::mc::IgnoredHeapRegion>* ignore_list,
149   const void *address)
150 {
151   int start = 0;
152   int end = ignore_list->size() - 1;
153
154   while (start <= end) {
155     unsigned int cursor = (start + end) / 2;
156     simgrid::mc::IgnoredHeapRegion const& region = (*ignore_list)[cursor];
157     if (region.address == address)
158       return region.size;
159     if (region.address < address)
160       start = cursor + 1;
161     if (region.address > address)
162       end = cursor - 1;
163   }
164
165   return -1;
166 }
167
168 static bool is_stack(const void *address)
169 {
170   for (auto const& stack : mc_model_checker->process().stack_areas())
171     if (address == stack.address)
172       return true;
173   return false;
174 }
175
176 // TODO, this should depend on the snapshot?
177 static bool is_block_stack(int block)
178 {
179   for (auto const& stack : mc_model_checker->process().stack_areas())
180     if (block == stack.block)
181       return true;
182   return false;
183 }
184
185 static void match_equals(simgrid::mc::StateComparator *state, xbt_dynar_t list)
186 {
187
188   unsigned int cursor = 0;
189   heap_area_pair_t current_pair;
190
191   xbt_dynar_foreach(list, cursor, current_pair)
192
193     if (current_pair->fragment1 != -1) {
194
195       state->equals_to1_(current_pair->block1, current_pair->fragment1) =
196           make_heap_area(current_pair->block2, current_pair->fragment2);
197       state->equals_to2_(current_pair->block2, current_pair->fragment2) =
198           make_heap_area(current_pair->block1, current_pair->fragment1);
199
200     } else {
201
202       state->equals_to1_(current_pair->block1, 0) =
203           make_heap_area(current_pair->block2, current_pair->fragment2);
204       state->equals_to2_(current_pair->block2, 0) =
205           make_heap_area(current_pair->block1, current_pair->fragment1);
206
207     }
208
209 }
210
211 /** Check whether two blocks are known to be matching
212  *
213  *  @param state  State used
214  *  @param b1     Block of state 1
215  *  @param b2     Block of state 2
216  *  @return       if the blocks are known to be matching
217  */
218 static int equal_blocks(simgrid::mc::StateComparator *state, int b1, int b2)
219 {
220
221   if (state->equals_to1_(b1, 0).block == b2
222       && state->equals_to2_(b2, 0).block == b1)
223     return 1;
224
225   return 0;
226 }
227
228 /** Check whether two fragments are known to be matching
229  *
230  *  @param state  State used
231  *  @param b1     Block of state 1
232  *  @param f1     Fragment of state 1
233  *  @param b2     Block of state 2
234  *  @param f2     Fragment of state 2
235  *  @return       if the fragments are known to be matching
236  */
237 static int equal_fragments(simgrid::mc::StateComparator *state, int b1, int f1, int b2,
238                            int f2)
239 {
240
241   if (state->equals_to1_(b1, f1).block == b2
242       && state->equals_to1_(b1, f1).fragment == f2
243       && state->equals_to2_(b2, f2).block == b1
244       && state->equals_to2_(b2, f2).fragment == f1)
245     return 1;
246
247   return 0;
248 }
249
250 namespace simgrid {
251 namespace mc {
252
253 int init_heap_information(xbt_mheap_t heap1, xbt_mheap_t heap2,
254                           std::vector<simgrid::mc::IgnoredHeapRegion>* i1,
255                           std::vector<simgrid::mc::IgnoredHeapRegion>* i2)
256 {
257   if (mc_diff_info == nullptr)
258     mc_diff_info = std::unique_ptr<StateComparator>(new StateComparator());
259   return mc_diff_info->initHeapInformation(heap1, heap2, i1, i2);
260 }
261
262 void ProcessComparisonState::initHeapInformation(xbt_mheap_t heap,
263                         std::vector<simgrid::mc::IgnoredHeapRegion>* i)
264 {
265   auto heaplimit = ((struct mdesc *) heap)->heaplimit;
266   this->heapsize = ((struct mdesc *) heap)->heapsize;
267   this->to_ignore = i;
268   this->equals_to.assign(heaplimit * MAX_FRAGMENT_PER_BLOCK, s_heap_area {0, 0, 0});
269   this->types.assign(heaplimit * MAX_FRAGMENT_PER_BLOCK, nullptr);
270 }
271
272 int StateComparator::initHeapInformation(xbt_mheap_t heap1, xbt_mheap_t heap2,
273                           std::vector<simgrid::mc::IgnoredHeapRegion>* i1,
274                           std::vector<simgrid::mc::IgnoredHeapRegion>* i2)
275 {
276   if ((((struct mdesc *) heap1)->heaplimit !=
277        ((struct mdesc *) heap2)->heaplimit)
278       ||
279       ((((struct mdesc *) heap1)->heapsize !=
280         ((struct mdesc *) heap2)->heapsize)))
281     return -1;
282   this->heaplimit = ((struct mdesc *) heap1)->heaplimit;
283   this->std_heap_copy = *mc_model_checker->process().get_heap();
284   this->processStates[0].initHeapInformation(heap1, i1);
285   this->processStates[1].initHeapInformation(heap2, i2);
286   return 0;
287 }
288
289 void reset_heap_information()
290 {
291
292 }
293
294 // TODO, have a robust way to find it in O(1)
295 static inline
296 mc_mem_region_t MC_get_heap_region(simgrid::mc::Snapshot* snapshot)
297 {
298   size_t n = snapshot->snapshot_regions.size();
299   for (size_t i=0; i!=n; ++i) {
300     mc_mem_region_t region = snapshot->snapshot_regions[i].get();
301     if (region->region_type() == simgrid::mc::RegionType::Heap)
302       return region;
303   }
304   xbt_die("No heap region");
305 }
306
307 int mmalloc_compare_heap(simgrid::mc::Snapshot* snapshot1, simgrid::mc::Snapshot* snapshot2)
308 {
309   simgrid::mc::Process* process = &mc_model_checker->process();
310   simgrid::mc::StateComparator *state = mc_diff_info.get();
311
312   /* Start comparison */
313   size_t i1, i2, j1, j2, k;
314   void *addr_block1, *addr_block2, *addr_frag1, *addr_frag2;
315   int nb_diff1 = 0, nb_diff2 = 0;
316
317   int equal, res_compare = 0;
318
319   /* Check busy blocks */
320
321   i1 = 1;
322
323   malloc_info heapinfo_temp1, heapinfo_temp2;
324   malloc_info heapinfo_temp2b;
325
326   mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
327   mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
328
329   // This is the address of std_heap->heapinfo in the application process:
330   void* heapinfo_address = &((xbt_mheap_t) process->heap_address)->heapinfo;
331
332   // This is in snapshot do not use them directly:
333   const malloc_info* heapinfos1 = snapshot1->read<malloc_info*>(
334     (std::uint64_t)heapinfo_address, simgrid::mc::ProcessIndexMissing);
335   const malloc_info* heapinfos2 = snapshot2->read<malloc_info*>(
336     (std::uint64_t)heapinfo_address, simgrid::mc::ProcessIndexMissing);
337
338   while (i1 < state->heaplimit) {
339
340     const malloc_info* heapinfo1 = (const malloc_info*) MC_region_read(heap_region1, &heapinfo_temp1, &heapinfos1[i1], sizeof(malloc_info));
341     const malloc_info* heapinfo2 = (const malloc_info*) MC_region_read(heap_region2, &heapinfo_temp2, &heapinfos2[i1], sizeof(malloc_info));
342
343     if (heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type == MMALLOC_TYPE_HEAPINFO) {      /* Free block */
344       i1 ++;
345       continue;
346     }
347
348     if (heapinfo1->type < 0) {
349       fprintf(stderr, "Unkown mmalloc block type.\n");
350       abort();
351     }
352
353     addr_block1 =
354         ((void *) (((ADDR2UINT(i1)) - 1) * BLOCKSIZE +
355                    (char *) state->std_heap_copy.heapbase));
356
357     if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED) {       /* Large block */
358
359       if (is_stack(addr_block1)) {
360         for (k = 0; k < heapinfo1->busy_block.size; k++)
361           state->equals_to1_(i1 + k, 0) = make_heap_area(i1, -1);
362         for (k = 0; k < heapinfo2->busy_block.size; k++)
363           state->equals_to2_(i1 + k, 0) = make_heap_area(i1, -1);
364         i1 += heapinfo1->busy_block.size;
365         continue;
366       }
367
368       if (state->equals_to1_(i1, 0).valid) {
369         i1++;
370         continue;
371       }
372
373       i2 = 1;
374       equal = 0;
375       res_compare = 0;
376
377       /* Try first to associate to same block in the other heap */
378       if (heapinfo2->type == heapinfo1->type) {
379
380         if (state->equals_to2_(i1, 0).valid == 0) {
381
382           addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE +
383                          (char *) state->std_heap_copy.heapbase;
384
385           res_compare =
386               compare_heap_area(simgrid::mc::ProcessIndexMissing, addr_block1, addr_block2, snapshot1, snapshot2,
387                                 nullptr, nullptr, 0);
388
389           if (res_compare != 1) {
390             for (k = 1; k < heapinfo2->busy_block.size; k++)
391               state->equals_to2_(i1 + k, 0) = make_heap_area(i1, -1);
392             for (k = 1; k < heapinfo1->busy_block.size; k++)
393               state->equals_to1_(i1 + k, 0) = make_heap_area(i1, -1);
394             equal = 1;
395             i1 += heapinfo1->busy_block.size;
396           }
397
398         }
399
400       }
401
402       while (i2 < state->heaplimit && !equal) {
403
404         addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE +
405                        (char *) state->std_heap_copy.heapbase;
406
407         if (i2 == i1) {
408           i2++;
409           continue;
410         }
411
412         const malloc_info* heapinfo2b = (const malloc_info*) MC_region_read(heap_region2, &heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info));
413
414         if (heapinfo2b->type != MMALLOC_TYPE_UNFRAGMENTED) {
415           i2++;
416           continue;
417         }
418
419         if (state->equals_to2_(i2, 0).valid) {
420           i2++;
421           continue;
422         }
423
424         res_compare =
425             compare_heap_area(simgrid::mc::ProcessIndexMissing, addr_block1, addr_block2, snapshot1, snapshot2,
426                               nullptr, nullptr, 0);
427
428         if (res_compare != 1) {
429           for (k = 1; k < heapinfo2b->busy_block.size; k++)
430             state->equals_to2_(i2 + k, 0) = make_heap_area(i1, -1);
431           for (k = 1; k < heapinfo1->busy_block.size; k++)
432             state->equals_to1_(i1 + k, 0) = make_heap_area(i2, -1);
433           equal = 1;
434           i1 += heapinfo1->busy_block.size;
435         }
436
437         i2++;
438
439       }
440
441       if (!equal) {
442         XBT_DEBUG("Block %zu not found (size_used = %zu, addr = %p)", i1,
443                   heapinfo1->busy_block.busy_size, addr_block1);
444         i1 = state->heaplimit + 1;
445         nb_diff1++;
446         //i1++;
447       }
448
449     } else {                    /* Fragmented block */
450
451       for (j1 = 0; j1 < (size_t) (BLOCKSIZE >> heapinfo1->type); j1++) {
452
453         if (heapinfo1->busy_frag.frag_size[j1] == -1) /* Free fragment */
454           continue;
455
456         if (state->equals_to1_(i1, j1).valid)
457           continue;
458
459         addr_frag1 =
460             (void *) ((char *) addr_block1 + (j1 << heapinfo1->type));
461
462         i2 = 1;
463         equal = 0;
464
465         /* Try first to associate to same fragment in the other heap */
466         if (heapinfo2->type == heapinfo1->type) {
467
468           if (state->equals_to2_(i1, j1).valid == 0) {
469
470             addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE +
471                            (char *) state->std_heap_copy.heapbase;
472             addr_frag2 =
473                 (void *) ((char *) addr_block2 +
474                           (j1 << heapinfo2->type));
475
476             res_compare =
477                 compare_heap_area(simgrid::mc::ProcessIndexMissing, addr_frag1, addr_frag2, snapshot1, snapshot2,
478                                   nullptr, nullptr, 0);
479
480             if (res_compare != 1)
481               equal = 1;
482
483           }
484
485         }
486
487         while (i2 < state->heaplimit && !equal) {
488
489           const malloc_info* heapinfo2b = (const malloc_info*) MC_region_read(
490             heap_region2, &heapinfo_temp2b, &heapinfos2[i2],
491             sizeof(malloc_info));
492
493           if (heapinfo2b->type == MMALLOC_TYPE_FREE || heapinfo2b->type == MMALLOC_TYPE_HEAPINFO) {
494             i2 ++;
495             continue;
496           }
497
498           // We currently do not match fragments with unfragmented blocks (maybe we should).
499           if (heapinfo2b->type == MMALLOC_TYPE_UNFRAGMENTED) {
500             i2++;
501             continue;
502           }
503
504           if (heapinfo2b->type < 0) {
505             fprintf(stderr, "Unkown mmalloc block type.\n");
506             abort();
507           }
508
509           for (j2 = 0; j2 < (size_t) (BLOCKSIZE >> heapinfo2b->type);
510                j2++) {
511
512             if (i2 == i1 && j2 == j1)
513               continue;
514
515             if (state->equals_to2_(i2, j2).valid)
516               continue;
517
518             addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE +
519                            (char *) state->std_heap_copy.heapbase;
520             addr_frag2 =
521                 (void *) ((char *) addr_block2 +
522                           (j2 << heapinfo2b->type));
523
524             res_compare =
525                 compare_heap_area(simgrid::mc::ProcessIndexMissing, addr_frag1, addr_frag2, snapshot2, snapshot2,
526                                   nullptr, nullptr, 0);
527
528             if (res_compare != 1) {
529               equal = 1;
530               break;
531             }
532
533           }
534
535           i2++;
536
537         }
538
539         if (!equal) {
540           XBT_DEBUG
541               ("Block %zu, fragment %zu not found (size_used = %zd, address = %p)\n",
542                i1, j1, heapinfo1->busy_frag.frag_size[j1],
543                addr_frag1);
544           i2 = state->heaplimit + 1;
545           i1 = state->heaplimit + 1;
546           nb_diff1++;
547           break;
548         }
549
550       }
551
552       i1++;
553
554     }
555
556   }
557
558   /* All blocks/fragments are equal to another block/fragment ? */
559   size_t i = 1, j = 0;
560
561   for(i = 1; i < state->heaplimit; i++) {
562     const malloc_info* heapinfo1 = (const malloc_info*) MC_region_read(
563       heap_region1, &heapinfo_temp1, &heapinfos1[i], sizeof(malloc_info));
564     if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED) {
565       if (i1 == state->heaplimit) {
566         if (heapinfo1->busy_block.busy_size > 0) {
567           if (state->equals_to1_(i, 0).valid == 0) {
568             if (XBT_LOG_ISENABLED(mc_diff, xbt_log_priority_debug)) {
569               // TODO, add address
570               XBT_DEBUG("Block %zu not found (size used = %zu)", i,
571                         heapinfo1->busy_block.busy_size);
572             }
573             nb_diff1++;
574           }
575         }
576       }
577     }
578     if (heapinfo1->type > 0) {
579       for (j = 0; j < (size_t) (BLOCKSIZE >> heapinfo1->type); j++) {
580         if (i1 == state->heaplimit) {
581           if (heapinfo1->busy_frag.frag_size[j] > 0) {
582             if (state->equals_to1_(i, j).valid == 0) {
583               if (XBT_LOG_ISENABLED(mc_diff, xbt_log_priority_debug)) {
584                 // TODO, print fragment address
585                 XBT_DEBUG
586                     ("Block %zu, Fragment %zu not found (size used = %zd)",
587                      i, j,
588                      heapinfo1->busy_frag.frag_size[j]);
589               }
590               nb_diff1++;
591             }
592           }
593         }
594       }
595     }
596   }
597
598   if (i1 == state->heaplimit)
599     XBT_DEBUG("Number of blocks/fragments not found in heap1 : %d", nb_diff1);
600
601   for (i=1; i < state->heaplimit; i++) {
602     const malloc_info* heapinfo2 = (const malloc_info*) MC_region_read(
603       heap_region2, &heapinfo_temp2, &heapinfos2[i], sizeof(malloc_info));
604     if (heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED) {
605       if (i1 == state->heaplimit) {
606         if (heapinfo2->busy_block.busy_size > 0) {
607           if (state->equals_to2_(i, 0).valid == 0) {
608             if (XBT_LOG_ISENABLED(mc_diff, xbt_log_priority_debug)) {
609               // TODO, print address of the block
610               XBT_DEBUG("Block %zu not found (size used = %zu)", i,
611                         heapinfo2->busy_block.busy_size);
612             }
613             nb_diff2++;
614           }
615         }
616       }
617     }
618     if (heapinfo2->type > 0) {
619       for (j = 0; j < (size_t) (BLOCKSIZE >> heapinfo2->type); j++) {
620         if (i1 == state->heaplimit) {
621           if (heapinfo2->busy_frag.frag_size[j] > 0) {
622             if (state->equals_to2_(i, j).valid == 0) {
623               if (XBT_LOG_ISENABLED(mc_diff, xbt_log_priority_debug)) {
624                 // TODO, print address of the block
625                 XBT_DEBUG
626                     ("Block %zu, Fragment %zu not found (size used = %zd)",
627                      i, j,
628                      heapinfo2->busy_frag.frag_size[j]);
629               }
630               nb_diff2++;
631             }
632           }
633         }
634       }
635     }
636   }
637
638   if (i1 == state->heaplimit)
639     XBT_DEBUG("Number of blocks/fragments not found in heap2 : %d", nb_diff2);
640
641   return ((nb_diff1 > 0) || (nb_diff2 > 0));
642 }
643
644 /**
645  *
646  * @param state
647  * @param real_area1     Process address for state 1
648  * @param real_area2     Process address for state 2
649  * @param snapshot1      Snapshot of state 1
650  * @param snapshot2      Snapshot of state 2
651  * @param previous
652  * @param size
653  * @param check_ignore
654  */
655 static int compare_heap_area_without_type(
656   simgrid::mc::StateComparator *state, int process_index,
657   const void *real_area1, const void *real_area2,
658   simgrid::mc::Snapshot* snapshot1,
659   simgrid::mc::Snapshot* snapshot2,
660   xbt_dynar_t previous, int size,
661   int check_ignore)
662 {
663   simgrid::mc::Process* process = &mc_model_checker->process();
664
665   int i = 0;
666   const void *addr_pointed1, *addr_pointed2;
667   int pointer_align, res_compare;
668   ssize_t ignore1, ignore2;
669
670   mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
671   mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
672
673   while (i < size) {
674
675     if (check_ignore > 0) {
676       if ((ignore1 =
677            heap_comparison_ignore_size(state->processStates[0].to_ignore,
678                                        (char *) real_area1 + i)) != -1) {
679         if ((ignore2 =
680              heap_comparison_ignore_size(state->processStates[1].to_ignore,
681                                          (char *) real_area2 + i)) == ignore1) {
682           if (ignore1 == 0) {
683             check_ignore--;
684             return 0;
685           } else {
686             i = i + ignore2;
687             check_ignore--;
688             continue;
689           }
690         }
691       }
692     }
693
694     if (MC_snapshot_region_memcmp(((char *) real_area1) + i, heap_region1, ((char *) real_area2) + i, heap_region2, 1) != 0) {
695
696       pointer_align = (i / sizeof(void *)) * sizeof(void *);
697       addr_pointed1 = snapshot1->read(
698         remote((void**)((char *) real_area1 + pointer_align)), process_index);
699       addr_pointed2 = snapshot2->read(
700         remote((void**)((char *) real_area2 + pointer_align)), process_index);
701
702       if (process->in_maestro_stack(remote(addr_pointed1))
703         && process->in_maestro_stack(remote(addr_pointed2))) {
704         i = pointer_align + sizeof(void *);
705         continue;
706       } else if (addr_pointed1 > state->std_heap_copy.heapbase
707                  && addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)
708                  && addr_pointed2 > state->std_heap_copy.heapbase
709                  && addr_pointed2 < mc_snapshot_get_heap_end(snapshot2)) {
710         // Both addreses are in the heap:
711         res_compare =
712             compare_heap_area(process_index, addr_pointed1, addr_pointed2, snapshot1,
713                               snapshot2, previous, nullptr, 0);
714         if (res_compare == 1)
715           return res_compare;
716         i = pointer_align + sizeof(void *);
717         continue;
718       } else
719         return 1;
720
721     }
722
723     i++;
724
725   }
726
727   return 0;
728
729 }
730
731 /**
732  *
733  * @param state
734  * @param real_area1     Process address for state 1
735  * @param real_area2     Process address for state 2
736  * @param snapshot1      Snapshot of state 1
737  * @param snapshot2      Snapshot of state 2
738  * @param previous
739  * @param type_id
740  * @param area_size      either a byte_size or an elements_count (?)
741  * @param check_ignore
742  * @param pointer_level
743  * @return               0 (same), 1 (different), -1 (unknown)
744  */
745 static int compare_heap_area_with_type(
746   simgrid::mc::StateComparator *state, int process_index,
747   const void *real_area1, const void *real_area2,
748   simgrid::mc::Snapshot* snapshot1,
749   simgrid::mc::Snapshot* snapshot2,
750   xbt_dynar_t previous, simgrid::mc::Type* type,
751   int area_size, int check_ignore,
752   int pointer_level)
753 {
754 top:
755
756   // HACK: This should not happen but in pratice, there are some
757   // DW_TAG_typedef without an associated DW_AT_type:
758   //<1><538832>: Abbrev Number: 111 (DW_TAG_typedef)
759   //    <538833>   DW_AT_name        : (indirect string, offset: 0x2292f3): gregset_t
760   //    <538837>   DW_AT_decl_file   : 98
761   //    <538838>   DW_AT_decl_line   : 37
762   if (type == nullptr)
763     return 0;
764
765   if (is_stack(real_area1) && is_stack(real_area2))
766     return 0;
767   ssize_t ignore1, ignore2;
768
769   if ((check_ignore > 0)
770       && ((ignore1 = heap_comparison_ignore_size(
771         state->processStates[0].to_ignore, real_area1))
772           > 0)
773       && ((ignore2 = heap_comparison_ignore_size(
774           state->processStates[1].to_ignore, real_area2))
775           == ignore1))
776     return 0;
777
778   simgrid::mc::Type *subtype, *subsubtype;
779   int res, elm_size;
780   const void *addr_pointed1, *addr_pointed2;
781
782   mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
783   mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
784
785   switch (type->type) {
786   case DW_TAG_unspecified_type:
787     return 1;
788
789   case DW_TAG_base_type:
790     if (!type->name.empty() && type->name == "char") {        /* String, hence random (arbitrary ?) size */
791       if (real_area1 == real_area2)
792         return -1;
793       else
794         return (MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, area_size) != 0);
795     } else {
796       if (area_size != -1 && type->byte_size != area_size)
797         return -1;
798       else
799         return (MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0);
800     }
801     break;
802   case DW_TAG_enumeration_type:
803     if (area_size != -1 && type->byte_size != area_size)
804       return -1;
805     else
806       return (MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0);
807     break;
808   case DW_TAG_typedef:
809   case DW_TAG_const_type:
810   case DW_TAG_volatile_type:
811     // Poor man's TCO:
812     type = type->subtype;
813     goto top;
814     break;
815   case DW_TAG_array_type:
816     subtype = type->subtype;
817     switch (subtype->type) {
818     case DW_TAG_unspecified_type:
819       return 1;
820
821     case DW_TAG_base_type:
822     case DW_TAG_enumeration_type:
823     case DW_TAG_pointer_type:
824     case DW_TAG_reference_type:
825     case DW_TAG_rvalue_reference_type:
826     case DW_TAG_structure_type:
827     case DW_TAG_class_type:
828     case DW_TAG_union_type:
829       if (subtype->full_type)
830         subtype = subtype->full_type;
831       elm_size = subtype->byte_size;
832       break;
833       // TODO, just remove the type indirection?
834     case DW_TAG_const_type:
835     case DW_TAG_typedef:
836     case DW_TAG_volatile_type:
837       subsubtype = subtype->subtype;
838       if (subsubtype->full_type)
839         subsubtype = subsubtype->full_type;
840       elm_size = subsubtype->byte_size;
841       break;
842     default:
843       return 0;
844       break;
845     }
846     for (int i = 0; i < type->element_count; i++) {
847       // TODO, add support for variable stride (DW_AT_byte_stride)
848       res =
849           compare_heap_area_with_type(state, process_index,
850                                       (char *) real_area1 + (i * elm_size),
851                                       (char *) real_area2 + (i * elm_size),
852                                       snapshot1, snapshot2, previous,
853                                       type->subtype, subtype->byte_size,
854                                       check_ignore, pointer_level);
855       if (res == 1)
856         return res;
857     }
858     break;
859   case DW_TAG_reference_type:
860   case DW_TAG_rvalue_reference_type:
861   case DW_TAG_pointer_type:
862     if (type->subtype && type->subtype->type == DW_TAG_subroutine_type) {
863       addr_pointed1 = snapshot1->read(remote((void**)real_area1), process_index);
864       addr_pointed2 = snapshot2->read(remote((void**)real_area2), process_index);
865       return (addr_pointed1 != addr_pointed2);;
866     } else {
867       pointer_level++;
868       if (pointer_level > 1) {  /* Array of pointers */
869         for (size_t i = 0; i < (area_size / sizeof(void *)); i++) {
870           addr_pointed1 = snapshot1->read(
871             remote((void**)((char*) real_area1 + i * sizeof(void *))),
872             process_index);
873           addr_pointed2 = snapshot2->read(
874             remote((void**)((char*) real_area2 + i * sizeof(void *))),
875             process_index);
876           if (addr_pointed1 > state->std_heap_copy.heapbase
877               && addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)
878               && addr_pointed2 > state->std_heap_copy.heapbase
879               && addr_pointed2 < mc_snapshot_get_heap_end(snapshot2))
880             res =
881                 compare_heap_area(process_index, addr_pointed1, addr_pointed2, snapshot1,
882                                   snapshot2, previous, type->subtype,
883                                   pointer_level);
884           else
885             res = (addr_pointed1 != addr_pointed2);
886           if (res == 1)
887             return res;
888         }
889       } else {
890         addr_pointed1 = snapshot1->read(remote((void**)real_area1), process_index);
891         addr_pointed2 = snapshot2->read(remote((void**)real_area2), process_index);
892         if (addr_pointed1 > state->std_heap_copy.heapbase
893             && addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)
894             && addr_pointed2 > state->std_heap_copy.heapbase
895             && addr_pointed2 < mc_snapshot_get_heap_end(snapshot2))
896           return compare_heap_area(process_index, addr_pointed1, addr_pointed2, snapshot1,
897                                    snapshot2, previous, type->subtype,
898                                    pointer_level);
899         else
900           return (addr_pointed1 != addr_pointed2);
901       }
902     }
903     break;
904   case DW_TAG_structure_type:
905   case DW_TAG_class_type:
906     if (type->full_type)
907       type = type->full_type;
908     if (area_size != -1 && type->byte_size != area_size) {
909       if (area_size > type->byte_size && area_size % type->byte_size == 0) {
910         for (size_t i = 0; i < (size_t)(area_size / type->byte_size); i++) {
911           res =
912               compare_heap_area_with_type(state, process_index,
913                                           (char *) real_area1 + i * type->byte_size,
914                                           (char *) real_area2 + i * type->byte_size,
915                                           snapshot1, snapshot2, previous, type, -1,
916                                           check_ignore, 0);
917           if (res == 1)
918             return res;
919         }
920       } else
921         return -1;
922     } else {
923       for(simgrid::mc::Member& member : type->members) {
924         // TODO, optimize this? (for the offset case)
925         void *real_member1 = simgrid::dwarf::resolve_member(
926           real_area1, type, &member, (simgrid::mc::AddressSpace*) snapshot1, process_index);
927         void *real_member2 = simgrid::dwarf::resolve_member(
928             real_area2, type, &member, (simgrid::mc::AddressSpace*) snapshot2, process_index);
929         res =
930           compare_heap_area_with_type(state, process_index, real_member1, real_member2,
931                                         snapshot1, snapshot2,
932                                         previous, member.type, -1,
933                                         check_ignore, 0);
934         if (res == 1)
935           return res;
936       }
937     }
938     break;
939   case DW_TAG_union_type:
940     return compare_heap_area_without_type(state, process_index, real_area1, real_area2,
941                                           snapshot1, snapshot2, previous,
942                                           type->byte_size, check_ignore);
943     break;
944   default:
945     break;
946   }
947
948   return 0;
949
950 }
951
952 /** Infer the type of a part of the block from the type of the block
953  *
954  * TODO, handle DW_TAG_array_type as well as arrays of the object ((*p)[5], p[5])
955  *
956  * TODO, handle subfields ((*p).bar.foo, (*p)[5].bar…)
957  *
958  * @param  type_id            DWARF type ID of the root address
959  * @param  area_size
960  * @return                    DWARF type ID for given offset
961  */
962 static simgrid::mc::Type* get_offset_type(void *real_base_address, simgrid::mc::Type* type,
963                                  int offset, int area_size,
964                                  simgrid::mc::Snapshot* snapshot, int process_index)
965 {
966
967   // Beginning of the block, the infered variable type if the type of the block:
968   if (offset == 0)
969     return type;
970
971   switch (type->type) {
972   case DW_TAG_structure_type:
973   case DW_TAG_class_type:
974     if (type->full_type)
975       type = type->full_type;
976
977     if (area_size != -1 && type->byte_size != area_size) {
978       if (area_size > type->byte_size && area_size % type->byte_size == 0)
979         return type;
980       else
981         return nullptr;
982     } else {
983       for(simgrid::mc::Member& member : type->members) {
984
985         if (member.has_offset_location()) {
986           // We have the offset, use it directly (shortcut):
987           if (member.offset() == offset)
988             return member.type;
989         } else {
990           void *real_member = simgrid::dwarf::resolve_member(
991             real_base_address, type, &member, snapshot, process_index);
992           if ((char*) real_member - (char *) real_base_address == offset)
993             return member.type;
994         }
995
996       }
997       return nullptr;
998     }
999     break;
1000   default:
1001     /* FIXME : other cases ? */
1002     return nullptr;
1003     break;
1004   }
1005 }
1006
1007 /**
1008  *
1009  * @param area1          Process address for state 1
1010  * @param area2          Process address for state 2
1011  * @param snapshot1      Snapshot of state 1
1012  * @param snapshot2      Snapshot of state 2
1013  * @param previous       Pairs of blocks already compared on the current path (or nullptr)
1014  * @param type_id        Type of variable
1015  * @param pointer_level
1016  * @return 0 (same), 1 (different), -1
1017  */
1018 int compare_heap_area(int process_index, const void *area1, const void *area2, simgrid::mc::Snapshot* snapshot1,
1019                       simgrid::mc::Snapshot* snapshot2, xbt_dynar_t previous,
1020                       simgrid::mc::Type* type, int pointer_level)
1021 {
1022   simgrid::mc::Process* process = &mc_model_checker->process();
1023
1024   simgrid::mc::StateComparator *state = mc_diff_info.get();
1025
1026   int res_compare;
1027   ssize_t block1, frag1, block2, frag2;
1028   ssize_t size;
1029   int check_ignore = 0;
1030
1031   void *real_addr_block1, *real_addr_block2, *real_addr_frag1, *real_addr_frag2;
1032   int type_size = -1;
1033   int offset1 = 0, offset2 = 0;
1034   int new_size1 = -1, new_size2 = -1;
1035   simgrid::mc::Type *new_type1 = nullptr, *new_type2 = nullptr;
1036
1037   int match_pairs = 0;
1038
1039   // This is the address of std_heap->heapinfo in the application process:
1040   void* heapinfo_address = &((xbt_mheap_t) process->heap_address)->heapinfo;
1041
1042   const malloc_info* heapinfos1 = snapshot1->read(
1043     remote((const malloc_info**)heapinfo_address), process_index);
1044   const malloc_info* heapinfos2 = snapshot2->read(
1045     remote((const malloc_info**)heapinfo_address), process_index);
1046
1047   malloc_info heapinfo_temp1, heapinfo_temp2;
1048
1049   if (previous == nullptr) {
1050     previous =
1051         xbt_dynar_new(sizeof(heap_area_pair_t), heap_area_pair_free_voidp);
1052     match_pairs = 1;
1053   }
1054   // Get block number:
1055   block1 =
1056       ((char *) area1 -
1057        (char *) state->std_heap_copy.heapbase) / BLOCKSIZE + 1;
1058   block2 =
1059       ((char *) area2 -
1060        (char *) state->std_heap_copy.heapbase) / BLOCKSIZE + 1;
1061
1062   // If either block is a stack block:
1063   if (is_block_stack((int) block1) && is_block_stack((int) block2)) {
1064     add_heap_area_pair(previous, block1, -1, block2, -1);
1065     if (match_pairs) {
1066       match_equals(state, previous);
1067       xbt_dynar_free(&previous);
1068     }
1069     return 0;
1070   }
1071   // If either block is not in the expected area of memory:
1072   if (((char *) area1 < (char *) state->std_heap_copy.heapbase)
1073       || (block1 > (ssize_t) state->processStates[0].heapsize) || (block1 < 1)
1074       || ((char *) area2 < (char *) state->std_heap_copy.heapbase)
1075       || (block2 > (ssize_t) state->processStates[1].heapsize) || (block2 < 1)) {
1076     if (match_pairs)
1077       xbt_dynar_free(&previous);
1078     return 1;
1079   }
1080
1081   // Process address of the block:
1082   real_addr_block1 = (ADDR2UINT(block1) - 1) * BLOCKSIZE +
1083                  (char *) state->std_heap_copy.heapbase;
1084   real_addr_block2 = (ADDR2UINT(block2) - 1) * BLOCKSIZE +
1085                  (char *) state->std_heap_copy.heapbase;
1086
1087   if (type) {
1088
1089     if (type->full_type)
1090       type = type->full_type;
1091
1092     // This assume that for "boring" types (volatile ...) byte_size is absent:
1093     while (type->byte_size == 0 && type->subtype != nullptr)
1094       type = type->subtype;
1095
1096     // Find type_size:
1097     if ((type->type == DW_TAG_pointer_type)
1098         || ((type->type == DW_TAG_base_type) && !type->name.empty()
1099             && type->name == "char"))
1100       type_size = -1;
1101     else
1102       type_size = type->byte_size;
1103
1104   }
1105
1106   mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
1107   mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
1108
1109   const malloc_info* heapinfo1 = (const malloc_info*) MC_region_read(
1110     heap_region1, &heapinfo_temp1, &heapinfos1[block1], sizeof(malloc_info));
1111   const malloc_info* heapinfo2 = (const malloc_info*) MC_region_read(
1112     heap_region2, &heapinfo_temp2, &heapinfos2[block2], sizeof(malloc_info));
1113
1114   if ((heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type==MMALLOC_TYPE_HEAPINFO)
1115     && (heapinfo2->type == MMALLOC_TYPE_FREE || heapinfo2->type ==MMALLOC_TYPE_HEAPINFO)) {
1116
1117     /* Free block */
1118     if (match_pairs) {
1119       match_equals(state, previous);
1120       xbt_dynar_free(&previous);
1121     }
1122     return 0;
1123
1124   } else if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED
1125     && heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED) {
1126     /* Complete block */
1127
1128     // TODO, lookup variable type from block type as done for fragmented blocks
1129
1130     offset1 = (char *) area1 - (char *) real_addr_block1;
1131     offset2 = (char *) area2 - (char *) real_addr_block2;
1132
1133     if (state->equals_to1_(block1, 0).valid
1134         && state->equals_to2_(block2, 0).valid) {
1135       if (equal_blocks(state, block1, block2)) {
1136         if (match_pairs) {
1137           match_equals(state, previous);
1138           xbt_dynar_free(&previous);
1139         }
1140         return 0;
1141       }
1142     }
1143
1144     if (type_size != -1) {
1145       if (type_size != (ssize_t) heapinfo1->busy_block.busy_size
1146           && type_size != (ssize_t)   heapinfo2->busy_block.busy_size
1147           && (type->name.empty() || type->name == "struct s_smx_context")) {
1148         if (match_pairs) {
1149           match_equals(state, previous);
1150           xbt_dynar_free(&previous);
1151         }
1152         return -1;
1153       }
1154     }
1155
1156     if (heapinfo1->busy_block.size !=
1157         heapinfo2->busy_block.size) {
1158       if (match_pairs)
1159         xbt_dynar_free(&previous);
1160       return 1;
1161     }
1162
1163     if (heapinfo1->busy_block.busy_size !=
1164         heapinfo2->busy_block.busy_size) {
1165       if (match_pairs)
1166         xbt_dynar_free(&previous);
1167       return 1;
1168     }
1169
1170     if (!add_heap_area_pair(previous, block1, -1, block2, -1)) {
1171       if (match_pairs) {
1172         match_equals(state, previous);
1173         xbt_dynar_free(&previous);
1174       }
1175       return 0;
1176     }
1177
1178     size = heapinfo1->busy_block.busy_size;
1179
1180     // Remember (basic) type inference.
1181     // The current data structure only allows us to do this for the whole block.
1182     if (type != nullptr && area1 == real_addr_block1)
1183       state->types1_(block1, 0) = type;
1184     if (type != nullptr && area2 == real_addr_block2)
1185       state->types2_(block2, 0) = type;
1186
1187     if (size <= 0) {
1188       if (match_pairs) {
1189         match_equals(state, previous);
1190         xbt_dynar_free(&previous);
1191       }
1192       return 0;
1193     }
1194
1195     frag1 = -1;
1196     frag2 = -1;
1197
1198     if ((heapinfo1->busy_block.ignore > 0)
1199         && (heapinfo2->busy_block.ignore ==
1200             heapinfo1->busy_block.ignore))
1201       check_ignore = heapinfo1->busy_block.ignore;
1202
1203   } else if ((heapinfo1->type > 0) && (heapinfo2->type > 0)) {      /* Fragmented block */
1204
1205     // Fragment number:
1206     frag1 =
1207         ((uintptr_t) (ADDR2UINT(area1) % (BLOCKSIZE))) >> heapinfo1->type;
1208     frag2 =
1209         ((uintptr_t) (ADDR2UINT(area2) % (BLOCKSIZE))) >> heapinfo2->type;
1210
1211     // Process address of the fragment:
1212     real_addr_frag1 =
1213         (void *) ((char *) real_addr_block1 +
1214                   (frag1 << heapinfo1->type));
1215     real_addr_frag2 =
1216         (void *) ((char *) real_addr_block2 +
1217                   (frag2 << heapinfo2->type));
1218
1219     // Check the size of the fragments against the size of the type:
1220     if (type_size != -1) {
1221       if (heapinfo1->busy_frag.frag_size[frag1] == -1
1222           || heapinfo2->busy_frag.frag_size[frag2] == -1) {
1223         if (match_pairs) {
1224           match_equals(state, previous);
1225           xbt_dynar_free(&previous);
1226         }
1227         return -1;
1228       }
1229       // ?
1230       if (type_size != heapinfo1->busy_frag.frag_size[frag1]
1231           || type_size != heapinfo2->busy_frag.frag_size[frag2]) {
1232         if (match_pairs) {
1233           match_equals(state, previous);
1234           xbt_dynar_free(&previous);
1235         }
1236         return -1;
1237       }
1238     }
1239
1240     // Check if the blocks are already matched together:
1241     if (state->equals_to1_(block1, frag1).valid
1242         && state->equals_to2_(block2, frag2).valid) {
1243       if (offset1==offset2 && equal_fragments(state, block1, frag1, block2, frag2)) {
1244         if (match_pairs) {
1245           match_equals(state, previous);
1246           xbt_dynar_free(&previous);
1247         }
1248         return 0;
1249       }
1250     }
1251     // Compare the size of both fragments:
1252     if (heapinfo1->busy_frag.frag_size[frag1] !=
1253         heapinfo2->busy_frag.frag_size[frag2]) {
1254       if (type_size == -1) {
1255         if (match_pairs) {
1256           match_equals(state, previous);
1257           xbt_dynar_free(&previous);
1258         }
1259         return -1;
1260       } else {
1261         if (match_pairs)
1262           xbt_dynar_free(&previous);
1263         return 1;
1264       }
1265     }
1266
1267     // Size of the fragment:
1268     size = heapinfo1->busy_frag.frag_size[frag1];
1269
1270     // Remember (basic) type inference.
1271     // The current data structure only allows us to do this for the whole fragment.
1272     if (type != nullptr && area1 == real_addr_frag1)
1273       state->types1_(block1, frag1) = type;
1274     if (type != nullptr && area2 == real_addr_frag2)
1275       state->types2_(block2, frag2) = type;
1276
1277     // The type of the variable is already known:
1278     if (type) {
1279       new_type1 = type;
1280       new_type2 = type;
1281     }
1282     // Type inference from the block type.
1283     else if (state->types1_(block1, frag1) != nullptr
1284              || state->types2_(block2, frag2) != nullptr) {
1285
1286       offset1 = (char *) area1 - (char *) real_addr_frag1;
1287       offset2 = (char *) area2 - (char *) real_addr_frag2;
1288
1289       if (state->types1_(block1, frag1) != nullptr
1290           && state->types2_(block2, frag2) != nullptr) {
1291         new_type1 =
1292             get_offset_type(real_addr_frag1, state->types1_(block1, frag1),
1293                             offset1, size, snapshot1, process_index);
1294         new_type2 =
1295             get_offset_type(real_addr_frag2, state->types2_(block2, frag2),
1296                             offset1, size, snapshot2, process_index);
1297       } else if (state->types1_(block1, frag1) != nullptr) {
1298         new_type1 =
1299             get_offset_type(real_addr_frag1, state->types1_(block1, frag1),
1300                             offset1, size, snapshot1, process_index);
1301         new_type2 =
1302             get_offset_type(real_addr_frag2, state->types1_(block1, frag1),
1303                             offset2, size, snapshot2, process_index);
1304       } else if (state->types2_(block2, frag2) != nullptr) {
1305         new_type1 =
1306             get_offset_type(real_addr_frag1, state->types2_(block2, frag2),
1307                             offset1, size, snapshot1, process_index);
1308         new_type2 =
1309             get_offset_type(real_addr_frag2, state->types2_(block2, frag2),
1310                             offset2, size, snapshot2, process_index);
1311       } else {
1312         if (match_pairs) {
1313           match_equals(state, previous);
1314           xbt_dynar_free(&previous);
1315         }
1316         return -1;
1317       }
1318
1319       if (new_type1 != nullptr && new_type2 != nullptr && new_type1 != new_type2) {
1320
1321         type = new_type1;
1322         while (type->byte_size == 0 && type->subtype != nullptr)
1323           type = type->subtype;
1324         new_size1 = type->byte_size;
1325
1326         type = new_type2;
1327         while (type->byte_size == 0 && type->subtype != nullptr)
1328           type = type->subtype;
1329         new_size2 = type->byte_size;
1330
1331       } else {
1332         if (match_pairs) {
1333           match_equals(state, previous);
1334           xbt_dynar_free(&previous);
1335         }
1336         return -1;
1337       }
1338     }
1339
1340     if (new_size1 > 0 && new_size1 == new_size2) {
1341       type = new_type1;
1342       size = new_size1;
1343     }
1344
1345     if (offset1 == 0 && offset2 == 0
1346       && !add_heap_area_pair(previous, block1, frag1, block2, frag2)) {
1347         if (match_pairs) {
1348           match_equals(state, previous);
1349           xbt_dynar_free(&previous);
1350         }
1351         return 0;
1352       }
1353
1354     if (size <= 0) {
1355       if (match_pairs) {
1356         match_equals(state, previous);
1357         xbt_dynar_free(&previous);
1358       }
1359       return 0;
1360     }
1361
1362     if ((heapinfo1->busy_frag.ignore[frag1] > 0)
1363         && (heapinfo2->busy_frag.ignore[frag2] ==
1364             heapinfo1->busy_frag.ignore[frag1]))
1365       check_ignore = heapinfo1->busy_frag.ignore[frag1];
1366
1367   } else {
1368
1369     if (match_pairs)
1370       xbt_dynar_free(&previous);
1371     return 1;
1372
1373   }
1374
1375
1376   /* Start comparison */
1377   if (type)
1378     res_compare =
1379         compare_heap_area_with_type(state, process_index, area1, area2, snapshot1, snapshot2,
1380                                     previous, type, size, check_ignore,
1381                                     pointer_level);
1382   else
1383     res_compare =
1384         compare_heap_area_without_type(state, process_index, area1, area2, snapshot1, snapshot2,
1385                                        previous, size, check_ignore);
1386
1387   if (res_compare == 1) {
1388     if (match_pairs)
1389       xbt_dynar_free(&previous);
1390     return res_compare;
1391   }
1392
1393   if (match_pairs) {
1394     match_equals(state, previous);
1395     xbt_dynar_free(&previous);
1396   }
1397
1398   return 0;
1399 }
1400
1401 }
1402 }