Ejemplo n.º 1
0
/* Second top-level entry point to the error management subsystem, for
   errors that the tool wants to report immediately, eg. because they're
   guaranteed to only happen once.  This avoids all the recording and
   comparing stuff.  But they can be suppressed;  returns True if it is
   suppressed.  Bool 'print_error' dictates whether to print the error. 
   Bool 'count_error' dictates whether to count the error in n_errs_found.
*/
Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
                         void* extra, ExeContext* where, Bool print_error,
                         Bool allow_db_attach, Bool count_error )
{
   Error err;
   Supp *su;

   /* Build ourselves the error */
   construct_error ( &err, tid, ekind, a, s, extra, where );

   /* Unless it's suppressed, we're going to show it.  Don't need to make
      a copy, because it's only temporary anyway.

      Then update the 'extra' part with VG_(tdict).tool_update_extra),
      because that can have an affect on whether it's suppressed.  Ignore
      the size return value of VG_(tdict).tool_update_extra, because we're
      not copying 'extra'. */
   (void)VG_TDICT_CALL(tool_update_extra, &err);

   su = is_suppressible_error(&err);
   if (NULL == su) {
      if (count_error)
         n_errs_found++;

      if (print_error) {
         if (!is_first_shown_context)
            VG_(message)(Vg_UserMsg, "");
         pp_Error(&err);
         is_first_shown_context = False;
         n_errs_shown++;
         do_actions_on_error(&err, allow_db_attach);
      }
      return False;

   } else {
      n_errs_suppressed++;
      su->count++;
      return True;
   }
}
Ejemplo n.º 2
0
/* Second top-level entry point to the error management subsystem, for
   errors that the skin want to report immediately, eg. because they're
   guaranteed to only happen once.  This avoids all the recording and
   comparing stuff.  But they can be suppressed;  returns True if it is
   suppressed.  Bool `print_error' dictates whether to print the error. 
   Bool `count_error' dictates whether to count the error in VG_(n_errs_found)
*/
Bool VG_(unique_error) ( ThreadState* tst, ErrorKind ekind, Addr a, Char* s,
                         void* extra, ExeContext* where, Bool print_error,
                         Bool allow_GDB_attach, Bool count_error )
{
   Error  err;
   Addr   m_eip, m_esp, m_ebp;

   /* Build ourselves the error */
   construct_error ( &err, tst, ekind, a, s, extra, where,
                     &m_eip, &m_esp, &m_ebp );

   /* Unless it's suppressed, we're going to show it.  Don't need to make
      a copy, because it's only temporary anyway.

      Then update the `extra' part with SK_(update_extra), because that can
      have an affect on whether it's suppressed.  Ignore the size return
      value of SK_(update_extra), because we're not copying `extra'. */
   (void)SK_(update_extra)(&err);

   if (NULL == is_suppressible_error(&err)) {
      if (count_error)
         VG_(n_errs_found)++;

      if (print_error) {
         if (!is_first_shown_context)
            VG_(message)(Vg_UserMsg, "");
         pp_Error(&err, False);
         is_first_shown_context = False;
      }
      do_actions_on_error(&err, allow_GDB_attach, m_eip, m_esp, m_ebp);

      return False;

   } else {
      vg_n_errs_suppressed++;
      return True;
   }
}
Ejemplo n.º 3
0
/* Top-level entry point to the error management subsystem.
   All detected errors are notified here; this routine decides if/when the
   user should see the error. */
void VG_(maybe_record_error) ( ThreadId tid, 
                               ErrorKind ekind, Addr a, Char* s, void* extra )
{
          Error  err;
          Error* p;
          Error* p_prev;
          UInt   extra_size;
          VgRes  exe_res                = Vg_MedRes;
   static Bool   stopping_message       = False;
   static Bool   slowdown_message       = False;
   static Int    vg_n_errs_shown        = 0;

   /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
      been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
      have been found, just refuse to collect any more.  This stops
      the burden of the error-management system becoming excessive in
      extremely buggy programs, although it does make it pretty
      pointless to continue the Valgrind run after this point. */
   if (VG_(clo_error_limit) 
       && (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
           || n_errs_found >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND)) {
      if (!stopping_message) {
         VG_(message)(Vg_UserMsg, "");

	 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
            VG_(message)(Vg_UserMsg, 
               "More than %d different errors detected.  "
               "I'm not reporting any more.",
               M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
         } else {
            VG_(message)(Vg_UserMsg, 
               "More than %d total errors detected.  "
               "I'm not reporting any more.",
               M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
	 }

         VG_(message)(Vg_UserMsg, 
            "Final error counts will be inaccurate.  Go fix your program!");
         VG_(message)(Vg_UserMsg, 
            "Rerun with --error-limit=no to disable this cutoff.  Note");
         VG_(message)(Vg_UserMsg, 
            "that errors may occur in your program without prior warning from");
         VG_(message)(Vg_UserMsg, 
            "Valgrind, because errors are no longer being displayed.");
         VG_(message)(Vg_UserMsg, "");
         stopping_message = True;
      }
      return;
   }

   /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
      been found, be much more conservative about collecting new
      ones. */
   if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
      exe_res = Vg_LowRes;
      if (!slowdown_message) {
         VG_(message)(Vg_UserMsg, "");
         VG_(message)(Vg_UserMsg, 
            "More than %d errors detected.  Subsequent errors",
            M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
         VG_(message)(Vg_UserMsg, 
            "will still be recorded, but in less detail than before.");
         slowdown_message = True;
      }
   }

   /* Build ourselves the error */
   construct_error ( &err, tid, ekind, a, s, extra, NULL );

   /* First, see if we've got an error record matching this one. */
   p      = vg_errors;
   p_prev = NULL;
   while (p != NULL) {
      if (eq_Error(exe_res, p, &err)) {
         /* Found it. */
         p->count++;
	 if (p->supp != NULL) {
            /* Deal correctly with suppressed errors. */
            p->supp->count++;
            n_errs_suppressed++;	 
         } else {
            n_errs_found++;
         }

         /* Move p to the front of the list so that future searches
            for it are faster. */
         if (p_prev != NULL) {
            vg_assert(p_prev->next == p);
            p_prev->next    = p->next;
            p->next         = vg_errors;
            vg_errors = p;
	 }

         return;
      }
      p_prev = p;
      p      = p->next;
   }

   /* Didn't see it.  Copy and add. */

   /* OK, we're really going to collect it.  The context is on the stack and
      will disappear shortly, so we must copy it.  First do the main
      (non-`extra') part.
     
      Then SK_(update_extra) can update the `extra' part.  This is for when
      there are more details to fill in which take time to work out but
      don't affect our earlier decision to include the error -- by
      postponing those details until now, we avoid the extra work in the
      case where we ignore the error.  Ugly.

      Then, if there is an `extra' part, copy it too, using the size that
      SK_(update_extra) returned.  Also allow for people using the void*
      extra field for a scalar value like an integer.
   */

   /* copy main part */
   p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
   *p = err;

   /* update `extra', for non-core errors (core ones don't use 'extra') */
   if (VG_(needs).skin_errors && PThreadErr != ekind) {
      extra_size = SK_(update_extra)(p);

      /* copy block pointed to by `extra', if there is one */
      if (NULL != p->extra && 0 != extra_size) { 
         void* new_extra = VG_(malloc)(extra_size);
         VG_(memcpy)(new_extra, p->extra, extra_size);
         p->extra = new_extra;
      }
   }

   p->next = vg_errors;
   p->supp = is_suppressible_error(&err);
   vg_errors = p;
   if (p->supp == NULL) {
      n_errs_found++;
      if (!is_first_shown_context)
         VG_(message)(Vg_UserMsg, "");
      pp_Error(p, False);
      is_first_shown_context = False;
      vg_n_errs_shown++;
      do_actions_on_error(p, /*allow_db_attach*/True);
   } else {
      n_errs_suppressed++;
      p->supp->count++;
   }
}