예제 #1
0
/* Top level entry point to leak detector.  Call here, passing in
   suitable address-validating functions (see comment at top of
   scan_all_valid_memory above).  These functions used to encapsulate the
   differences between Memcheck and Addrcheck;  they no longer do but it
   doesn't hurt to keep them here.
*/
void MC_(do_detect_memory_leaks) (
   ThreadId tid, LeakCheckMode mode,
   Bool (*is_within_valid_secondary) ( Addr ),
   Bool (*is_valid_aligned_word)     ( Addr )
)
{
   Int i;
   
   tl_assert(mode != LC_Off);

   lc_shadows = find_active_shadows(&lc_n_shadows);

   /* Sort the array. */
   VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);

   /* Sanity check; assert that the blocks are now in order */
   for (i = 0; i < lc_n_shadows-1; i++) {
      tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
   }

   /* Sanity check -- make sure they don't overlap.  But do allow
      exact duplicates.  If this assertion fails, it may mean that the
      application has done something stupid with
      VALGRIND_MALLOCLIKE_BLOCK client requests, specifically, has
      made overlapping requests (which are nonsensical).  Another way
      to screw up is to use VALGRIND_MALLOCLIKE_BLOCK for stack
      locations; again nonsensical. */
   for (i = 0; i < lc_n_shadows-1; i++) {
      Bool nonsense_overlap = ! (
            /* normal case - no overlap */
            (lc_shadows[i]->data + lc_shadows[i]->szB <= lc_shadows[i+1]->data)
         ||
            /* degenerate case: exact duplicates */
              (lc_shadows[i]->data == lc_shadows[i+1]->data
            && lc_shadows[i]->szB == lc_shadows[i+1]->szB)
         );
      if (nonsense_overlap) {
         VG_(message)(Vg_UserMsg, "Block [0x%lx, 0x%lx) overlaps with block [0x%lx, 0x%lx)",
                      lc_shadows[   i]->data, (lc_shadows[   i]->data + lc_shadows[   i]->szB),
                      lc_shadows[1+ i]->data, (lc_shadows[1+ i]->data + lc_shadows[1+ i]->szB) );
      }
      tl_assert (!nonsense_overlap);
   }

   if (lc_n_shadows == 0) {
      tl_assert(lc_shadows == NULL);
      if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
         VG_(message)(Vg_UserMsg, 
                      "All heap blocks were freed -- no leaks are possible.");
      }
      return;
   }

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
      VG_(message)(Vg_UserMsg, 
                   "searching for pointers to %'d not-freed blocks.",
                   lc_n_shadows );

   lc_min_mallocd_addr = lc_shadows[0]->data;
   lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
                         + lc_shadows[lc_n_shadows-1]->szB;

   lc_markstack = VG_(malloc)( "mc.ddml.1",
                               lc_n_shadows * sizeof(*lc_markstack) );
   for (i = 0; i < lc_n_shadows; i++) {
      lc_markstack[i].next = -1;
      lc_markstack[i].state = Unreached;
      lc_markstack[i].indirect = 0;
   }
   lc_markstack_top = -1;

   lc_is_within_valid_secondary = is_within_valid_secondary;
   lc_is_valid_aligned_word     = is_valid_aligned_word;

   lc_scanned = 0;

   /* Push roots onto the mark stack.  Roots are:
      - the integer registers of all threads
      - all mappings belonging to the client, including stacks
      - .. but excluding any client heap segments.
      Client heap segments are excluded because we wish to differentiate
      client heap blocks which are referenced only from inside the heap
      from those outside.  This facilitates the indirect vs direct loss
      categorisation, which [if the users ever manage to understand it]
      is really useful for detecting lost cycles.
   */
   { Addr*     seg_starts;
     Int       n_seg_starts;
     seg_starts = get_seg_starts( &n_seg_starts );
     tl_assert(seg_starts && n_seg_starts > 0);
     /* VG_(am_show_nsegments)( 0,"leakcheck"); */
     for (i = 0; i < n_seg_starts; i++) {
        NSegment const* seg = VG_(am_find_nsegment)( seg_starts[i] );
        tl_assert(seg);
        if (seg->kind != SkFileC && seg->kind != SkAnonC) 
           continue;
        if (!(seg->hasR && seg->hasW))
           continue;
        if (seg->isCH)
           continue;

        /* Don't poke around in device segments as this may cause
           hangs.  Exclude /dev/zero just in case someone allocated
           memory by explicitly mapping /dev/zero. */
        if (seg->kind == SkFileC 
            && (VKI_S_ISCHR(seg->mode) || VKI_S_ISBLK(seg->mode))) {
           HChar* dev_name = VG_(am_get_filename)( (NSegment*)seg );
           if (dev_name && 0 == VG_(strcmp)(dev_name, "/dev/zero")) {
              /* don't skip /dev/zero */
           } else {
              /* skip this device mapping */
              continue;
           }
        }

        if (0)
           VG_(printf)("ACCEPT %2d  %#lx %#lx\n", i, seg->start, seg->end);
        lc_scan_memory(seg->start, seg->end+1 - seg->start);
     }
   }

   /* Push registers onto mark stack */
   VG_(apply_to_GP_regs)(lc_markstack_push);

   /* Keep walking the heap until everything is found */
   lc_do_leakcheck(-1);

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
      VG_(message)(Vg_UserMsg, "checked %'lu bytes.", lc_scanned);

   blocks_leaked     = MC_(bytes_leaked)     = 0;
   blocks_indirect   = MC_(bytes_indirect)   = 0;
   blocks_dubious    = MC_(bytes_dubious)    = 0;
   blocks_reachable  = MC_(bytes_reachable)  = 0;
   blocks_suppressed = MC_(bytes_suppressed) = 0;

   if (mode == LC_Full)
      full_report(tid);
   else
      make_summary();

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
      VG_(message)(Vg_UserMsg, "");
      VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
      VG_(message)(Vg_UserMsg, "   definitely lost: %'lu bytes in %'lu blocks.",
                               MC_(bytes_leaked), blocks_leaked );
      if (blocks_indirect > 0)
	 VG_(message)(Vg_UserMsg, "   indirectly lost: %'lu bytes in %'lu blocks.",
		      MC_(bytes_indirect), blocks_indirect );
      VG_(message)(Vg_UserMsg, "     possibly lost: %'lu bytes in %'lu blocks.",
                               MC_(bytes_dubious), blocks_dubious );
      VG_(message)(Vg_UserMsg, "   still reachable: %'lu bytes in %'lu blocks.",
                               MC_(bytes_reachable), blocks_reachable );
      VG_(message)(Vg_UserMsg, "        suppressed: %'lu bytes in %'lu blocks.",
                               MC_(bytes_suppressed), blocks_suppressed );
      if (mode == LC_Summary 
          && (blocks_leaked + blocks_indirect 
              + blocks_dubious + blocks_reachable) > 0) {
         VG_(message)(Vg_UserMsg,
                      "Rerun with --leak-check=full to see details of leaked memory.");
      }
      if (blocks_reachable > 0 && !MC_(clo_show_reachable) && mode == LC_Full) {
         VG_(message)(Vg_UserMsg, 
           "Reachable blocks (those to which a pointer was found) are not shown.");
         VG_(message)(Vg_UserMsg, 
            "To see them, rerun with: --leak-check=full --show-reachable=yes");
      }
   }

   VG_(free) ( lc_shadows );
   VG_(free) ( lc_markstack );
}
예제 #2
0
/* Top level entry point to leak detector.  Call here, passing in
   suitable address-validating functions (see comment at top of
   scan_all_valid_memory above).  All this is to avoid duplication
   of the leak-detection code for Memcheck and Addrcheck.
   Also pass in a tool-specific function to extract the .where field
   for allocated blocks, an indication of the resolution wanted for
   distinguishing different allocation points, and whether or not
   reachable blocks should be shown.
*/
void MAC_(do_detect_memory_leaks) (
   ThreadId tid, LeakCheckMode mode,
   Bool (*is_within_valid_secondary) ( Addr ),
   Bool (*is_valid_aligned_word)     ( Addr )
)
{
   Int i;
   
   tl_assert(mode != LC_Off);

   /* VG_(HT_to_array) allocates storage for shadows */
   lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
                                               &lc_n_shadows );

   /* Sort the array. */
   VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);

   /* Sanity check; assert that the blocks are now in order */
   for (i = 0; i < lc_n_shadows-1; i++) {
      tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
   }

   /* Sanity check -- make sure they don't overlap */
   for (i = 0; i < lc_n_shadows-1; i++) {
      tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
                 < lc_shadows[i+1]->data );
   }

   if (lc_n_shadows == 0) {
      tl_assert(lc_shadows == NULL);
      if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
         VG_(message)(Vg_UserMsg, 
                      "No malloc'd blocks -- no leaks are possible.");
      }
      return;
   }

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
      VG_(message)(Vg_UserMsg, 
                   "searching for pointers to %d not-freed blocks.", 
                   lc_n_shadows );

   lc_min_mallocd_addr = lc_shadows[0]->data;
   lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
                         + lc_shadows[lc_n_shadows-1]->size;

   lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
   for (i = 0; i < lc_n_shadows; i++) {
      lc_markstack[i].next = -1;
      lc_markstack[i].state = Unreached;
      lc_markstack[i].indirect = 0;
   }
   lc_markstack_top = -1;

   lc_is_within_valid_secondary = is_within_valid_secondary;
   lc_is_valid_aligned_word     = is_valid_aligned_word;

   lc_scanned = 0;

   /* Push roots onto the mark stack.  Roots are:
      - the integer registers of all threads
      - all mappings belonging to the client, including stacks
      - .. but excluding any client heap segments.
      Client heap segments are excluded because we wish to differentiate
      client heap blocks which are referenced only from inside the heap
      from those outside.  This facilitates the indirect vs direct loss
      categorisation, which [if the users ever manage to understand it]
      is really useful for detecting lost cycles.
   */
   { NSegment* seg;
     Addr*     seg_starts;
     Int       n_seg_starts;
     seg_starts = get_seg_starts( &n_seg_starts );
     tl_assert(seg_starts && n_seg_starts > 0);
     /* VG_(am_show_nsegments)( 0,"leakcheck"); */
     for (i = 0; i < n_seg_starts; i++) {
        seg = VG_(am_find_nsegment)( seg_starts[i] );
        tl_assert(seg);
        if (seg->kind != SkFileC && seg->kind != SkAnonC) 
           continue;
        if (!(seg->hasR && seg->hasW))
           continue;
        if (seg->isCH)
           continue;
        if (0)
           VG_(printf)("ACCEPT %2d  %p %p\n", i, seg->start, seg->end);
        lc_scan_memory(seg->start, seg->end+1 - seg->start);
     }
   }

   /* Push registers onto mark stack */
   VG_(apply_to_GP_regs)(lc_markstack_push);

   /* Keep walking the heap until everything is found */
   lc_do_leakcheck(-1);

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
      VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);

   blocks_leaked     = MAC_(bytes_leaked)     = 0;
   blocks_indirect   = MAC_(bytes_indirect)   = 0;
   blocks_dubious    = MAC_(bytes_dubious)    = 0;
   blocks_reachable  = MAC_(bytes_reachable)  = 0;
   blocks_suppressed = MAC_(bytes_suppressed) = 0;

   if (mode == LC_Full)
      full_report(tid);
   else
      make_summary();

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
      VG_(message)(Vg_UserMsg, "");
      VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
      VG_(message)(Vg_UserMsg, "   definitely lost: %d bytes in %d blocks.", 
                               MAC_(bytes_leaked), blocks_leaked );
      if (blocks_indirect > 0)
	 VG_(message)(Vg_UserMsg, "   indirectly lost: %d bytes in %d blocks.", 
		      MAC_(bytes_indirect), blocks_indirect );
      VG_(message)(Vg_UserMsg, "     possibly lost: %d bytes in %d blocks.", 
                               MAC_(bytes_dubious), blocks_dubious );
      VG_(message)(Vg_UserMsg, "   still reachable: %d bytes in %d blocks.", 
                               MAC_(bytes_reachable), blocks_reachable );
      VG_(message)(Vg_UserMsg, "        suppressed: %d bytes in %d blocks.", 
                               MAC_(bytes_suppressed), blocks_suppressed );
      if (mode == LC_Summary && blocks_leaked > 0)
	 VG_(message)(Vg_UserMsg,
		      "Use --leak-check=full to see details of leaked memory.");
      else if (!MAC_(clo_show_reachable)) {
         VG_(message)(Vg_UserMsg, 
           "Reachable blocks (those to which a pointer was found) are not shown.");
         VG_(message)(Vg_UserMsg, 
            "To see them, rerun with: --show-reachable=yes");
      }
   }

   VG_(free) ( lc_shadows );
   VG_(free) ( lc_markstack );
}
예제 #3
0
/* Event handler for tool 'error-support' */
ATerm error_support_handler(int conn, ATerm term)
{
  ATerm in, out;
  /* We need some temporary variables during matching */
  char *s0, *s1;
  ATerm t0;

  if(ATmatch(term, "rec-eval(make-error(<str>,<term>))", &s0, &t0)) {
    return make_error(conn, s0, t0);
  }
  if(ATmatch(term, "rec-eval(get-area-end-line(<term>))", &t0)) {
    return get_area_end_line(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-location-filename(<term>))", &t0)) {
    return get_location_filename(conn, t0);
  }
  if(ATmatch(term, "rec-eval(has-location-area(<term>))", &t0)) {
    return has_location_area(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-summary-id(<term>))", &t0)) {
    return get_summary_id(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-error-description(<term>))", &t0)) {
    return get_error_description(conn, t0);
  }
  if(ATmatch(term, "rec-do(display-summary(<term>))", &t0)) {
    display_summary(conn, t0);
    return NULL;
  }
  if(ATmatch(term, "rec-eval(lower-summary(<term>))", &t0)) {
    return lower_summary(conn, t0);
  }
  if(ATmatch(term, "rec-eval(make-localized-subject(<str>,<term>))", &s0, &t0)) {
    return make_localized_subject(conn, s0, t0);
  }
  if(ATmatch(term, "rec-eval(get-summary-producer(<term>))", &t0)) {
    return get_summary_producer(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-error-subjects(<term>))", &t0)) {
    return get_error_subjects(conn, t0);
  }
  if(ATmatch(term, "rec-eval(make-subject(<str>))", &s0)) {
    return make_subject(conn, s0);
  }
  if(ATmatch(term, "rec-eval(get-subject-location(<term>))", &t0)) {
    return get_subject_location(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-area-offset(<term>))", &t0)) {
    return get_area_offset(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-area-begin-line(<term>))", &t0)) {
    return get_area_begin_line(conn, t0);
  }
  if(ATmatch(term, "rec-eval(add-filename-in-error(<str>,<term>))", &s0, &t0)) {
    return add_filename_in_error(conn, s0, t0);
  }
  if(ATmatch(term, "rec-eval(get-location-area(<term>))", &t0)) {
    return get_location_area(conn, t0);
  }
  if(ATmatch(term, "rec-eval(set-summary-id(<term>,<str>))", &t0, &s0)) {
    return set_summary_id(conn, t0, s0);
  }
  if(ATmatch(term, "rec-eval(has-subject-location(<term>))", &t0)) {
    return has_subject_location(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-area-end-column(<term>))", &t0)) {
    return get_area_end_column(conn, t0);
  }
  if(ATmatch(term, "rec-eval(make-summary(<str>,<str>,<term>))", &s0, &s1, &t0)) {
    return make_summary(conn, s0, s1, t0);
  }
  if(ATmatch(term, "rec-eval(get-summary-errors(<term>))", &t0)) {
    return get_summary_errors(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-subject-description(<term>))", &t0)) {
    return get_subject_description(conn, t0);
  }
  if(ATmatch(term, "rec-eval(get-area-length(<term>))", &t0)) {
    return get_area_length(conn, t0);
  }
  if(ATmatch(term, "rec-terminate(<term>)", &t0)) {
    rec_terminate(conn, t0);
    return NULL;
  }
  if(ATmatch(term, "rec-eval(get-area-begin-column(<term>))", &t0)) {
    return get_area_begin_column(conn, t0);
  }
  if(ATmatch(term, "rec-do(signature(<term>,<term>))", &in, &out)) {
    ATerm result = error_support_checker(conn, in);
    if(!ATmatch(result, "[]"))
      ATfprintf(stderr, "warning: not in input signature:\n\t%\n\tl\n", result);
    return NULL;
  }

  ATerror("tool error-support cannot handle term %t", term);
  return NULL; /* Silence the compiler */
}
예제 #4
0
/* Top level entry point to leak detector.  Call here, passing in
   suitable address-validating functions (see comment at top of
   scan_all_valid_memory above).  All this is to avoid duplication
   of the leak-detection code for Memcheck and Addrcheck.
   Also pass in a tool-specific function to extract the .where field
   for allocated blocks, an indication of the resolution wanted for
   distinguishing different allocation points, and whether or not
   reachable blocks should be shown.
*/
void MAC_(do_detect_memory_leaks) (
   ThreadId tid, LeakCheckMode mode,
   Bool (*is_within_valid_secondary) ( Addr ),
   Bool (*is_valid_aligned_word)     ( Addr )
)
{
   Int i;
   
   tl_assert(mode != LC_Off);

   /* VG_(HT_to_array) allocates storage for shadows */
   lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
                                               &lc_n_shadows );

   /* Sort the array. */
   VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);

   /* Sanity check; assert that the blocks are now in order */
   for (i = 0; i < lc_n_shadows-1; i++) {
      tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
   }

   /* Sanity check -- make sure they don't overlap */
   for (i = 0; i < lc_n_shadows-1; i++) {
      tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
                 < lc_shadows[i+1]->data );
   }

   if (lc_n_shadows == 0) {
      tl_assert(lc_shadows == NULL);
      if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
         VG_(message)(Vg_UserMsg, 
                      "No malloc'd blocks -- no leaks are possible.");
      }
      return;
   }

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
      VG_(message)(Vg_UserMsg, 
                   "searching for pointers to %d not-freed blocks.", 
                   lc_n_shadows );

   lc_min_mallocd_addr = lc_shadows[0]->data;
   lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
                         + lc_shadows[lc_n_shadows-1]->size;

   lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
   for (i = 0; i < lc_n_shadows; i++) {
      lc_markstack[i].next = -1;
      lc_markstack[i].state = Unreached;
      lc_markstack[i].indirect = 0;
   }
   lc_markstack_top = -1;

   lc_is_within_valid_secondary = is_within_valid_secondary;
   lc_is_valid_aligned_word     = is_valid_aligned_word;

   lc_scanned = 0;

   /* Do the scan of memory, pushing any pointers onto the mark stack */
   VG_(find_root_memory)(lc_scan_memory);

   /* Push registers onto mark stack */
   VG_(apply_to_GP_regs)(lc_markstack_push);

   /* Keep walking the heap until everything is found */
   lc_do_leakcheck(-1);

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
      VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);

   blocks_leaked     = MAC_(bytes_leaked)     = 0;
   blocks_indirect   = MAC_(bytes_indirect)   = 0;
   blocks_dubious    = MAC_(bytes_dubious)    = 0;
   blocks_reachable  = MAC_(bytes_reachable)  = 0;
   blocks_suppressed = MAC_(bytes_suppressed) = 0;

   if (mode == LC_Full)
      full_report(tid);
   else
      make_summary();

   if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
      VG_(message)(Vg_UserMsg, "");
      VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
      VG_(message)(Vg_UserMsg, "   definitely lost: %d bytes in %d blocks.", 
                               MAC_(bytes_leaked), blocks_leaked );
      if (blocks_indirect > 0)
	 VG_(message)(Vg_UserMsg, "   indirectly lost: %d bytes in %d blocks.", 
		      MAC_(bytes_indirect), blocks_indirect );
      VG_(message)(Vg_UserMsg, "     possibly lost: %d bytes in %d blocks.", 
                               MAC_(bytes_dubious), blocks_dubious );
      VG_(message)(Vg_UserMsg, "   still reachable: %d bytes in %d blocks.", 
                               MAC_(bytes_reachable), blocks_reachable );
      VG_(message)(Vg_UserMsg, "        suppressed: %d bytes in %d blocks.", 
                               MAC_(bytes_suppressed), blocks_suppressed );
      if (mode == LC_Summary && blocks_leaked > 0)
	 VG_(message)(Vg_UserMsg,
		      "Use --leak-check=full to see details of leaked memory.");
      else if (!MAC_(clo_show_reachable)) {
         VG_(message)(Vg_UserMsg, 
           "Reachable blocks (those to which a pointer was found) are not shown.");
         VG_(message)(Vg_UserMsg, 
            "To see them, rerun with: --show-reachable=yes");
      }
   }

   VG_(free) ( lc_shadows );
   VG_(free) ( lc_markstack );
}