diff options
Diffstat (limited to 'src/test/test_util.c')
-rw-r--r-- | src/test/test_util.c | 1277 |
1 files changed, 1061 insertions, 216 deletions
diff --git a/src/test/test_util.c b/src/test/test_util.c index d534cc0b52..0b707caeeb 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -5,6 +5,7 @@ #include "orconfig.h" #define COMPAT_PRIVATE +#define COMPAT_TIME_PRIVATE #define CONTROL_PRIVATE #define UTIL_PRIVATE #include "or.h" @@ -13,6 +14,7 @@ #include "test.h" #include "memarea.h" #include "util_process.h" +#include "log_test_helpers.h" #ifdef HAVE_PWD_H #include <pwd.h> @@ -30,6 +32,9 @@ #include <ctype.h> #include <float.h> +#define INFINITY_DBL ((double)INFINITY) +#define NAN_DBL ((double)NAN) + /* XXXX this is a minimal wrapper to make the unit tests compile with the * changed tor_timegm interface. */ static time_t @@ -258,7 +263,7 @@ test_util_time(void *arg) int i; struct timeval tv; - /* Test tv_udiff */ + /* Test tv_udiff and tv_mdiff */ (void)arg; start.tv_sec = 5; @@ -268,22 +273,312 @@ test_util_time(void *arg) end.tv_usec = 5000; tt_int_op(0L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(0L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(0L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(0L,OP_EQ, tv_mdiff(&end, &start)); end.tv_usec = 7000; tt_int_op(2000L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(2L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-2000L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-2L,OP_EQ, tv_mdiff(&end, &start)); end.tv_sec = 6; tt_int_op(1002000L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(1002L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-1002000L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-1002L,OP_EQ, tv_mdiff(&end, &start)); end.tv_usec = 0; tt_int_op(995000L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(995L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-995000L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-995L,OP_EQ, tv_mdiff(&end, &start)); end.tv_sec = 4; tt_int_op(-1005000L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(-1005L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(1005000L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(1005L,OP_EQ, tv_mdiff(&end, &start)); + + /* Negative tv_sec values, these will break on platforms where tv_sec is + * unsigned */ + + end.tv_sec = -10; + + tt_int_op(-15005000L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(-15005L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(15005000L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(15005L,OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = -100; + + tt_int_op(89995000L,OP_EQ, tv_udiff(&start, &end)); + tt_int_op(89995L,OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-89995000L,OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-89995L,OP_EQ, tv_mdiff(&end, &start)); + + /* Test that tv_usec values round away from zero when converted to msec */ + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = 10; + end.tv_usec = 499; + + tt_int_op(10000499L, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(10000L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-10000499L, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-10000L, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = 10; + end.tv_usec = 500; + + tt_int_op(10000500L, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(10001L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-10000500L, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-10000L, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = 10; + end.tv_usec = 501; + + tt_int_op(10000501L, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(10001L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-10000501L, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-10001L, OP_EQ, tv_mdiff(&end, &start)); + + /* Overflow conditions */ + +#ifdef _WIN32 + /* Would you believe that tv_sec is a long on windows? Of course you would.*/ +#define TV_SEC_MAX LONG_MAX +#define TV_SEC_MIN LONG_MIN +#else + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + * Which means TIME_MAX is not actually the maximum value of tv_sec. + * But that's ok for the moment, because the code correctly performs 64-bit + * calculations internally, then catches the overflow. */ +#define TV_SEC_MAX TIME_MAX +#define TV_SEC_MIN TIME_MIN +#endif + +/* Assume tv_usec is an unsigned integer until proven otherwise */ +#define TV_USEC_MAX UINT_MAX +#define TOR_USEC_PER_SEC 1000000 + + /* Overflows in the result type */ + + /* All comparisons work */ + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = LONG_MAX/1000 - 2; + end.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(end.tv_sec*1000L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-end.tv_sec*1000L, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = LONG_MAX/1000000 - 1; + end.tv_usec = 0; + + tt_int_op(end.tv_sec*1000000L, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(end.tv_sec*1000L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(-end.tv_sec*1000000L, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-end.tv_sec*1000L, OP_EQ, tv_mdiff(&end, &start)); + + /* No comparisons work */ + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = LONG_MAX/1000 + 1; + end.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = LONG_MAX/1000000 + 1; + end.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(end.tv_sec*1000L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-end.tv_sec*1000L, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = LONG_MAX/1000; + end.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = 0; + start.tv_usec = 0; + end.tv_sec = LONG_MAX/1000000; + end.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op((end.tv_sec + 1)*1000L, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(-(end.tv_sec + 1)*1000L, OP_EQ, tv_mdiff(&end, &start)); + + /* Overflows on comparison to zero */ + + start.tv_sec = 0; + start.tv_usec = 0; + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = 0; + end.tv_usec = TV_USEC_MAX; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = TV_USEC_MAX; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = 0; + end.tv_usec = 0; + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = TV_USEC_MAX; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + /* overflows on comparison to maxima / minima */ + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = 0; + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = 0; + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + /* overflows on comparison to maxima / minima with extra usec */ + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = TOR_USEC_PER_SEC; + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + end.tv_sec = TV_SEC_MAX; + end.tv_usec = TOR_USEC_PER_SEC; + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = 0; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); + + start.tv_sec = TV_SEC_MIN; + start.tv_usec = TOR_USEC_PER_SEC; + + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&start, &end)); + tt_int_op(LONG_MAX, OP_EQ, tv_udiff(&end, &start)); + tt_int_op(LONG_MAX, OP_EQ, tv_mdiff(&end, &start)); /* Test tor_timegm & tor_gmtime_r */ @@ -349,31 +644,57 @@ test_util_time(void *arg) /* Test tor_timegm out of range */ + /* The below tests will all cause a BUG message, so we capture, suppress, + * and detect. */ +#define CAPTURE() do { \ + setup_full_capture_of_logs(LOG_WARN); \ + } while (0) +#define CHECK_TIMEGM_WARNING(msg) do { \ + expect_log_msg_containing(msg); \ + tt_int_op(1, OP_EQ, smartlist_len(mock_saved_logs())); \ + teardown_capture_of_logs(); \ + } while (0) + +#define CHECK_TIMEGM_ARG_OUT_OF_RANGE(msg) \ + CHECK_TIMEGM_WARNING("Out-of-range argument to tor_timegm") + /* year */ /* Wrong year < 1970 */ a_time.tm_year = 1969-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = -1-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); #if SIZEOF_INT == 4 || SIZEOF_INT == 8 a_time.tm_year = -1*(1 << 16); + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* one of the smallest tm_year values my 64 bit system supports: * t_res = -9223372036854775LL without clamping */ a_time.tm_year = -292275055-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = INT32_MIN; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); #endif #if SIZEOF_INT == 8 a_time.tm_year = -1*(1 << 48); + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* while unlikely, the system's gmtime(_r) could return * a "correct" retrospective gregorian negative year value, @@ -381,25 +702,35 @@ test_util_time(void *arg) * -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657 * 730485 is the number of days in two millenia, including leap days */ a_time.tm_year = -292277022657-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = INT64_MIN; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); #endif /* Wrong year >= INT32_MAX - 1900 */ #if SIZEOF_INT == 4 || SIZEOF_INT == 8 a_time.tm_year = INT32_MAX-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = INT32_MAX; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); #endif #if SIZEOF_INT == 8 /* one of the largest tm_year values my 64 bit system supports */ a_time.tm_year = 292278994-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* while unlikely, the system's gmtime(_r) could return * a "correct" proleptic gregorian year value, @@ -407,72 +738,104 @@ test_util_time(void *arg) * (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596 * 730485 is the number of days in two millenia, including leap days */ a_time.tm_year = 292277026596-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = INT64_MAX-1900; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = INT64_MAX; + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); #endif /* month */ a_time.tm_year = 2007-1900; /* restore valid year */ a_time.tm_mon = 12; /* Wrong month, it's 0-based */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_mon = -1; /* Wrong month */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* day */ a_time.tm_mon = 6; /* Try July */ a_time.tm_mday = 32; /* Wrong day */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_mon = 5; /* Try June */ a_time.tm_mday = 31; /* Wrong day */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = 2008-1900; /* Try a leap year */ a_time.tm_mon = 1; /* in feb. */ a_time.tm_mday = 30; /* Wrong day */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_year = 2011-1900; /* Try a non-leap year */ a_time.tm_mon = 1; /* in feb. */ a_time.tm_mday = 29; /* Wrong day */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_mday = 0; /* Wrong day, it's 1-based (to be different) */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* hour */ a_time.tm_mday = 3; /* restore valid month day */ a_time.tm_hour = 24; /* Wrong hour, it's 0-based */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_hour = -1; /* Wrong hour */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* minute */ a_time.tm_hour = 22; /* restore valid hour */ a_time.tm_min = 60; /* Wrong minute, it's 0-based */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_min = -1; /* Wrong minute */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* second */ a_time.tm_min = 37; /* restore valid minute */ a_time.tm_sec = 61; /* Wrong second: 0-based with leap seconds */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); a_time.tm_sec = -1; /* Wrong second */ + CAPTURE(); tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time)); + CHECK_TIMEGM_ARG_OUT_OF_RANGE(); /* Test tor_gmtime_r out of range */ @@ -512,9 +875,17 @@ test_util_time(void *arg) * 730485 is the number of days in two millenia, including leap days * (int64_t)b_time.tm_year == (-292277022657LL-1900LL) without clamping */ t_res = INT64_MIN; + CAPTURE(); tor_gmtime_r(&t_res, &b_time); - tt_assert(b_time.tm_year == (1970-1900) || - b_time.tm_year == (1-1900)); + if (! (b_time.tm_year == (1970-1900) || + b_time.tm_year == (1-1900))) { + tt_int_op(b_time.tm_year, OP_EQ, 1970-1900); + } + if (b_time.tm_year != 1970-1900) { + CHECK_TIMEGM_WARNING("Rounding up to "); + } else { + teardown_capture_of_logs(); + } } #endif @@ -550,7 +921,10 @@ test_util_time(void *arg) * 730485 is the number of days in two millenia, including leap days * (int64_t)b_time.tm_year == (292277026596L-1900L) without clamping */ t_res = INT64_MAX; + CAPTURE(); tor_gmtime_r(&t_res, &b_time); + CHECK_TIMEGM_WARNING("Rounding down to "); + tt_assert(b_time.tm_year == (2037-1900) || b_time.tm_year == (9999-1900)); } @@ -622,9 +996,16 @@ test_util_time(void *arg) parse_rfc1123_time("Wed, 30 Ene 2011 23:59:59 GMT", &t_res)); tt_int_op(-1,OP_EQ, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:59 GM", &t_res)); + tt_int_op(-1,OP_EQ, + parse_rfc1123_time("Wed, 30 Mar 1900 23:59:59 GMT", &t_res)); + /* Leap year. */ tt_int_op(-1,OP_EQ, parse_rfc1123_time("Wed, 29 Feb 2011 16:00:00 GMT", &t_res)); + tt_int_op(0,OP_EQ, + parse_rfc1123_time("Wed, 29 Feb 2012 16:00:00 GMT", &t_res)); + + /* Leap second plus one */ tt_int_op(-1,OP_EQ, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:61 GMT", &t_res)); @@ -732,8 +1113,11 @@ test_util_time(void *arg) #endif #endif +#undef CAPTURE +#undef CHECK_TIMEGM_ARG_OUT_OF_RANGE + done: - ; + teardown_capture_of_logs(); } static void @@ -865,106 +1249,106 @@ test_util_config_line(void *arg) , sizeof(buf)); str = buf; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k"); tt_str_op(v,OP_EQ, "v"); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "key value with")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "key"); tt_str_op(v,OP_EQ, "value with spaces"); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "keykey")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "keykey"); tt_str_op(v,OP_EQ, "val"); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "k2\n")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k2"); tt_str_op(v,OP_EQ, ""); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "k3 \n")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k3"); tt_str_op(v,OP_EQ, ""); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "#comment")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k4"); tt_str_op(v,OP_EQ, ""); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "k5#abc")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k5"); tt_str_op(v,OP_EQ, ""); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "k6")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k6"); tt_str_op(v,OP_EQ, "val"); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "kseven")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "kseven"); tt_str_op(v,OP_EQ, "a quoted \'string"); tor_free(k); tor_free(v); tt_assert(!strcmpstart(str, "k8 ")); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k8"); tt_str_op(v,OP_EQ, "a quoted\n\"str\\ing\t\x01\x01\x01\""); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k9"); tt_str_op(v,OP_EQ, "a line that spans two lines."); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k10"); tt_str_op(v,OP_EQ, "more than one continuation"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k11"); tt_str_op(v,OP_EQ, "continuation at the start"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k12"); tt_str_op(v,OP_EQ, "line with a embedded"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k13"); tt_str_op(v,OP_EQ, "continuation at the very start"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k14"); tt_str_op(v,OP_EQ, "a line that has a comment and" ); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k15"); tt_str_op(v,OP_EQ, "this should be the next new line"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k16"); tt_str_op(v,OP_EQ, "a line that has a comment and" ); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k17"); tt_str_op(v,OP_EQ, "this should be the next new line"); tor_free(k); tor_free(v); @@ -999,32 +1383,36 @@ test_util_config_line_quotes(void *arg) , sizeof(buf4)); str = buf1; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "kTrailingSpace"); tt_str_op(v,OP_EQ, "quoted value"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); str = buf2; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); str = buf3; - str = parse_config_line_from_str(str, &k, &v); + const char *err = NULL; + str = parse_config_line_from_str_verbose(str, &k, &v, &err); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); + tt_str_op(err, OP_EQ, "Invalid escape sequence in quoted string"); str = buf4; - str = parse_config_line_from_str(str, &k, &v); + err = NULL; + str = parse_config_line_from_str_verbose(str, &k, &v, &err); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); + tt_str_op(err, OP_EQ, "Invalid escape sequence in quoted string"); done: tor_free(k); @@ -1046,12 +1434,12 @@ test_util_config_line_comment_character(void *arg) , sizeof(buf)); str = buf; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k1"); tt_str_op(v,OP_EQ, "# in quotes"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "k2"); tt_str_op(v,OP_EQ, "some value"); tor_free(k); tor_free(v); @@ -1059,7 +1447,7 @@ test_util_config_line_comment_character(void *arg) tt_str_op(str,OP_EQ, "k3 /home/user/myTorNetwork#2\n"); #if 0 - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); test_streq(k, "k3"); test_streq(v, "/home/user/myTorNetwork#2"); tor_free(k); tor_free(v); @@ -1116,57 +1504,57 @@ test_util_config_line_escaped_content(void *arg) str = buf1; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "HexadecimalLower"); tt_str_op(v,OP_EQ, "*"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "HexadecimalUpper"); tt_str_op(v,OP_EQ, "*"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "HexadecimalUpperX"); tt_str_op(v,OP_EQ, "*"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "Octal"); tt_str_op(v,OP_EQ, "*"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "Newline"); tt_str_op(v,OP_EQ, "\n"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "Tab"); tt_str_op(v,OP_EQ, "\t"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "CarriageReturn"); tt_str_op(v,OP_EQ, "\r"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "DoubleQuote"); tt_str_op(v,OP_EQ, "\""); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "SimpleQuote"); tt_str_op(v,OP_EQ, "'"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "Backslash"); tt_str_op(v,OP_EQ, "\\"); tor_free(k); tor_free(v); - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_str_op(k,OP_EQ, "Mix"); tt_str_op(v,OP_EQ, "This is a \"star\":\t'*'\nAnd second line"); tor_free(k); tor_free(v); @@ -1174,41 +1562,115 @@ test_util_config_line_escaped_content(void *arg) str = buf2; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); str = buf3; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); str = buf4; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); #if 0 str = buf5; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str, OP_EQ, NULL); tor_free(k); tor_free(v); #endif str = buf6; - str = parse_config_line_from_str(str, &k, &v); + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); + tt_ptr_op(str,OP_EQ, NULL); + tor_free(k); tor_free(v); + + /* more things to try. */ + /* Bad hex: */ + strlcpy(buf1, "Foo \"\\x9g\"\n", sizeof(buf1)); + strlcpy(buf2, "Foo \"\\xg0\"\n", sizeof(buf2)); + strlcpy(buf3, "Foo \"\\xf\"\n", sizeof(buf3)); + /* bad escape */ + strlcpy(buf4, "Foo \"\\q\"\n", sizeof(buf4)); + /* missing endquote */ + strlcpy(buf5, "Foo \"hello\n", sizeof(buf5)); + /* extra stuff */ + strlcpy(buf6, "Foo \"hello\" world\n", sizeof(buf6)); + + str=buf1; + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); + tt_ptr_op(str,OP_EQ, NULL); + tor_free(k); tor_free(v); + + str=buf2; + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); + tt_ptr_op(str,OP_EQ, NULL); + tor_free(k); tor_free(v); + + str=buf3; + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); + tt_ptr_op(str,OP_EQ, NULL); + tor_free(k); tor_free(v); + + str=buf4; + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); + tt_ptr_op(str,OP_EQ, NULL); + tor_free(k); tor_free(v); + + str=buf5; + + str = parse_config_line_from_str_verbose(str, &k, &v, NULL); tt_ptr_op(str,OP_EQ, NULL); tor_free(k); tor_free(v); + str=buf6; + const char *err = NULL; + str = parse_config_line_from_str_verbose(str, &k, &v, &err); + tt_ptr_op(str,OP_EQ, NULL); + tor_free(k); tor_free(v); + tt_str_op(err,OP_EQ, "Excess data after quoted string"); + done: tor_free(k); tor_free(v); } +static void +test_util_config_line_crlf(void *arg) +{ + char *k=NULL, *v=NULL; + const char *err = NULL; + (void)arg; + const char *str = + "Hello world\r\n" + "Hello \"nice big world\"\r\n"; + + str = parse_config_line_from_str_verbose(str, &k, &v, &err); + tt_assert(str); + tt_str_op(k,OP_EQ,"Hello"); + tt_str_op(v,OP_EQ,"world"); + tt_assert(!err); + tor_free(k); tor_free(v); + + str = parse_config_line_from_str_verbose(str, &k, &v, &err); + tt_assert(str); + tt_str_op(k,OP_EQ,"Hello"); + tt_str_op(v,OP_EQ,"nice big world"); + tt_assert(!err); + tor_free(k); tor_free(v); + tt_str_op(str,OP_EQ, ""); + + done: + tor_free(k); tor_free(v); +} + #ifndef _WIN32 static void test_util_expand_filename(void *arg) @@ -1372,8 +1834,7 @@ static void test_util_strmisc(void *arg) { char buf[1024]; - int i; - char *cp, *cp_tmp = NULL; + char *cp_tmp = NULL; /* Test strl operations */ (void)arg; @@ -1398,117 +1859,6 @@ test_util_strmisc(void *arg) tor_strstrip(buf, "!? "); tt_str_op(buf,OP_EQ, "Testing123"); - /* Test parse_long */ - /* Empty/zero input */ - tt_int_op(0L,OP_EQ, tor_parse_long("",10,0,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("0",10,0,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - /* Normal cases */ - tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,10,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(10L,OP_EQ, tor_parse_long("10",10,10,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,100,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,0,&i,NULL)); - tt_int_op(1,OP_EQ, i); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-50,0,&i,NULL)); - tt_int_op(1,OP_EQ, i); - /* Extra garbage */ - tt_int_op(0L,OP_EQ, tor_parse_long("10m",10,0,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(10L,OP_EQ, tor_parse_long("10m",10,0,100,&i,&cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, "m"); - tt_int_op(-50L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, " plus garbage"); - /* Out of bounds */ - tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,0,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - /* Base different than 10 */ - tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL)); - tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL)); - tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL)); - tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL)); - tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); - tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL)); - tt_int_op(i,OP_EQ, 0); - - /* Test parse_ulong */ - tt_int_op(0UL,OP_EQ, tor_parse_ulong("",10,0,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("0",10,0,100,NULL,NULL)); - tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("10",10,50,100,NULL,NULL)); - tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,10,NULL,NULL)); - tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,10,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL)); - tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,-100,100,NULL,NULL)); - tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL)); - tt_int_op(0,OP_EQ, i); - - /* Test parse_uint64 */ - tt_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, " x"); - tt_assert(U64_LITERAL(12345678901) == - tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp)); - tt_int_op(1,OP_EQ, i); - tt_str_op(cp,OP_EQ, ""); - tt_assert(U64_LITERAL(0) == - tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); - tt_int_op(0,OP_EQ, i); - tt_assert(U64_LITERAL(0) == - tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp)); - tt_int_op(0,OP_EQ, i); - - { - /* Test parse_double */ - double d = tor_parse_double("10", 0, UINT64_MAX,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 10); - d = tor_parse_double("0", 0, UINT64_MAX,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 0); - d = tor_parse_double(" ", 0, UINT64_MAX,&i,NULL); - tt_int_op(0,OP_EQ, i); - d = tor_parse_double(".0a", 0, UINT64_MAX,&i,NULL); - tt_int_op(0,OP_EQ, i); - d = tor_parse_double(".0a", 0, UINT64_MAX,&i,&cp); - tt_int_op(1,OP_EQ, i); - d = tor_parse_double("-.0", 0, UINT64_MAX,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 0); - d = tor_parse_double("-10", -100.0, 100.0,&i,NULL); - tt_int_op(1,OP_EQ, i); - tt_int_op(-10.0,OP_EQ, d); - } - - { - /* Test tor_parse_* where we overflow/underflow the underlying type. */ - /* This string should overflow 64-bit ints. */ -#define TOOBIG "100000000000000000000000000" - tt_int_op(0L, OP_EQ, - tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - tt_int_op(0L,OP_EQ, - tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - tt_int_op(0UL,OP_EQ, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - tt_u64_op(U64_LITERAL(0), OP_EQ, tor_parse_uint64(TOOBIG, 10, - 0, UINT64_MAX, &i, NULL)); - tt_int_op(i,OP_EQ, 0); - } - /* Test snprintf */ /* Returning -1 when there's not enough room in the output buffer */ tt_int_op(-1,OP_EQ, tor_snprintf(buf, 0, "Foo")); @@ -1583,6 +1933,17 @@ test_util_strmisc(void *arg) tt_str_op("\"z\\001abc\\277d\"",OP_EQ, escaped("z\001abc\277d")); tt_str_op("\"z\\336\\255 ;foo\"",OP_EQ, escaped("z\xde\xad\x20;foo")); + /* Other cases of esc_for_log{,_len} */ + cp_tmp = esc_for_log(NULL); + tt_str_op(cp_tmp, OP_EQ, "(null)"); + tor_free(cp_tmp); + cp_tmp = esc_for_log_len("abcdefg", 3); + tt_str_op(cp_tmp, OP_EQ, "\"abc\""); + tor_free(cp_tmp); + cp_tmp = esc_for_log_len("abcdefg", 100); + tt_str_op(cp_tmp, OP_EQ, "\"abcdefg\""); + tor_free(cp_tmp); + /* Test strndup and memdup */ { const char *s = "abcdefghijklmnopqrstuvwxyz"; @@ -1642,9 +2003,9 @@ test_util_strmisc(void *arg) /* Test hex_str */ { char binary_data[68]; - size_t i; - for (i = 0; i < sizeof(binary_data); ++i) - binary_data[i] = i; + size_t idx; + for (idx = 0; idx < sizeof(binary_data); ++idx) + binary_data[idx] = idx; tt_str_op(hex_str(binary_data, 0),OP_EQ, ""); tt_str_op(hex_str(binary_data, 1),OP_EQ, "00"); tt_str_op(hex_str(binary_data, 17),OP_EQ, @@ -1687,6 +2048,144 @@ test_util_strmisc(void *arg) } static void +test_util_parse_integer(void *arg) +{ + (void)arg; + int i; + char *cp; + + /* Test parse_long */ + /* Empty/zero input */ + tt_int_op(0L,OP_EQ, tor_parse_long("",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0L,OP_EQ, tor_parse_long("0",10,0,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + /* Normal cases */ + tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,10,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(10L,OP_EQ, tor_parse_long("10",10,10,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,100,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,0,&i,NULL)); + tt_int_op(1,OP_EQ, i); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-50,0,&i,NULL)); + tt_int_op(1,OP_EQ, i); + /* Extra garbage */ + tt_int_op(0L,OP_EQ, tor_parse_long("10m",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(10L,OP_EQ, tor_parse_long("10m",10,0,100,&i,&cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, "m"); + tt_int_op(-50L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, " plus garbage"); + /* Illogical min max */ + tor_capture_bugs_(1); + tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); + tt_str_op("!(max < min)", OP_EQ, + smartlist_get(tor_get_captured_bug_log_(), 0)); + tor_end_capture_bugs_(); + tor_capture_bugs_(1); + tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); + tt_str_op("!(max < min)", OP_EQ, + smartlist_get(tor_get_captured_bug_log_(), 0)); + tor_end_capture_bugs_(); + /* Out of bounds */ + tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + /* Base different than 10 */ + tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL)); + tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL)); + tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL)); + tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL)); + tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); + tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL)); + tt_int_op(i,OP_EQ, 0); + + /* Test parse_ulong */ + tt_int_op(0UL,OP_EQ, tor_parse_ulong("",10,0,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("0",10,0,100,NULL,NULL)); + tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("10",10,50,100,NULL,NULL)); + tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,10,NULL,NULL)); + tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,10,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL)); + tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL)); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL)); + tt_int_op(0,OP_EQ, i); + + /* Test parse_uint64 */ + tt_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, " x"); + tt_assert(U64_LITERAL(12345678901) == + tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp)); + tt_int_op(1,OP_EQ, i); + tt_str_op(cp,OP_EQ, ""); + tt_assert(U64_LITERAL(0) == + tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); + tt_int_op(0,OP_EQ, i); + tt_assert(U64_LITERAL(0) == + tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp)); + tt_int_op(0,OP_EQ, i); + + { + /* Test parse_double */ + double d = tor_parse_double("10", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_assert(DBL_TO_U64(d) == 10); + d = tor_parse_double("0", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_assert(DBL_TO_U64(d) == 0); + d = tor_parse_double(" ", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(0,OP_EQ, i); + d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(0,OP_EQ, i); + d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,&cp); + tt_int_op(1,OP_EQ, i); + d = tor_parse_double("-.0", 0, (double)UINT64_MAX,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_assert(DBL_TO_U64(d) == 0); + d = tor_parse_double("-10", -100.0, 100.0,&i,NULL); + tt_int_op(1,OP_EQ, i); + tt_double_op(fabs(d - -10.0),OP_LT, 1E-12); + } + + { + /* Test tor_parse_* where we overflow/underflow the underlying type. */ + /* This string should overflow 64-bit ints. */ +#define TOOBIG "100000000000000000000000000" + tt_int_op(0L, OP_EQ, + tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + tt_int_op(0L,OP_EQ, + tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + tt_int_op(0UL,OP_EQ, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + tt_u64_op(U64_LITERAL(0), OP_EQ, tor_parse_uint64(TOOBIG, 10, + 0, UINT64_MAX, &i, NULL)); + tt_int_op(i,OP_EQ, 0); + } + done: + tor_end_capture_bugs_(); +} + +static void test_util_pow2(void *arg) { /* Test tor_log2(). */ @@ -1737,22 +2236,21 @@ test_util_gzip(void *arg) (void)arg; buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ"); tt_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD); - if (is_gzip_supported()) { - tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, - GZIP_METHOD)); - tt_assert(buf2); - tt_assert(len1 < strlen(buf1)); - tt_assert(detect_compression_method(buf2, len1) == GZIP_METHOD); - - tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1, - GZIP_METHOD, 1, LOG_INFO)); - tt_assert(buf3); - tt_int_op(strlen(buf1) + 1,OP_EQ, len2); - tt_str_op(buf1,OP_EQ, buf3); - - tor_free(buf2); - tor_free(buf3); - } + + tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, + GZIP_METHOD)); + tt_assert(buf2); + tt_assert(len1 < strlen(buf1)); + tt_assert(detect_compression_method(buf2, len1) == GZIP_METHOD); + + tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1, + GZIP_METHOD, 1, LOG_INFO)); + tt_assert(buf3); + tt_int_op(strlen(buf1) + 1,OP_EQ, len2); + tt_str_op(buf1,OP_EQ, buf3); + + tor_free(buf2); + tor_free(buf3); tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1, ZLIB_METHOD)); @@ -1836,6 +2334,58 @@ test_util_gzip(void *arg) tor_free(buf1); } +static void +test_util_gzip_compression_bomb(void *arg) +{ + /* A 'compression bomb' is a very small object that uncompresses to a huge + * one. Most compression formats support them, but they can be a DOS vector. + * In Tor we try not to generate them, and we don't accept them. + */ + (void) arg; + size_t one_million = 1<<20; + char *one_mb = tor_malloc_zero(one_million); + char *result = NULL; + size_t result_len = 0; + tor_zlib_state_t *state = NULL; + + /* Make sure we can't produce a compression bomb */ + setup_full_capture_of_logs(LOG_WARN); + tt_int_op(-1, OP_EQ, tor_gzip_compress(&result, &result_len, + one_mb, one_million, + ZLIB_METHOD)); + expect_single_log_msg_containing( + "We compressed something and got an insanely high " + "compression factor; other Tors would think this " + "was a zlib bomb."); + teardown_capture_of_logs(); + + /* Here's a compression bomb that we made manually. */ + const char compression_bomb[1039] = + { 0x78, 0xDA, 0xED, 0xC1, 0x31, 0x01, 0x00, 0x00, 0x00, 0xC2, + 0xA0, 0xF5, 0x4F, 0x6D, 0x08, 0x5F, 0xA0 /* .... */ }; + tt_int_op(-1, OP_EQ, tor_gzip_uncompress(&result, &result_len, + compression_bomb, 1039, + ZLIB_METHOD, 0, LOG_WARN)); + + /* Now try streaming that. */ + state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION); + tor_zlib_output_t r; + const char *inp = compression_bomb; + size_t inlen = 1039; + do { + char *outp = one_mb; + size_t outleft = 4096; /* small on purpose */ + r = tor_zlib_process(state, &outp, &outleft, &inp, &inlen, 0); + tt_int_op(inlen, OP_NE, 0); + } while (r == TOR_ZLIB_BUF_FULL); + + tt_int_op(r, OP_EQ, TOR_ZLIB_ERR); + + done: + tor_free(one_mb); + tor_zlib_free(state); +} + /** Run unit tests for mmap() wrapper functionality. */ static void test_util_mmap(void *arg) @@ -1950,7 +2500,7 @@ test_util_sscanf(void *arg) { unsigned u1, u2, u3; unsigned long ulng; - char s1[20], s2[10], s3[10], ch; + char s1[20], s2[10], s3[10], ch, *huge = NULL; int r; long lng1,lng2; int int1, int2; @@ -1962,7 +2512,13 @@ test_util_sscanf(void *arg) tt_int_op(-1,OP_EQ, tor_sscanf("wrong", "%5c", s1)); /* %c cannot have a number. */ tt_int_op(-1,OP_EQ, tor_sscanf("hello", "%s", s1)); /* %s needs a number. */ - tt_int_op(-1,OP_EQ, tor_sscanf("prettylongstring", "%999999s", s1)); + /* this will fail because we don't allow widths longer than 9999 */ + { + huge = tor_malloc(1000000); + r = tor_sscanf("prettylongstring", "%99999s", huge); + tor_free(huge); + tt_int_op(-1,OP_EQ, r); + } #if 0 /* GCC thinks these two are illegal. */ test_eq(-1, tor_sscanf("prettylongstring", "%0s", s1)); @@ -2068,8 +2624,13 @@ test_util_sscanf(void *arg) tt_int_op(2,OP_EQ, tor_sscanf("76trombones", "%6u%9s", &u1, s1)); /* %u%s */ tt_int_op(76,OP_EQ, u1); tt_str_op(s1,OP_EQ, "trombones"); - tt_int_op(1,OP_EQ, tor_sscanf("prettylongstring", "%999s", s1)); - tt_str_op(s1,OP_EQ, "prettylongstring"); + { + huge = tor_malloc(1000); + r = tor_sscanf("prettylongstring", "%999s", huge); + tt_int_op(1,OP_EQ, r); + tt_str_op(huge,OP_EQ, "prettylongstring"); + tor_free(huge); + } /* %s doesn't eat spaces */ tt_int_op(2,OP_EQ, tor_sscanf("hello world", "%9s %9s", s1, s2)); tt_str_op(s1,OP_EQ, "hello"); @@ -2293,7 +2854,7 @@ test_util_sscanf(void *arg) test_feq(d4, 3.2); done: - ; + tor_free(huge); } #define tt_char_op(a,op,b) tt_assert_op_type(a,op,b,char,"%c") @@ -2842,19 +3403,40 @@ test_util_memarea(void *arg) p1 = memarea_alloc(area, 1); tt_ptr_op(p1,OP_EQ, p1_orig); memarea_clear(area); + size_t total = 0, initial_allocation, allocation2, dummy; + memarea_get_stats(area, &initial_allocation, &dummy); /* Check for running over an area's size. */ - for (i = 0; i < 512; ++i) { - p1 = memarea_alloc(area, crypto_rand_int(5)+1); + for (i = 0; i < 4096; ++i) { + size_t n = crypto_rand_int(6); + p1 = memarea_alloc(area, n); + total += n; tt_assert(memarea_owns_ptr(area, p1)); } memarea_assert_ok(area); + memarea_get_stats(area, &allocation2, &dummy); /* Make sure we can allocate a too-big object. */ p1 = memarea_alloc_zero(area, 9000); p2 = memarea_alloc_zero(area, 16); + total += 9000; + total += 16; tt_assert(memarea_owns_ptr(area, p1)); tt_assert(memarea_owns_ptr(area, p2)); + /* Now test stats... */ + size_t allocated = 0, used = 0; + memarea_get_stats(area, &allocated, &used); + tt_int_op(used, OP_LE, allocated); + tt_int_op(used, OP_GE, total); /* not EQ, because of alignment and headers*/ + tt_int_op(allocated, OP_GT, allocation2); + + tt_int_op(allocation2, OP_GT, initial_allocation); + + memarea_clear(area); + memarea_get_stats(area, &allocated, &used); + tt_int_op(used, OP_LT, 128); /* Not 0, because of header */ + tt_int_op(allocated, OP_EQ, initial_allocation); + done: memarea_drop_all(area); tor_free(malloced_ptr); @@ -3244,6 +3826,21 @@ test_util_ftruncate(void *ptr) tor_free(buf); } +static void +test_util_num_cpus(void *arg) +{ + (void)arg; + int num = compute_num_cpus(); + if (num < 0) + tt_skip(); + + tt_int_op(num, OP_GE, 1); + tt_int_op(num, OP_LE, 16); + + done: + ; +} + #ifdef _WIN32 static void test_util_load_win_lib(void *ptr) @@ -4209,6 +4806,31 @@ test_util_mathlog(void *arg) } static void +test_util_fraction(void *arg) +{ + uint64_t a,b; + (void)arg; + + a = 99; b = 30; + simplify_fraction64(&a,&b); + tt_u64_op(a, OP_EQ, 33); + tt_u64_op(b, OP_EQ, 10); + + a = 3000000; b = 10000000; + simplify_fraction64(&a,&b); + tt_u64_op(a, OP_EQ, 3); + tt_u64_op(b, OP_EQ, 10); + + a = 0; b = 15; + simplify_fraction64(&a,&b); + tt_u64_op(a, OP_EQ, 0); + tt_u64_op(b, OP_EQ, 1); + + done: + ; +} + +static void test_util_round_to_next_multiple_of(void *arg) { (void)arg; @@ -4223,21 +4845,6 @@ test_util_round_to_next_multiple_of(void *arg) tt_u64_op(round_uint64_to_next_multiple_of(UINT64_MAX,2), ==, UINT64_MAX); - tt_i64_op(round_int64_to_next_multiple_of(0,1), ==, 0); - tt_i64_op(round_int64_to_next_multiple_of(0,7), ==, 0); - - tt_i64_op(round_int64_to_next_multiple_of(99,1), ==, 99); - tt_i64_op(round_int64_to_next_multiple_of(99,7), ==, 105); - tt_i64_op(round_int64_to_next_multiple_of(99,9), ==, 99); - - tt_i64_op(round_int64_to_next_multiple_of(-99,1), ==, -99); - tt_i64_op(round_int64_to_next_multiple_of(-99,7), ==, -98); - tt_i64_op(round_int64_to_next_multiple_of(-99,9), ==, -99); - - tt_i64_op(round_int64_to_next_multiple_of(INT64_MIN,2), ==, INT64_MIN); - tt_i64_op(round_int64_to_next_multiple_of(INT64_MAX,2), ==, - INT64_MAX); - tt_int_op(round_uint32_to_next_multiple_of(0,1), ==, 0); tt_int_op(round_uint32_to_next_multiple_of(0,7), ==, 0); @@ -4407,7 +5014,7 @@ test_util_clamp_double_to_int64(void *arg) { (void)arg; - tt_i64_op(INT64_MIN, ==, clamp_double_to_int64(-INFINITY)); + tt_i64_op(INT64_MIN, ==, clamp_double_to_int64(-INFINITY_DBL)); tt_i64_op(INT64_MIN, ==, clamp_double_to_int64(-1.0 * pow(2.0, 64.0) - 1.0)); tt_i64_op(INT64_MIN, ==, @@ -4420,7 +5027,7 @@ test_util_clamp_double_to_int64(void *arg) tt_i64_op(0, ==, clamp_double_to_int64(-0.9)); tt_i64_op(0, ==, clamp_double_to_int64(-0.1)); tt_i64_op(0, ==, clamp_double_to_int64(0.0)); - tt_i64_op(0, ==, clamp_double_to_int64(NAN)); + tt_i64_op(0, ==, clamp_double_to_int64(NAN_DBL)); tt_i64_op(0, ==, clamp_double_to_int64(0.1)); tt_i64_op(0, ==, clamp_double_to_int64(0.9)); tt_i64_op(1, ==, clamp_double_to_int64(1.0)); @@ -4432,7 +5039,7 @@ test_util_clamp_double_to_int64(void *arg) clamp_double_to_int64(pow(2.0, 63.0))); tt_i64_op(INT64_MAX, ==, clamp_double_to_int64(pow(2.0, 64.0))); - tt_i64_op(INT64_MAX, ==, clamp_double_to_int64(INFINITY)); + tt_i64_op(INT64_MAX, ==, clamp_double_to_int64(INFINITY_DBL)); done: ; @@ -4507,25 +5114,61 @@ test_util_socket(void *arg) tt_int_op(fd_is_nonblocking(fd4), OP_EQ, 1); #endif - tor_close_socket(fd1); - tor_close_socket(fd2); + tor_assert(tor_close_socket == tor_close_socket__real); + + /* we use close_socket__real here so that coverity can tell that we are + * really closing these sockets. */ + tor_close_socket__real(fd1); + tor_close_socket__real(fd2); fd1 = fd2 = TOR_INVALID_SOCKET; tt_int_op(get_n_open_sockets(), OP_EQ, n + 2); - tor_close_socket(fd3); - tor_close_socket(fd4); + tor_close_socket__real(fd3); + tor_close_socket__real(fd4); fd3 = fd4 = TOR_INVALID_SOCKET; tt_int_op(get_n_open_sockets(), OP_EQ, n); done: if (SOCKET_OK(fd1)) - tor_close_socket(fd1); + tor_close_socket__real(fd1); if (SOCKET_OK(fd2)) - tor_close_socket(fd2); + tor_close_socket__real(fd2); if (SOCKET_OK(fd3)) - tor_close_socket(fd3); + tor_close_socket__real(fd3); if (SOCKET_OK(fd4)) - tor_close_socket(fd4); + tor_close_socket__real(fd4); +} + +#if 0 +static int +is_there_a_localhost(int family) +{ + tor_socket_t s; + s = tor_open_socket(family, SOCK_STREAM, IPPROTO_TCP); + tor_assert(SOCKET_OK(s)); + + int result = 0; + if (family == AF_INET) { + struct sockaddr_in s_in; + memset(&s_in, 0, sizeof(s_in)); + s_in.sin_family = AF_INET; + s_in.sin_addr.s_addr = htonl(0x7f000001); + s_in.sin_port = 0; + + if (bind(s, (void*)&s_in, sizeof(s_in)) == 0) { + result = 1; + } + } else if (family == AF_INET6) { + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr.s6_addr[15] = 1; + sin6.sin6_port = 0; + } + tor_close_socket(s); + + return result; } +#endif /* Test for socketpair and ersatz_socketpair(). We test them both, since * the latter is a tolerably good way to exersize tor_accept_socket(). */ @@ -4541,15 +5184,18 @@ test_util_socketpair(void *arg) int socketpair_result = 0; socketpair_result = tor_socketpair_fn(family, SOCK_STREAM, 0, fds); - /* If there is no 127.0.0.1 or ::1, tor_ersatz_socketpair will and must fail. + +#ifdef __FreeBSD__ + /* If there is no 127.0.0.1, tor_ersatz_socketpair will and must fail. * Otherwise, we risk exposing a socketpair on a routable IP address. (Some * BSD jails use a routable address for localhost. Fortunately, they have * the real AF_UNIX socketpair.) */ - if (ersatz && ERRNO_IS_EPROTO(-socketpair_result)) { + if (ersatz && socketpair_result < 0) { /* In my testing, an IPv6-only FreeBSD jail without ::1 returned EINVAL. * Assume we're on a machine without 127.0.0.1 or ::1 and give up now. */ - goto done; + tt_skip(); } +#endif tt_int_op(0, OP_EQ, socketpair_result); tt_assert(SOCKET_OK(fds[0])); @@ -4780,12 +5426,203 @@ test_util_pwdb(void *arg) dir = get_user_homedir(name); tt_assert(dir != NULL); + /* Try failing cases. First find a user that doesn't exist by name */ + char randbytes[4]; + char badname[9]; + int i, found=0; + for (i = 0; i < 100; ++i) { + crypto_rand(randbytes, sizeof(randbytes)); + base16_encode(badname, sizeof(badname), randbytes, sizeof(randbytes)); + if (tor_getpwnam(badname) == NULL) { + found = 1; + break; + } + } + tt_assert(found); + tor_free(dir); + + /* We should do a LOG_ERR */ + setup_full_capture_of_logs(LOG_ERR); + dir = get_user_homedir(badname); + tt_assert(dir == NULL); + expect_log_msg_containing("not found"); + tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1); + teardown_capture_of_logs(); + + /* Now try to find a user that doesn't exist by ID. */ + found = 0; + for (i = 0; i < 1000; ++i) { + uid_t u; + crypto_rand((char*)&u, sizeof(u)); + if (tor_getpwuid(u) == NULL) { + found = 1; + break; + } + } + tt_assert(found); + done: tor_free(name); tor_free(dir); + teardown_capture_of_logs(); } #endif +static void +test_util_calloc_check(void *arg) +{ + (void) arg; + /* Easy cases that are good. */ + tt_assert(size_mul_check__(0,0)); + tt_assert(size_mul_check__(0,100)); + tt_assert(size_mul_check__(100,0)); + tt_assert(size_mul_check__(100,100)); + + /* Harder cases that are still good. */ + tt_assert(size_mul_check__(SIZE_MAX, 1)); + tt_assert(size_mul_check__(1, SIZE_MAX)); + tt_assert(size_mul_check__(SIZE_MAX / 10, 9)); + tt_assert(size_mul_check__(11, SIZE_MAX / 12)); + const size_t sqrt_size_max_p1 = ((size_t)1) << (sizeof(size_t) * 4); + tt_assert(size_mul_check__(sqrt_size_max_p1, sqrt_size_max_p1 - 1)); + + /* Cases that overflow */ + tt_assert(! size_mul_check__(SIZE_MAX, 2)); + tt_assert(! size_mul_check__(2, SIZE_MAX)); + tt_assert(! size_mul_check__(SIZE_MAX / 10, 11)); + tt_assert(! size_mul_check__(11, SIZE_MAX / 10)); + tt_assert(! size_mul_check__(SIZE_MAX / 8, 9)); + tt_assert(! size_mul_check__(sqrt_size_max_p1, sqrt_size_max_p1)); + + done: + ; +} + +static void +test_util_monotonic_time(void *arg) +{ + (void)arg; + + monotime_t mt1, mt2; + monotime_coarse_t mtc1, mtc2; + uint64_t nsec1, nsec2, usec1, msec1; + uint64_t nsecc1, nsecc2, usecc1, msecc1; + + monotime_init(); + + monotime_get(&mt1); + monotime_coarse_get(&mtc1); + nsec1 = monotime_absolute_nsec(); + usec1 = monotime_absolute_usec(); + msec1 = monotime_absolute_msec(); + nsecc1 = monotime_coarse_absolute_nsec(); + usecc1 = monotime_coarse_absolute_usec(); + msecc1 = monotime_coarse_absolute_msec(); + + tor_sleep_msec(200); + + monotime_get(&mt2); + monotime_coarse_get(&mtc2); + nsec2 = monotime_absolute_nsec(); + nsecc2 = monotime_coarse_absolute_nsec(); + + /* We need to be a little careful here since we don't know the system load. + */ + tt_i64_op(monotime_diff_msec(&mt1, &mt2), OP_GE, 175); + tt_i64_op(monotime_diff_msec(&mt1, &mt2), OP_LT, 1000); + tt_i64_op(monotime_coarse_diff_msec(&mtc1, &mtc2), OP_GE, 125); + tt_i64_op(monotime_coarse_diff_msec(&mtc1, &mtc2), OP_LT, 1000); + tt_u64_op(nsec2-nsec1, OP_GE, 175000000); + tt_u64_op(nsec2-nsec1, OP_LT, 1000000000); + tt_u64_op(nsecc2-nsecc1, OP_GE, 125000000); + tt_u64_op(nsecc2-nsecc1, OP_LT, 1000000000); + + tt_u64_op(msec1, OP_GE, nsec1 / 1000000); + tt_u64_op(usec1, OP_GE, nsec1 / 1000); + tt_u64_op(msecc1, OP_GE, nsecc1 / 1000000); + tt_u64_op(usecc1, OP_GE, nsecc1 / 1000); + tt_u64_op(msec1, OP_LE, nsec1 / 1000000 + 1); + tt_u64_op(usec1, OP_LE, nsec1 / 1000 + 1000); + tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 1); + tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 1000); + + done: + ; +} + +static void +test_util_monotonic_time_ratchet(void *arg) +{ + (void)arg; + monotime_init(); + monotime_reset_ratchets_for_testing(); + + /* win32, performance counter ratchet. */ + tt_i64_op(100, OP_EQ, ratchet_performance_counter(100)); + tt_i64_op(101, OP_EQ, ratchet_performance_counter(101)); + tt_i64_op(2000, OP_EQ, ratchet_performance_counter(2000)); + tt_i64_op(2000, OP_EQ, ratchet_performance_counter(100)); + tt_i64_op(2005, OP_EQ, ratchet_performance_counter(105)); + tt_i64_op(3005, OP_EQ, ratchet_performance_counter(1105)); + tt_i64_op(3005, OP_EQ, ratchet_performance_counter(1000)); + tt_i64_op(3010, OP_EQ, ratchet_performance_counter(1005)); + + /* win32, GetTickCounts32 ratchet-and-rollover-detector. */ + const int64_t R = ((int64_t)1) << 32; + tt_i64_op(5, OP_EQ, ratchet_coarse_performance_counter(5)); + tt_i64_op(1000, OP_EQ, ratchet_coarse_performance_counter(1000)); + tt_i64_op(5+R, OP_EQ, ratchet_coarse_performance_counter(5)); + tt_i64_op(10+R, OP_EQ, ratchet_coarse_performance_counter(10)); + tt_i64_op(4+R*2, OP_EQ, ratchet_coarse_performance_counter(4)); + + /* gettimeofday regular ratchet. */ + struct timeval tv_in = {0,0}, tv_out; + tv_in.tv_usec = 9000; + + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 9000); + tt_i64_op(tv_out.tv_sec, OP_EQ, 0); + + tv_in.tv_sec = 1337; + tv_in.tv_usec = 0; + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 0); + tt_i64_op(tv_out.tv_sec, OP_EQ, 1337); + + tv_in.tv_sec = 1336; + tv_in.tv_usec = 500000; + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 0); + tt_i64_op(tv_out.tv_sec, OP_EQ, 1337); + + tv_in.tv_sec = 1337; + tv_in.tv_usec = 0; + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 500000); + tt_i64_op(tv_out.tv_sec, OP_EQ, 1337); + + tv_in.tv_sec = 1337; + tv_in.tv_usec = 600000; + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 100000); + tt_i64_op(tv_out.tv_sec, OP_EQ, 1338); + + tv_in.tv_sec = 1000; + tv_in.tv_usec = 1000; + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 100000); + tt_i64_op(tv_out.tv_sec, OP_EQ, 1338); + + tv_in.tv_sec = 2000; + tv_in.tv_usec = 2000; + ratchet_timeval(&tv_in, &tv_out); + tt_int_op(tv_out.tv_usec, OP_EQ, 101000); + tt_i64_op(tv_out.tv_sec, OP_EQ, 2338); + + done: + ; +} + #define UTIL_LEGACY(name) \ { #name, test_util_ ## name , 0, NULL, NULL } @@ -4809,17 +5646,20 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(config_line_quotes), UTIL_LEGACY(config_line_comment_character), UTIL_LEGACY(config_line_escaped_content), + UTIL_LEGACY(config_line_crlf), UTIL_LEGACY_NO_WIN(expand_filename), UTIL_LEGACY(escape_string_socks), UTIL_LEGACY(string_is_key_value), UTIL_LEGACY(strmisc), + UTIL_TEST(parse_integer, 0), UTIL_LEGACY(pow2), UTIL_LEGACY(gzip), + UTIL_TEST(gzip_compression_bomb, TT_FORK), UTIL_LEGACY(datadir), UTIL_LEGACY(memarea), UTIL_LEGACY(control_formats), UTIL_LEGACY(mmap), - UTIL_LEGACY(sscanf), + UTIL_TEST(sscanf, TT_FORK), UTIL_LEGACY(format_time_interval), UTIL_LEGACY(path_is_relative), UTIL_LEGACY(strtok), @@ -4834,6 +5674,7 @@ struct testcase_t util_tests[] = { UTIL_TEST(listdir, 0), UTIL_TEST(parent_dir, 0), UTIL_TEST(ftruncate, 0), + UTIL_TEST(num_cpus, 0), UTIL_TEST_WIN_ONLY(load_win_lib, 0), UTIL_TEST_NO_WIN(exit_status, 0), UTIL_TEST_NO_WIN(fgets_eagain, 0), @@ -4855,6 +5696,7 @@ struct testcase_t util_tests[] = { UTIL_TEST(read_file_eof_zero_bytes, 0), UTIL_TEST(write_chunks_to_file, 0), UTIL_TEST(mathlog, 0), + UTIL_TEST(fraction, 0), UTIL_TEST(weak_random, 0), { "socket_ipv4", test_util_socket, TT_FORK, &passthrough_setup, (void*)"4" }, @@ -4871,6 +5713,9 @@ struct testcase_t util_tests[] = { UTIL_TEST(get_avail_disk_space, 0), UTIL_TEST(touch_file, 0), UTIL_TEST_NO_WIN(pwdb, TT_FORK), + UTIL_TEST(calloc_check, 0), + UTIL_TEST(monotonic_time, 0), + UTIL_TEST(monotonic_time_ratchet, TT_FORK), END_OF_TESTCASES }; |