[tor-bugs] #29527 [Core Tor/Tor]: Division by zero: undefined behaviour in circuitpadding/circuitpadding_sample_distribution test

Tor Bug Tracker & Wiki blackhole at torproject.org
Sat Feb 23 02:37:50 UTC 2019


#29527: Division by zero: undefined behaviour in
circuitpadding/circuitpadding_sample_distribution test
-------------------------------------------------+-------------------------
 Reporter:  teor                                 |          Owner:  (none)
     Type:  defect                               |         Status:  new
 Priority:  High                                 |      Milestone:  Tor:
                                                 |  0.4.0.x-final
Component:  Core Tor/Tor                         |        Version:
 Severity:  Normal                               |     Resolution:
 Keywords:  regression, tor-ci, tor-test,        |  Actual Points:
  040-must                                       |
Parent ID:                                       |         Points:
 Reviewer:                                       |        Sponsor:
-------------------------------------------------+-------------------------

Comment (by riastradh):

 Floating-point division by zero isn't undefined behaviour -- it is
 precisely defined in IEEE 754 and has been consistently implemented in
 essentially all software and hardware for decades.  This looks like
 mostly, if not entirely, false positives from a buggy UB sanitizer that's
 confused about floating-point arithmetic.

 All of the cases in test_prob_distr.c appear to be working as intended.
 For example, test_prob_distr.c line 496 invokes `CHECK_RELERR(np,
 cdf_log_logistic(1/x, 1, 1))`.  The log-logistic distribution has the
 property that CDF(1/x) = 1 - CDF(x).  When x is arbitrarily close to 0, 1
 - CDF(x) should be extremely close to 1; when we round x to zero, CDF(x)
 should be 0, 1/x is rounded to infinity, and CDF(1/x) = 1 - CDF(x) should
 be 1, exactly as the test confirms.

 In prob_distr.c:

 - line 344, column 17 is inside logit.  logit(1) should be +inf (lim_{x
 --> 1^-^} logit(x) = +inf), and the +inf yielded by division by zero is
 correctly propagated by the expression log(p/(1 - p)).  The test suite
 specifically checks that logit(1) = +inf (test_prob_distr.c lines 323 and
 395).
 - line 427, column 26 is inside logithalf.  logithalf(1/2) = logit(1)
 should be +inf, and the +inf yielded by division by zero is correctly
 propagated by the expression log((0.5 + p0)/(0.5 - p0)).  The test suite
 specifically checks that logithalf(+/-1/2) = +/-inf (test_prob_distr.c
 lines 294, 323, and 397).
 - line 685, column 27 is inside isf_log_logistic.  The log logistic
 distribution has the property that CDF(1/x) = 1 - CDF(x), which means
 CDF^-1^(1 - p) = SF^-1^(p) = 1/x.  In test_prob_distr.c, line 450
 specifies a test where p = 0, np = 1 - p = 1, and line 553 confirms
 isf_log_logistic(p, 1, 1), which entails dividing by p, correctly gives
 1/x.
 - line 814, column 23 is in cdf_genpareto.  Here we are checking whether
 the approximation 1 - e^-x_0^ is safe for the specified value of xi, which
 we consider it to be if |xi| < 1e-17/x_0.  If x_0 is infinite, we consider
 it safe.  For any xi, as x_0 goes to zero, the CDF goes to zero too, which
 is exactly what the approximation computes, so this is correct.  The test
 case on line 718 of test_prob_distr.c specifies x_0 = 0.  (Side note: It
 appears I wrote no tests with a nonzero mean.  Should maybe add some.)
 - line 837, column 23 is in sf_genpareto, which has the same case analysis
 and test cases as the above instance.
 - line 1170, column 20 is in sample_log_logistic, evaluating the quotient
 in `(1 - p0)/p0`.  This is division by zero only if p0 = 0.  In that case,
 we return the correct answer is +inf, since as p0 -> 0, this function
 grows without bound.  In test_prob_distr.c, lines 565, 567, and 569
 specify tests with p0 = 0.  (However, in actual runs of the code with p0
 drawn using `random_uniform_01`, p0 = 0 should happen only with
 probability 2^-1075^, i.e. never.)
 - line 1311, column 17 is inside sample_geometric, evaluating the quotient
 in `-x/log1p(-p)`.  The divisor can be zero only if p = 0, which means
 we're trying to sample from a geometric distribution with zero success
 probability.  Of course, the only reasonable result is +inf.  **Is there
 anything _upstream_ of this logic that tries to construct a
 `CIRCPAD_DIST_GEOMETRIC` with zero success probability?**
 - line 1219, column 49 is inside sample_weibull, computing `1/k`.  This
 can happen only if k = 0, which is an edge case that's probably not very
 useful, but the expression does return +inf which is the correct limit as
 k --> 0.  **Is there anything upstream of this logic that tries to
 construct a `CIRCPAD_DIST_WEIBULL` with zero shape?**

 By the way, pretty much all non-arm hardware supports a kind of
 ‘sanitizer’ for floating-point invalid operations (which are not undefined
 behaviour, but are usually undesirable) with zero overhead if they don't
 happen, namely trapping the invalid-operation exception, which Unix will
 translate to SIGFPE.  (Most arm hardware supports the exception, but only
 via sticky bits you can explicitly test with `fetestexcept`, not via
 trapping.)

 I tried running the tests with tinytest.c modified to do
 `feenableexcept(FE_INVALID)` first thing in tinytest_main (needs `#define
 _GNU_SOURCE` and `#include <fenv.h>`).  This turned up only one invalid
 operation in the tests: the logsumexp in test_stochastic_geometric_impl
 slightly exceeds zero, so log1mexp performs an invalid operation (log of
 negative); it is safe to replace `log1mexp(logsumexp(...))` here by
 `log1mexp(fmin(0, logsumexp(...)))` to avoid this.

--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/29527#comment:7>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online


More information about the tor-bugs mailing list