diff options
author | Nick Mathewson <nickm@torproject.org> | 2019-03-26 09:39:46 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2019-03-26 09:39:46 -0400 |
commit | f32d8905316e67df25e3ed06e259b57233108ae7 (patch) | |
tree | 489624a70bd0c123da9e234f9eeffada957f667b | |
parent | d11976b8bd4bded2939ff973d7b2beb36c201bf0 (diff) | |
parent | 27f24484d47cbf72bfad5f81280773128da9e3d2 (diff) | |
download | tor-f32d8905316e67df25e3ed06e259b57233108ae7.tar.gz tor-f32d8905316e67df25e3ed06e259b57233108ae7.zip |
Merge branch 'bug29805_rebased_squashed'
-rw-r--r-- | changes/bug29805 | 3 | ||||
-rw-r--r-- | src/lib/math/prob_distr.h | 97 |
2 files changed, 99 insertions, 1 deletions
diff --git a/changes/bug29805 b/changes/bug29805 new file mode 100644 index 0000000000..00c846e9af --- /dev/null +++ b/changes/bug29805 @@ -0,0 +1,3 @@ + o Minor bugfixes (probability distributions): + - Refactor and improve parts of the probability distribution code that made + Coverity complain. Fixes bug 29805; bugfix on 0.4.0.1-alpha.
\ No newline at end of file diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h index 66acb796fd..2eb935e4a8 100644 --- a/src/lib/math/prob_distr.h +++ b/src/lib/math/prob_distr.h @@ -19,10 +19,100 @@ struct dist { const struct dist_ops *ops; }; +/** + * Untyped initializer element for struct dist using the specified + * struct dist_ops pointer. Don't actually use this directly -- use + * the type-specific macro built out of DIST_BASE_TYPED below -- but if + * you did use this directly, it would be something like: + * + * struct weibull mydist = { + * DIST_BASE(&weibull_ops), + * .lambda = ..., + * .k = ..., + * }; + * + * Note there is NO COMPILER FEEDBACK if you accidentally do something + * like + * + * struct geometric mydist = { + * DIST_BASE(&weibull_ops), + * ... + * }; + */ #define DIST_BASE(OPS) { .ops = (OPS) } + +/** A compile-time type-checking macro for use with DIST_BASE_TYPED. + * + * This macro works by checking that &OBJ is a pointer type that is the same + * type (except for qualifiers) as (const TYPE *)&OBJ. It's a C constraint + * violation (which requires a diagnostic) if two pointers are different types + * and are subtracted. The sizeof() forces compile-time evaluation, and the + * multiplication by zero is to discard the result of the sizeof() from the + * expression. + * + * We define this conditionally to suppress false positives from + * Coverity, which gets confused by the sizeof business. + */ +#ifdef __COVERITY___ +#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0 +#else +#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \ + (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ))) +#endif + +/** +* Typed initializer element for struct dist using the specified struct +* dist_ops pointer. Don't actually use this directly -- use a +* type-specific macro built out of it -- but if you did use this +* directly, it would be something like: +* +* struct weibull mydist = { +* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull), +* .lambda = ..., +* .k = ..., +* }; +* +* If you want to define a distribution type, define a canonical set of +* operations and define a type-specific initializer element like so: +* +* struct foo { +* struct dist base; +* int omega; +* double tau; +* double phi; +* }; +* +* struct dist_ops foo_ops = ...; +* +* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo) +* +* Then users can do: +* +* struct foo mydist = { +* FOO(mydist), +* .omega = ..., +* .tau = ..., +* .phi = ..., +* }; +* +* If you accidentally write +* +* struct bar mydist = { +* FOO(mydist), +* ... +* }; +* +* then the compiler will report a type mismatch in the sizeof +* expression, which otherwise evaporates at runtime. +*/ #define DIST_BASE_TYPED(OPS, OBJ, TYPE) \ - DIST_BASE((OPS) + 0*sizeof(&(OBJ) - (const TYPE *)&(OBJ))) + DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE)) +/** + * Generic operations on distributions. These simply defer to the + * corresponding dist_ops function. In the parlance of C++, these call + * virtual member functions. + */ const char *dist_name(const struct dist *); double dist_sample(const struct dist *); double dist_cdf(const struct dist *, double x); @@ -30,6 +120,11 @@ double dist_sf(const struct dist *, double x); double dist_icdf(const struct dist *, double p); double dist_isf(const struct dist *, double p); +/** + * Set of operations on a potentially parametric family of + * distributions. In the parlance of C++, this would be called a + * `vtable' and the members are virtual member functions. + */ struct dist_ops { const char *name; double (*sample)(const struct dist *); |