/* 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; } }
/* 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; } }
void VG_(show_all_errors) ( void ) { Int i, n_min; Int n_err_contexts, n_supp_contexts; Error *p, *p_min; Supp *su; Bool any_supp; if (VG_(clo_verbosity) == 0) return; n_err_contexts = 0; for (p = vg_errors; p != NULL; p = p->next) { if (p->supp == NULL) n_err_contexts++; } n_supp_contexts = 0; for (su = vg_suppressions; su != NULL; su = su->next) { if (su->count > 0) n_supp_contexts++; } VG_(message)(Vg_UserMsg, "ERROR SUMMARY: " "%d errors from %d contexts (suppressed: %d from %d)", n_errs_found, n_err_contexts, n_errs_suppressed, n_supp_contexts ); if (VG_(clo_verbosity) <= 1) return; /* Print the contexts in order of increasing error count. */ for (i = 0; i < n_err_contexts; i++) { n_min = (1 << 30) - 1; p_min = NULL; for (p = vg_errors; p != NULL; p = p->next) { if (p->supp != NULL) continue; if (p->count < n_min) { n_min = p->count; p_min = p; } } if (p_min == NULL) VG_(skin_panic)("show_all_errors()"); VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:", p_min->count, i+1, n_err_contexts); pp_Error( p_min, False ); if ((i+1 == VG_(clo_dump_error))) { VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, p_min->where->eips[0], /*debugging*/True); } p_min->count = 1 << 30; } if (n_supp_contexts > 0) VG_(message)(Vg_DebugMsg, ""); any_supp = False; for (su = vg_suppressions; su != NULL; su = su->next) { if (su->count > 0) { any_supp = True; VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname); } } if (n_err_contexts > 0) { if (any_supp) VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "IN SUMMARY: " "%d errors from %d contexts (suppressed: %d from %d)", n_errs_found, n_err_contexts, n_errs_suppressed, n_supp_contexts ); VG_(message)(Vg_UserMsg, ""); } }
/* 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++; } }
/* Show all the errors that occurred, and possibly also the suppressions used. */ void VG_(show_all_errors) ( void ) { Int i, n_min; Int n_err_contexts, n_supp_contexts; Error *p, *p_min; Supp *su; Bool any_supp; if (VG_(clo_verbosity) == 0) return; n_err_contexts = 0; for (p = errors; p != NULL; p = p->next) { if (p->supp == NULL) n_err_contexts++; } n_supp_contexts = 0; for (su = suppressions; su != NULL; su = su->next) { if (su->count > 0) n_supp_contexts++; } /* If we're printing XML, just show the suppressions and stop. */ if (VG_(clo_xml)) { (void)show_used_suppressions(); return; } /* We only get here if not printing XML. */ VG_(message)(Vg_UserMsg, "ERROR SUMMARY: " "%d errors from %d contexts (suppressed: %d from %d)", n_errs_found, n_err_contexts, n_errs_suppressed, n_supp_contexts ); if (VG_(clo_verbosity) <= 1) return; /* Print the contexts in order of increasing error count. */ for (i = 0; i < n_err_contexts; i++) { n_min = (1 << 30) - 1; p_min = NULL; for (p = errors; p != NULL; p = p->next) { if (p->supp != NULL) continue; if (p->count < n_min) { n_min = p->count; p_min = p; } } if (p_min == NULL) VG_(tool_panic)("show_all_errors()"); VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:", p_min->count, i+1, n_err_contexts); pp_Error( p_min ); if ((i+1 == VG_(clo_dump_error))) { StackTrace ips = VG_(extract_StackTrace)(p_min->where); VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, ips[0], /*debugging*/True, 0xFE/*verbosity*/, /*bbs_done*/0, /*allow redir?*/True); } p_min->count = 1 << 30; } if (n_supp_contexts > 0) VG_(message)(Vg_DebugMsg, ""); any_supp = show_used_suppressions(); if (n_err_contexts > 0) { if (any_supp) VG_(message)(Vg_UserMsg, ""); VG_(message)(Vg_UserMsg, "IN SUMMARY: " "%d errors from %d contexts (suppressed: %d from %d)", n_errs_found, n_err_contexts, n_errs_suppressed, n_supp_contexts ); VG_(message)(Vg_UserMsg, ""); } }