summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-03-26 09:39:46 -0400
committerNick Mathewson <nickm@torproject.org>2019-03-26 09:39:46 -0400
commitf32d8905316e67df25e3ed06e259b57233108ae7 (patch)
tree489624a70bd0c123da9e234f9eeffada957f667b
parentd11976b8bd4bded2939ff973d7b2beb36c201bf0 (diff)
parent27f24484d47cbf72bfad5f81280773128da9e3d2 (diff)
downloadtor-f32d8905316e67df25e3ed06e259b57233108ae7.tar.gz
tor-f32d8905316e67df25e3ed06e259b57233108ae7.zip
Merge branch 'bug29805_rebased_squashed'
-rw-r--r--changes/bug298053
-rw-r--r--src/lib/math/prob_distr.h97
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 *);