LCOV - code coverage report
Current view: top level - lib/log - util_bug.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 31 65 47.7 %
Date: 2021-11-24 03:28:48 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /* Copyright (c) 2003, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file util_bug.c
       8             :  **/
       9             : 
      10             : #include "orconfig.h"
      11             : #include "lib/log/util_bug.h"
      12             : #include "lib/log/log.h"
      13             : #include "lib/err/backtrace.h"
      14             : #include "lib/err/torerr.h"
      15             : #ifdef TOR_UNIT_TESTS
      16             : #include "lib/smartlist_core/smartlist_core.h"
      17             : #include "lib/smartlist_core/smartlist_foreach.h"
      18             : #endif
      19             : #include "lib/malloc/malloc.h"
      20             : #include "lib/string/printf.h"
      21             : 
      22             : #include <string.h>
      23             : #include <stdlib.h>
      24             : 
      25             : #ifdef TOR_UNIT_TESTS
      26             : static void (*failed_assertion_cb)(void) = NULL;
      27             : static int n_bugs_to_capture = 0;
      28             : static smartlist_t *bug_messages = NULL;
      29             : #define capturing_bugs() (bug_messages != NULL && n_bugs_to_capture)
      30             : void
      31          41 : tor_capture_bugs_(int n)
      32             : {
      33          41 :   tor_end_capture_bugs_();
      34          41 :   bug_messages = smartlist_new();
      35          41 :   n_bugs_to_capture = n;
      36          41 : }
      37             : void
      38          94 : tor_end_capture_bugs_(void)
      39             : {
      40          94 :   n_bugs_to_capture = 0;
      41          94 :   if (!bug_messages)
      42             :     return;
      43          73 :   SMARTLIST_FOREACH(bug_messages, char *, cp, tor_free(cp));
      44          41 :   smartlist_free(bug_messages);
      45          41 :   bug_messages = NULL;
      46             : }
      47             : const smartlist_t *
      48          65 : tor_get_captured_bug_log_(void)
      49             : {
      50          65 :   return bug_messages;
      51             : }
      52             : static void
      53          32 : add_captured_bug(const char *s)
      54             : {
      55          32 :   --n_bugs_to_capture;
      56          32 :   smartlist_add_strdup(bug_messages, s);
      57          32 : }
      58             : /** Set a callback to be invoked when we get any tor_bug_occurred_
      59             :  * invocation. We use this in the unit tests so that a nonfatal
      60             :  * assertion failure can also count as a test failure.
      61             :  */
      62             : void
      63        5318 : tor_set_failed_assertion_callback(void (*fn)(void))
      64             : {
      65        5318 :   failed_assertion_cb = fn;
      66        5318 : }
      67             : #else /* !defined(TOR_UNIT_TESTS) */
      68             : #define capturing_bugs() (0)
      69             : #define add_captured_bug(s) do { } while (0)
      70             : #endif /* defined(TOR_UNIT_TESTS) */
      71             : 
      72             : /** Helper for tor_assert: report the assertion failure. */
      73             : void
      74           0 : tor_assertion_failed_(const char *fname, unsigned int line,
      75             :                       const char *func, const char *expr,
      76             :                       const char *fmt, ...)
      77             : {
      78           0 :   char *buf = NULL;
      79           0 :   char *extra = NULL;
      80           0 :   va_list ap;
      81             : 
      82             : #ifdef __clang__
      83             : #pragma clang diagnostic push
      84             : #pragma clang diagnostic ignored "-Wformat-nonliteral"
      85             : #endif
      86           0 :   if (fmt) {
      87           0 :     va_start(ap,fmt);
      88           0 :     tor_vasprintf(&extra, fmt, ap);
      89           0 :     va_end(ap);
      90             :   }
      91             : #ifdef __clang__
      92             : #pragma clang diagnostic pop
      93             : #endif
      94             : 
      95           0 :   log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
      96             :           fname, line, func, expr);
      97           0 :   tor_asprintf(&buf, "Assertion %s failed in %s at %s:%u: %s",
      98           0 :                expr, func, fname, line, extra ? extra : "");
      99           0 :   tor_free(extra);
     100           0 :   log_backtrace(LOG_ERR, LD_BUG, buf);
     101           0 :   tor_free(buf);
     102           0 : }
     103             : 
     104             : /** Helper for tor_assert_nonfatal: report the assertion failure. */
     105             : void
     106          32 : tor_bug_occurred_(const char *fname, unsigned int line,
     107             :                   const char *func, const char *expr,
     108             :                   int once, const char *fmt, ...)
     109             : {
     110          32 :   char *buf = NULL;
     111          64 :   const char *once_str = once ?
     112          32 :     " (Future instances of this warning will be silenced.)": "";
     113          32 :   if (! expr) {
     114           1 :     if (capturing_bugs()) {
     115           1 :       add_captured_bug("This line should not have been reached.");
     116          33 :       return;
     117             :     }
     118           0 :     log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s",
     119             :              fname, line, func, once_str);
     120           0 :     tor_asprintf(&buf,
     121             :                  "Line unexpectedly reached at %s at %s:%u",
     122             :                  func, fname, line);
     123             :   } else {
     124          31 :     if (capturing_bugs()) {
     125          31 :       add_captured_bug(expr);
     126          31 :       return;
     127             :     }
     128             : 
     129           0 :     va_list ap;
     130           0 :     char *extra = NULL;
     131             : 
     132             : #ifdef __clang__
     133             : #pragma clang diagnostic push
     134             : #pragma clang diagnostic ignored "-Wformat-nonliteral"
     135             : #endif
     136           0 :     if (fmt) {
     137           0 :       va_start(ap,fmt);
     138           0 :       tor_vasprintf(&extra, fmt, ap);
     139           0 :       va_end(ap);
     140             :     }
     141             : #ifdef __clang__
     142             : #pragma clang diagnostic pop
     143             : #endif
     144             : 
     145           0 :     log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s",
     146             :              fname, line, func, expr, once_str);
     147           0 :     tor_asprintf(&buf, "Non-fatal assertion %s failed in %s at %s:%u%s%s",
     148             :                  expr, func, fname, line, fmt ? " : " : "",
     149           0 :                  extra ? extra : "");
     150           0 :     tor_free(extra);
     151             :   }
     152           0 :   log_backtrace(LOG_WARN, LD_BUG, buf);
     153           0 :   tor_free(buf);
     154             : 
     155             : #ifdef TOR_UNIT_TESTS
     156           0 :   if (failed_assertion_cb) {
     157           0 :     failed_assertion_cb();
     158             :   }
     159             : #endif
     160             : }
     161             : 
     162             : /**
     163             :  * Call the tor_raw_abort_() function to close raw logs, then kill the current
     164             :  * process with a fatal error. But first, close the file-based log file
     165             :  * descriptors, so error messages are written before process termination.
     166             :  *
     167             :  * (This is a separate function so that we declare it in util_bug.h without
     168             :  * including torerr.h in all the users of util_bug.h)
     169             :  **/
     170             : void
     171           0 : tor_abort_(void)
     172             : {
     173           0 :   logs_flush_sigsafe();
     174           0 :   tor_raw_abort_();
     175             : }
     176             : 
     177             : #ifdef _WIN32
     178             : /** Take a filename and return a pointer to its final element.  This
     179             :  * function is called on __FILE__ to fix a MSVC nit where __FILE__
     180             :  * contains the full path to the file.  This is bad, because it
     181             :  * confuses users to find the home directory of the person who
     182             :  * compiled the binary in their warning messages.
     183             :  */
     184             : const char *
     185             : tor_fix_source_file(const char *fname)
     186             : {
     187             :   const char *cp1, *cp2, *r;
     188             :   cp1 = strrchr(fname, '/');
     189             :   cp2 = strrchr(fname, '\\');
     190             :   if (cp1 && cp2) {
     191             :     r = (cp1<cp2)?(cp2+1):(cp1+1);
     192             :   } else if (cp1) {
     193             :     r = cp1+1;
     194             :   } else if (cp2) {
     195             :     r = cp2+1;
     196             :   } else {
     197             :     r = fname;
     198             :   }
     199             :   return r;
     200             : }
     201             : #endif /* defined(_WIN32) */

Generated by: LCOV version 1.14