summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/address.c2
-rw-r--r--src/common/address.h2
-rw-r--r--src/common/compat.h2
-rw-r--r--src/common/crypto.c179
-rw-r--r--src/common/crypto.h2
-rw-r--r--src/common/crypto_curve25519.c9
-rw-r--r--src/common/crypto_ed25519.c19
-rw-r--r--src/common/crypto_pwbox.c28
-rw-r--r--src/common/crypto_s2k.c8
-rw-r--r--src/common/di_ops.c45
-rw-r--r--src/common/di_ops.h2
-rw-r--r--src/common/handles.h153
-rw-r--r--src/common/include.am54
-rw-r--r--src/common/memarea.c6
-rw-r--r--src/common/pubsub.c129
-rw-r--r--src/common/pubsub.h177
-rw-r--r--src/common/timers.c297
-rw-r--r--src/common/timers.h22
-rw-r--r--src/common/util.c55
-rw-r--r--src/common/util.h42
-rw-r--r--src/common/util_bug.c53
-rw-r--r--src/common/util_bug.h150
22 files changed, 1244 insertions, 192 deletions
diff --git a/src/common/address.c b/src/common/address.c
index 793a40effc..a6e0f3f491 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1172,7 +1172,7 @@ tor_addr_hash(const tor_addr_t *addr)
/** Return a newly allocated string with a representation of <b>addr</b>. */
char *
-tor_dup_addr(const tor_addr_t *addr)
+tor_addr_to_str_dup(const tor_addr_t *addr)
{
char buf[TOR_ADDR_BUF_LEN];
if (tor_addr_to_str(buf, addr, sizeof(buf), 0)) {
diff --git a/src/common/address.h b/src/common/address.h
index 53712bde02..3de67e1c74 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -179,7 +179,7 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
#define TOR_ADDR_BUF_LEN 48
int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out);
-char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
+char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC;
/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6
* addresses. */
diff --git a/src/common/compat.h b/src/common/compat.h
index 8cf84580c6..b6ee4106db 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -430,7 +430,7 @@ typedef int socklen_t;
#ifdef _WIN32
/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that
- * any inadvertant checks for the socket being <= 0 or > 0 will probably
+ * any inadvertent checks for the socket being <= 0 or > 0 will probably
* still work. */
#define tor_socket_t intptr_t
#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 933f1033f7..76e262e257 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -134,7 +134,7 @@ crypto_get_rsa_padding_overhead(int padding)
switch (padding)
{
case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
- default: tor_assert(0); return -1;
+ default: tor_assert(0); return -1; // LCOV_EXCL_LINE
}
}
@@ -146,7 +146,7 @@ crypto_get_rsa_padding(int padding)
switch (padding)
{
case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
- default: tor_assert(0); return -1;
+ default: tor_assert(0); return -1; // LCOV_EXCL_LINE
}
}
@@ -171,13 +171,9 @@ crypto_log_errors(int severity, const char *doing)
if (!msg) msg = "(null)";
if (!lib) lib = "(null)";
if (!func) func = "(null)";
- if (doing) {
- tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
+ if (BUG(!doing)) doing = "(null)";
+ tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
doing, msg, lib, func);
- } else {
- tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)",
- msg, lib, func);
- }
}
}
@@ -944,6 +940,10 @@ crypto_pk_copy_full(crypto_pk_t *env)
new_key = RSAPublicKey_dup(env->key);
}
if (!new_key) {
+ /* LCOV_EXCL_START
+ *
+ * We can't cause RSA*Key_dup() to fail, so we can't really test this.
+ */
log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.",
privatekey?"private":"public");
crypto_log_errors(LOG_ERR,
@@ -951,6 +951,7 @@ crypto_pk_copy_full(crypto_pk_t *env)
"Duplicating a public key");
tor_fragile_assert();
return NULL;
+ /* LCOV_EXCL_STOP */
}
return crypto_new_pk_from_rsa_(new_key);
@@ -1701,8 +1702,10 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg)
case DIGEST_SHA3_512:
return "sha3-512";
default:
+ // LCOV_EXCL_START
tor_fragile_assert();
return "??unknown_digest??";
+ // LCOV_EXCL_STOP
}
}
@@ -1726,7 +1729,7 @@ crypto_digest_algorithm_parse_name(const char *name)
}
/** Given an algorithm, return the digest length in bytes. */
-static inline size_t
+size_t
crypto_digest_algorithm_get_length(digest_algorithm_t alg)
{
switch (alg) {
@@ -1741,8 +1744,8 @@ crypto_digest_algorithm_get_length(digest_algorithm_t alg)
case DIGEST_SHA3_512:
return DIGEST512_LEN;
default:
- tor_assert(0);
- return 0; /* Unreachable */
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; /* Unreachable */ // LCOV_EXCL_LINE
}
}
@@ -1785,23 +1788,53 @@ crypto_digest_alloc_bytes(digest_algorithm_t alg)
case DIGEST_SHA3_512:
return END_OF_FIELD(d.sha3);
default:
- tor_assert(0);
- return 0;
+ tor_assert(0); // LCOV_EXCL_LINE
+ return 0; // LCOV_EXCL_LINE
}
#undef END_OF_FIELD
#undef STRUCT_FIELD_SIZE
}
+/**
+ * Internal function: create and return a new digest object for 'algorithm'.
+ * Does not typecheck the algorithm.
+ */
+static crypto_digest_t *
+crypto_digest_new_internal(digest_algorithm_t algorithm)
+{
+ crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
+ r->algorithm = algorithm;
+
+ switch (algorithm)
+ {
+ case DIGEST_SHA1:
+ SHA1_Init(&r->d.sha1);
+ break;
+ case DIGEST_SHA256:
+ SHA256_Init(&r->d.sha2);
+ break;
+ case DIGEST_SHA512:
+ SHA512_Init(&r->d.sha512);
+ break;
+ case DIGEST_SHA3_256:
+ keccak_digest_init(&r->d.sha3, 256);
+ break;
+ case DIGEST_SHA3_512:
+ keccak_digest_init(&r->d.sha3, 512);
+ break;
+ default:
+ tor_assert_unreached();
+ }
+
+ return r;
+}
+
/** Allocate and return a new digest object to compute SHA1 digests.
*/
crypto_digest_t *
crypto_digest_new(void)
{
- crypto_digest_t *r;
- r = tor_malloc(crypto_digest_alloc_bytes(DIGEST_SHA1));
- SHA1_Init(&r->d.sha1);
- r->algorithm = DIGEST_SHA1;
- return r;
+ return crypto_digest_new_internal(DIGEST_SHA1);
}
/** Allocate and return a new digest object to compute 256-bit digests
@@ -1809,15 +1842,8 @@ crypto_digest_new(void)
crypto_digest_t *
crypto_digest256_new(digest_algorithm_t algorithm)
{
- crypto_digest_t *r;
tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
- r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
- if (algorithm == DIGEST_SHA256)
- SHA256_Init(&r->d.sha2);
- else
- keccak_digest_init(&r->d.sha3, 256);
- r->algorithm = algorithm;
- return r;
+ return crypto_digest_new_internal(algorithm);
}
/** Allocate and return a new digest object to compute 512-bit digests
@@ -1825,15 +1851,8 @@ crypto_digest256_new(digest_algorithm_t algorithm)
crypto_digest_t *
crypto_digest512_new(digest_algorithm_t algorithm)
{
- crypto_digest_t *r;
tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
- r = tor_malloc(crypto_digest_alloc_bytes(algorithm));
- if (algorithm == DIGEST_SHA512)
- SHA512_Init(&r->d.sha512);
- else
- keccak_digest_init(&r->d.sha3, 512);
- r->algorithm = algorithm;
- return r;
+ return crypto_digest_new_internal(algorithm);
}
/** Deallocate a digest object.
@@ -1876,8 +1895,10 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
break;
default:
+ /* LCOV_EXCL_START */
tor_fragile_assert();
break;
+ /* LCOV_EXCL_STOP */
}
}
@@ -1916,13 +1937,15 @@ crypto_digest_get_digest(crypto_digest_t *digest,
case DIGEST_SHA512:
SHA512_Final(r, &tmpenv.d.sha512);
break;
+//LCOV_EXCL_START
case DIGEST_SHA3_256: /* FALLSTHROUGH */
case DIGEST_SHA3_512:
- log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
- tor_assert(0); /* This is fatal, because it should never happen. */
default:
- tor_assert(0); /* Unreachable. */
+ log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
+ /* This is fatal, because it should never happen. */
+ tor_assert_unreached();
break;
+//LCOV_EXCL_STOP
}
memcpy(out, r, out_len);
memwipe(r, 0, sizeof(r));
@@ -1981,27 +2004,7 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
const char *append,
digest_algorithm_t alg)
{
- crypto_digest_t *d = NULL;
- switch (alg) {
- case DIGEST_SHA1:
- d = crypto_digest_new();
- break;
- case DIGEST_SHA256: /* FALLSTHROUGH */
- case DIGEST_SHA3_256:
- d = crypto_digest256_new(alg);
- break;
- case DIGEST_SHA512: /* FALLSTHROUGH */
- case DIGEST_SHA3_512:
- d = crypto_digest512_new(alg);
- break;
- default:
- log_warn(LD_BUG, "Called with unknown algorithm %d", alg);
- /* If fragile_assert is not enabled, wipe output and return
- * without running any calculations */
- memwipe(digest_out, 0xff, len_out);
- tor_fragile_assert();
- goto free;
- }
+ crypto_digest_t *d = crypto_digest_new_internal(alg);
if (prepend)
crypto_digest_add_bytes(d, prepend, strlen(prepend));
SMARTLIST_FOREACH(lst, const char *, cp,
@@ -2009,8 +2012,6 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
if (append)
crypto_digest_add_bytes(d, append, strlen(append));
crypto_digest_get_digest(d, digest_out, len_out);
-
- free:
crypto_digest_free(d);
}
@@ -2169,9 +2170,14 @@ crypto_set_tls_dh_prime(void)
int r;
/* If the space is occupied, free the previous TLS DH prime */
- if (dh_param_p_tls) {
+ if (BUG(dh_param_p_tls)) {
+ /* LCOV_EXCL_START
+ *
+ * We shouldn't be calling this twice.
+ */
BN_clear_free(dh_param_p_tls);
dh_param_p_tls = NULL;
+ /* LCOV_EXCL_STOP */
}
tls_prime = BN_new();
@@ -2203,8 +2209,8 @@ init_dh_param(void)
{
BIGNUM *circuit_dh_prime;
int r;
- if (dh_param_p && dh_param_g)
- return;
+ if (BUG(dh_param_p && dh_param_g))
+ return; // LCOV_EXCL_LINE This function isn't supposed to be called twice.
circuit_dh_prime = BN_new();
tor_assert(circuit_dh_prime);
@@ -2269,10 +2275,13 @@ crypto_dh_new(int dh_type)
return res;
err:
+ /* LCOV_EXCL_START
+ * This error condition is only reached when an allocation fails */
crypto_log_errors(LOG_WARN, "creating DH object");
if (res->dh) DH_free(res->dh); /* frees p and g too */
tor_free(res);
return NULL;
+ /* LCOV_EXCL_STOP */
}
/** Return a copy of <b>dh</b>, sharing its internal state. */
@@ -2304,10 +2313,15 @@ crypto_dh_generate_public(crypto_dh_t *dh)
{
again:
if (!DH_generate_key(dh->dh)) {
+ /* LCOV_EXCL_START
+ * To test this we would need some way to tell openssl to break DH. */
crypto_log_errors(LOG_WARN, "generating DH key");
return -1;
+ /* LCOV_EXCL_STOP */
}
if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) {
+ /* LCOV_EXCL_START
+ * If this happens, then openssl's DH implementation is busted. */
log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-"
"the-universe chances really do happen. Trying again.");
/* Free and clear the keys, so OpenSSL will actually try again. */
@@ -2315,6 +2329,7 @@ crypto_dh_generate_public(crypto_dh_t *dh)
BN_clear_free(dh->dh->priv_key);
dh->dh->pub_key = dh->dh->priv_key = NULL;
goto again;
+ /* LCOV_EXCL_STOP */
}
return 0;
}
@@ -2361,8 +2376,8 @@ tor_check_dh_key(int severity, BIGNUM *bn)
tor_assert(bn);
x = BN_new();
tor_assert(x);
- if (!dh_param_p)
- init_dh_param();
+ if (BUG(!dh_param_p))
+ init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this.
BN_set_word(x, 1);
if (BN_cmp(bn,x)<=0) {
log_fn(severity, LD_CRYPTO, "DH key must be at least 2.");
@@ -2384,8 +2399,6 @@ tor_check_dh_key(int severity, BIGNUM *bn)
return -1;
}
-#undef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
/** Given a DH key exchange object, and our peer's value of g^y (as a
* <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate
* <b>secret_bytes_out</b> bytes of shared key material and write them
@@ -2573,6 +2586,11 @@ crypto_seed_weak_rng(tor_weak_rng_t *rng)
tor_init_weak_random(rng, seed);
}
+#ifdef TOR_UNIT_TESTS
+int break_strongest_rng_syscall = 0;
+int break_strongest_rng_fallback = 0;
+#endif
+
/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
* via system calls, storing it into <b>out</b>. Return 0 on success, -1 on
* failure. A maximum request size of 256 bytes is imposed.
@@ -2582,6 +2600,11 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
{
tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE);
+#ifdef TOR_UNIT_TESTS
+ if (break_strongest_rng_syscall)
+ return -1;
+#endif
+
#if defined(_WIN32)
static int provider_set = 0;
static HCRYPTPROV provider;
@@ -2631,6 +2654,7 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
} while (ret == -1 && ((errno == EINTR) ||(errno == EAGAIN)));
if (PREDICT_UNLIKELY(ret == -1)) {
+ /* LCOV_EXCL_START we can't actually make the syscall fail in testing. */
tor_assert(errno != EAGAIN);
tor_assert(errno != EINTR);
@@ -2638,6 +2662,7 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
log_warn(LD_CRYPTO, "Can't get entropy from getrandom().");
getrandom_works = 0; /* Don't bother trying again. */
return -1;
+ /* LCOV_EXCL_STOP */
}
tor_assert(ret == (long)out_len);
@@ -2666,6 +2691,11 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
static int
crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
{
+#ifdef TOR_UNIT_TESTS
+ if (break_strongest_rng_fallback)
+ return -1;
+#endif
+
#ifdef _WIN32
/* Windows exclusively uses crypto_strongest_rand_syscall(). */
(void)out;
@@ -2686,10 +2716,13 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
n = read_all(fd, (char*)out, out_len, 0);
close(fd);
if (n != out_len) {
+ /* LCOV_EXCL_START
+ * We can't make /dev/foorandom actually fail. */
log_warn(LD_CRYPTO,
"Error reading from entropy source (read only %lu bytes).",
(unsigned long)n);
return -1;
+ /* LCOV_EXCL_STOP */
}
return 0;
@@ -2703,7 +2736,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len)
* storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum
* request size of 256 bytes is imposed.
*/
-static int
+STATIC int
crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
{
static const size_t sanity_min_size = 16;
@@ -2737,13 +2770,17 @@ crypto_strongest_rand_raw(uint8_t *out, size_t out_len)
return 0;
}
- /* We tried max_attempts times to fill a buffer >= 128 bits long,
+ /* LCOV_EXCL_START
+ *
+ * We tried max_attempts times to fill a buffer >= 128 bits long,
* and each time it returned all '0's. Either the system entropy
* source is busted, or the user should go out and buy a ticket to
* every lottery on the planet.
*/
log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer.");
+
return -1;
+ /* LCOV_EXCL_STOP */
}
/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
@@ -2762,10 +2799,12 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
while (out_len) {
crypto_rand((char*) inp, DLEN);
if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) {
+ // LCOV_EXCL_START
log_err(LD_CRYPTO, "Failed to load strong entropy when generating an "
"important key. Exiting.");
/* Die with an assertion so we get a stack trace. */
tor_assert(0);
+ // LCOV_EXCL_STOP
}
if (out_len >= DLEN) {
SHA512(inp, sizeof(inp), out);
@@ -2796,7 +2835,7 @@ crypto_seed_rng(void)
* functions. If one succeeds, we'll accept the RNG as seeded. */
rand_poll_ok = RAND_poll();
if (rand_poll_ok == 0)
- log_warn(LD_CRYPTO, "RAND_poll() failed.");
+ log_warn(LD_CRYPTO, "RAND_poll() failed."); // LCOV_EXCL_LINE
load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf));
if (load_entropy_ok) {
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 682c4e3253..ff38cca0da 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -233,6 +233,7 @@ void crypto_digest_smartlist(char *digest_out, size_t len_out,
const struct smartlist_t *lst, const char *append,
digest_algorithm_t alg);
const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
+size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg);
int crypto_digest_algorithm_parse_name(const char *name);
crypto_digest_t *crypto_digest_new(void);
crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm);
@@ -317,6 +318,7 @@ void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
#ifdef CRYPTO_PRIVATE
STATIC int crypto_force_rand_ssleay(void);
+STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len);
#endif
#endif
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
index 57c878b79a..58ec923638 100644
--- a/src/common/crypto_curve25519.c
+++ b/src/common/crypto_curve25519.c
@@ -65,8 +65,10 @@ STATIC int
curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret)
{
int r = 0;
- if (PREDICT_UNLIKELY(curve25519_use_ed == -1)) {
+ if (BUG(curve25519_use_ed == -1)) {
+ /* LCOV_EXCL_START - Only reached if we forgot to call curve25519_init() */
pick_curve25519_basepoint_impl();
+ /* LCOV_EXCL_STOP */
}
/* TODO: Someone should benchmark curved25519_scalarmult_basepoint versus
@@ -290,10 +292,13 @@ pick_curve25519_basepoint_impl(void)
if (curve25519_basepoint_spot_check() == 0)
return;
- log_warn(LD_CRYPTO, "The ed25519-based curve25519 basepoint "
+ /* LCOV_EXCL_START
+ * only reachable if our basepoint implementation broken */
+ log_warn(LD_BUG|LD_CRYPTO, "The ed25519-based curve25519 basepoint "
"multiplication seems broken; using the curve25519 "
"implementation.");
curve25519_use_ed = 0;
+ /* LCOV_EXCL_STOP */
}
/** Initialize the curve25519 implementations. This is necessary if you're
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index ea2d8e3892..84c3eece6d 100644
--- a/src/common/crypto_ed25519.c
+++ b/src/common/crypto_ed25519.c
@@ -94,8 +94,8 @@ static const ed25519_impl_t *ed25519_impl = NULL;
static inline const ed25519_impl_t *
get_ed_impl(void)
{
- if (PREDICT_UNLIKELY(ed25519_impl == NULL)) {
- pick_ed25519_impl();
+ if (BUG(ed25519_impl == NULL)) {
+ pick_ed25519_impl(); // LCOV_EXCL_LINE - We always call ed25519_init().
}
return ed25519_impl;
}
@@ -259,11 +259,11 @@ ed25519_checksig_batch(int *okay_out,
int *oks;
int all_ok;
- ms = tor_malloc(sizeof(uint8_t*)*n_checkable);
- lens = tor_malloc(sizeof(size_t)*n_checkable);
- pks = tor_malloc(sizeof(uint8_t*)*n_checkable);
- sigs = tor_malloc(sizeof(uint8_t*)*n_checkable);
- oks = okay_out ? okay_out : tor_malloc(sizeof(int)*n_checkable);
+ ms = tor_calloc(n_checkable, sizeof(uint8_t*));
+ lens = tor_calloc(n_checkable, sizeof(size_t));
+ pks = tor_calloc(n_checkable, sizeof(uint8_t*));
+ sigs = tor_calloc(n_checkable, sizeof(uint8_t*));
+ oks = okay_out ? okay_out : tor_calloc(n_checkable, sizeof(int));
for (i = 0; i < n_checkable; ++i) {
ms[i] = checkable[i].msg;
@@ -433,6 +433,7 @@ ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out,
errno = EINVAL;
}
+ tor_free(*tag_out);
return -1;
}
@@ -472,6 +473,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
errno = EINVAL;
}
+ tor_free(*tag_out);
return -1;
}
@@ -594,9 +596,12 @@ pick_ed25519_impl(void)
if (ed25519_impl_spot_check() == 0)
return;
+ /* LCOV_EXCL_START
+ * unreachable unless ed25519_donna is broken */
log_warn(LD_CRYPTO, "The Ed25519-donna implementation seems broken; using "
"the ref10 implementation.");
ed25519_impl = &impl_ref10;
+ /* LCOV_EXCL_STOP */
}
/* Initialize the Ed25519 implementation. This is neccessary if you're
diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c
index 819dc0c39d..31e37c007d 100644
--- a/src/common/crypto_pwbox.c
+++ b/src/common/crypto_pwbox.c
@@ -61,7 +61,7 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
pwbox_encoded_getarray_skey_header(enc),
S2K_MAXLEN,
s2k_flags);
- if (spec_len < 0 || spec_len > S2K_MAXLEN)
+ if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN))
goto err;
pwbox_encoded_setlen_skey_header(enc, spec_len);
enc->header_len = spec_len;
@@ -76,10 +76,11 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
/* Now that all the data is in position, derive some keys, encrypt, and
* digest */
- if (secret_to_key_derivekey(keys, sizeof(keys),
+ const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys),
pwbox_encoded_getarray_skey_header(enc),
spec_len,
- secret, secret_len) < 0)
+ secret, secret_len);
+ if (BUG(s2k_rv < 0))
goto err;
cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
@@ -87,11 +88,11 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
crypto_cipher_free(cipher);
result_len = pwbox_encoded_encoded_len(enc);
- if (result_len < 0)
+ if (BUG(result_len < 0))
goto err;
result = tor_malloc(result_len);
enc_len = pwbox_encoded_encode(result, result_len, enc);
- if (enc_len < 0)
+ if (BUG(enc_len < 0))
goto err;
tor_assert(enc_len == result_len);
@@ -107,9 +108,24 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
goto out;
err:
+ /* LCOV_EXCL_START
+
+ This error case is often unreachable if we're correctly coded, unless
+ somebody adds a new error case somewhere, or unless you're building
+ without scrypto support.
+
+ - make_specifier can't fail, unless S2K_MAX_LEN is too short.
+ - secret_to_key_derivekey can't really fail unless we're missing
+ scrypt, or the underlying function fails, or we pass it a bogus
+ algorithm or parameters.
+ - pwbox_encoded_encoded_len can't fail unless we're using trunnel
+ incorrectly.
+ - pwbox_encoded_encode can't fail unless we're using trunnel wrong,
+ or it's buggy.
+ */
tor_free(result);
rv = -1;
-
+ /* LCOV_EXCL_STOP */
out:
pwbox_encoded_free(enc);
memwipe(keys, 0, sizeof(keys));
diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c
index a9140c7553..850a9632ca 100644
--- a/src/common/crypto_s2k.c
+++ b/src/common/crypto_s2k.c
@@ -57,7 +57,8 @@
#define SCRYPT_KEY_LEN 32
/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the
- * specifier part of it, without the prefix type byte. */
+ * specifier part of it, without the prefix type byte. Return -1 if it is not
+ * a valid algorithm ID. */
static int
secret_to_key_spec_len(uint8_t type)
{
@@ -86,7 +87,8 @@ secret_to_key_key_len(uint8_t type)
case S2K_TYPE_SCRYPT:
return DIGEST256_LEN;
default:
- return -1;
+ tor_fragile_assert(); // LCOV_EXCL_LINE
+ return -1; // LCOV_EXCL_LINE
}
}
@@ -168,7 +170,7 @@ make_specifier(uint8_t *spec_out, uint8_t type, unsigned flags)
spec_out[SCRYPT_SPEC_LEN-1] = (3u << 4) | (1u << 0);
break;
default:
- tor_fragile_assert();
+ tor_fragile_assert(); // LCOV_EXCL_LINE - we should have returned above.
return S2K_BAD_ALGORITHM;
}
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index 5dfe828066..e671af6fac 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -226,3 +226,48 @@ safe_mem_is_zero(const void *mem, size_t sz)
return 1 & ((total - 1) >> 8);
}
+/** Time-invariant 64-bit greater-than; works on two integers in the range
+ * (0,INT64_MAX). */
+#if SIZEOF_VOID_P == 8
+#define gt_i64_timei(a,b) ((a) > (b))
+#else
+static inline int
+gt_i64_timei(uint64_t a, uint64_t b)
+{
+ int64_t diff = (int64_t) (b - a);
+ int res = diff >> 63;
+ return res & 1;
+}
+#endif
+
+/**
+ * Given an array of list of <b>n_entries</b> uint64_t values, whose sum is
+ * <b>total</b>, find the first i such that the total of all elements 0...i is
+ * greater than rand_val.
+ *
+ * Try to perform this operation in a constant-time way.
+ */
+int
+select_array_member_cumulative_timei(const uint64_t *entries, int n_entries,
+ uint64_t total, uint64_t rand_val)
+{
+ int i, i_chosen=-1, n_chosen=0;
+ uint64_t total_so_far = 0;
+
+ for (i = 0; i < n_entries; ++i) {
+ total_so_far += entries[i];
+ if (gt_i64_timei(total_so_far, rand_val)) {
+ i_chosen = i;
+ n_chosen++;
+ /* Set rand_val to INT64_MAX rather than stopping the loop. This way,
+ * the time we spend in the loop does not leak which element we chose. */
+ rand_val = INT64_MAX;
+ }
+ }
+ tor_assert(total_so_far == total);
+ tor_assert(n_chosen == 1);
+ tor_assert(i_chosen >= 0);
+ tor_assert(i_chosen < n_entries);
+
+ return i_chosen;
+}
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index 6e77b5cfd7..f1050a00db 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -42,6 +42,8 @@ void dimap_add_entry(di_digest256_map_t **map,
const uint8_t *key, void *val);
void *dimap_search(const di_digest256_map_t *map, const uint8_t *key,
void *dflt_val);
+int select_array_member_cumulative_timei(const uint64_t *entries, int n_entries,
+ uint64_t total, uint64_t rand_val);
#endif
diff --git a/src/common/handles.h b/src/common/handles.h
new file mode 100644
index 0000000000..1ee2322579
--- /dev/null
+++ b/src/common/handles.h
@@ -0,0 +1,153 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file handles.h
+ * \brief Macros for C weak-handle implementation.
+ *
+ * A 'handle' is a pointer to an object that is allowed to go away while
+ * the handle stays alive. When you dereference the handle, you might get
+ * the object, or you might get "NULL".
+ *
+ * Use this pattern when an object has a single obvious lifespan, so you don't
+ * want to use reference counting, but when other objects might need to refer
+ * to the first object without caring about its lifetime.
+ *
+ * To enable a type to have handles, add a HANDLE_ENTRY() field in its
+ * definition, as in:
+ *
+ * struct walrus {
+ * HANDLE_ENTRY(wlr, walrus);
+ * // ...
+ * };
+ *
+ * And invoke HANDLE_DECL(wlr, walrus, [static]) to declare the handle
+ * manipulation functions (typically in a header):
+ *
+ * // opaque handle to walrus.
+ * typedef struct wlr_handle_t wlr_handle_t;
+ *
+ * // make a new handle
+ * struct wlr_handle_t *wlr_handle_new(struct walrus *);
+ *
+ * // release a handle
+ * void wlr_handle_free(wlr_handle_t *);
+ *
+ * // return the pointed-to walrus, or NULL.
+ * struct walrus *wlr_handle_get(wlr_handle_t *).
+ *
+ * // call this function when you're about to free the walrus;
+ * // it invalidates all handles. (IF YOU DON'T, YOU WILL HAVE
+ * // DANGLING REFERENCES)
+ * void wlr_handles_clear(struct walrus *);
+ *
+ * Finally, use HANDLE_IMPL() to define the above functions in some
+ * appropriate C file: HANDLE_IMPL(wlr, walrus, [static])
+ *
+ **/
+
+#ifndef TOR_HANDLE_H
+#define TOR_HANDLE_H
+
+#include "orconfig.h"
+#include "tor_queue.h"
+#include "util.h"
+
+#define HANDLE_ENTRY(name, structname) \
+ struct name ## _handle_head_t *handle_head
+
+#define HANDLE_DECL(name, structname, linkage) \
+ typedef struct name ## _handle_t name ## _handle_t; \
+ linkage name ## _handle_t *name ## _handle_new(struct structname *object); \
+ linkage void name ## _handle_free(name ## _handle_t *); \
+ linkage struct structname *name ## _handle_get(name ## _handle_t *); \
+ linkage void name ## _handles_clear(struct structname *object);
+
+/*
+ * Implementation notes: there are lots of possible implementations here. We
+ * could keep a linked list of handles, each with a backpointer to the object,
+ * and set all of their backpointers to NULL when the object is freed. Or we
+ * could have the clear function invalidate the object, but not actually let
+ * the object get freed until the all the handles went away. We could even
+ * have a hash-table mapping unique identifiers to objects, and have each
+ * handle be a copy of the unique identifier. (We'll want to build that last
+ * one eventually if we want cross-process handles.)
+ *
+ * But instead we're opting for a single independent 'head' that knows how
+ * many handles there are, and where the object is (or isn't). This makes
+ * all of our functions O(1), and most as fast as a single pointer access.
+ *
+ * The handles themselves are opaque structures holding a pointer to the head.
+ * We could instead have each foo_handle_t* be identical to foo_handle_head_t
+ * *, and save some allocations ... but doing so would make handle leaks
+ * harder to debug. As it stands, every handle leak is a memory leak, and
+ * existing memory debugging tools should help with those. We can revisit
+ * this decision if handles are too slow.
+ */
+
+#define HANDLE_IMPL(name, structname, linkage) \
+ /* The 'head' object for a handle-accessible type. This object */ \
+ /* persists for as long as the object, or any handles, exist. */ \
+ typedef struct name ## _handle_head_t { \
+ struct structname *object; /* pointed-to object, or NULL */ \
+ unsigned int references; /* number of existing handles */ \
+ } name ## _handle_head_t; \
+ \
+ struct name ## _handle_t { \
+ struct name ## _handle_head_t *head; /* reference to the 'head'. */ \
+ }; \
+ \
+ linkage struct name ## _handle_t * \
+ name ## _handle_new(struct structname *object) \
+ { \
+ tor_assert(object); \
+ name ## _handle_head_t *head = object->handle_head; \
+ if (PREDICT_UNLIKELY(head == NULL)) { \
+ head = object->handle_head = tor_malloc_zero(sizeof(*head)); \
+ head->object = object; \
+ } \
+ name ## _handle_t *new_ref = tor_malloc_zero(sizeof(*new_ref)); \
+ new_ref->head = head; \
+ ++head->references; \
+ return new_ref; \
+ } \
+ \
+ linkage void \
+ name ## _handle_free(struct name ## _handle_t *ref) \
+ { \
+ if (! ref) return; \
+ name ## _handle_head_t *head = ref->head; \
+ tor_assert(head); \
+ --head->references; \
+ tor_free(ref); \
+ if (head->object == NULL && head->references == 0) { \
+ tor_free(head); \
+ return; \
+ } \
+ } \
+ \
+ linkage struct structname * \
+ name ## _handle_get(struct name ## _handle_t *ref) \
+ { \
+ tor_assert(ref); \
+ name ## _handle_head_t *head = ref->head; \
+ tor_assert(head); \
+ return head->object; \
+ } \
+ \
+ linkage void \
+ name ## _handles_clear(struct structname *object) \
+ { \
+ tor_assert(object); \
+ name ## _handle_head_t *head = object->handle_head; \
+ if (! head) \
+ return; \
+ object->handle_head = NULL; \
+ head->object = NULL; \
+ if (head->references == 0) { \
+ tor_free(head); \
+ } \
+ }
+
+#endif /* TOR_HANDLE_H */
+
diff --git a/src/common/include.am b/src/common/include.am
index 5afb30da6a..222afe0291 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -1,12 +1,14 @@
noinst_LIBRARIES += \
src/common/libor.a \
+ src/common/libor-ctime.a \
src/common/libor-crypto.a \
src/common/libor-event.a
if UNITTESTS_ENABLED
noinst_LIBRARIES += \
src/common/libor-testing.a \
+ src/common/libor-ctime-testing.a \
src/common/libor-crypto-testing.a \
src/common/libor-event-testing.a
endif
@@ -27,12 +29,14 @@ src_common_libcurve25519_donna_a_CFLAGS=
if BUILD_CURVE25519_DONNA
src_common_libcurve25519_donna_a_SOURCES=\
src/ext/curve25519_donna/curve25519-donna.c
+# See bug 13538 -- this code is known to have signed overflow issues.
src_common_libcurve25519_donna_a_CFLAGS+=\
- @F_OMIT_FRAME_POINTER@
+ @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@
noinst_LIBRARIES+=src/common/libcurve25519_donna.a
LIBDONNA=src/common/libcurve25519_donna.a
else
if BUILD_CURVE25519_DONNA_C64
+src_common_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@
src_common_libcurve25519_donna_a_SOURCES=\
src/ext/curve25519_donna/curve25519-donna-c64.c
noinst_LIBRARIES+=src/common/libcurve25519_donna.a
@@ -58,22 +62,37 @@ else
readpassphrase_source=
endif
-LIBOR_A_SOURCES = \
+if ADD_MULODI4
+mulodi4_source=src/ext/mulodi/mulodi4.c
+else
+mulodi4_source=
+endif
+
+LIBOR_CTIME_A_SRC = \
+ $(mulodi4_source) \
+ src/ext/csiphash.c \
+ src/common/di_ops.c
+
+src_common_libor_ctime_a_SOURCES = $(LIBOR_CTIME_A_SRC)
+src_common_libor_ctime_testing_a_SOURCES = $(LIBOR_CTIME_A_SRC)
+src_common_libor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@
+src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS)
+
+LIBOR_A_SRC = \
src/common/address.c \
src/common/backtrace.c \
src/common/compat.c \
src/common/compat_threads.c \
src/common/container.c \
- src/common/di_ops.c \
src/common/log.c \
src/common/memarea.c \
+ src/common/pubsub.c \
src/common/util.c \
+ src/common/util_bug.c \
src/common/util_format.c \
src/common/util_process.c \
src/common/sandbox.c \
src/common/workqueue.c \
- src/ext/csiphash.c \
- src/ext/trunnel/trunnel.c \
$(libor_extra_source) \
$(threads_impl_source) \
$(readpassphrase_source)
@@ -81,7 +100,7 @@ LIBOR_A_SOURCES = \
src/common/src_common_libor_testing_a-log.$(OBJEXT) \
src/common/log.$(OBJEXT): micro-revision.i
-LIBOR_CRYPTO_A_SOURCES = \
+LIBOR_CRYPTO_A_SRC = \
src/common/aes.c \
src/common/crypto.c \
src/common/crypto_pwbox.c \
@@ -89,21 +108,22 @@ LIBOR_CRYPTO_A_SOURCES = \
src/common/crypto_format.c \
src/common/torgzip.c \
src/common/tortls.c \
- src/trunnel/pwbox.c \
src/common/crypto_curve25519.c \
src/common/crypto_ed25519.c
-LIBOR_EVENT_A_SOURCES = \
+LIBOR_EVENT_A_SRC = \
src/common/compat_libevent.c \
- src/common/procmon.c
+ src/common/procmon.c \
+ src/common/timers.c \
+ src/ext/timeouts/timeout.c
-src_common_libor_a_SOURCES = $(LIBOR_A_SOURCES)
-src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES)
-src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SOURCES)
+src_common_libor_a_SOURCES = $(LIBOR_A_SRC)
+src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SRC)
+src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SRC)
-src_common_libor_testing_a_SOURCES = $(LIBOR_A_SOURCES)
-src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES)
-src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SOURCES)
+src_common_libor_testing_a_SOURCES = $(LIBOR_A_SRC)
+src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SRC)
+src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SRC)
src_common_libor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_common_libor_crypto_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
@@ -129,16 +149,20 @@ COMMONHEADERS = \
src/common/crypto_pwbox.h \
src/common/crypto_s2k.h \
src/common/di_ops.h \
+ src/common/handles.h \
src/common/memarea.h \
src/common/linux_syscalls.inc \
src/common/procmon.h \
+ src/common/pubsub.h \
src/common/sandbox.h \
src/common/testsupport.h \
+ src/common/timers.h \
src/common/torgzip.h \
src/common/torint.h \
src/common/torlog.h \
src/common/tortls.h \
src/common/util.h \
+ src/common/util_bug.h \
src/common/util_format.h \
src/common/util_process.h \
src/common/workqueue.h
diff --git a/src/common/memarea.c b/src/common/memarea.c
index 173ed4e1cb..7d16b702e3 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -131,7 +131,7 @@ alloc_chunk(size_t sz)
/** Release <b>chunk</b> from a memarea. */
static void
-chunk_free_unchecked(memarea_chunk_t *chunk)
+memarea_chunk_free_unchecked(memarea_chunk_t *chunk)
{
CHECK_SENTINEL(chunk);
tor_free(chunk);
@@ -154,7 +154,7 @@ memarea_drop_all(memarea_t *area)
memarea_chunk_t *chunk, *next;
for (chunk = area->first; chunk; chunk = next) {
next = chunk->next_chunk;
- chunk_free_unchecked(chunk);
+ memarea_chunk_free_unchecked(chunk);
}
area->first = NULL; /*fail fast on */
tor_free(area);
@@ -170,7 +170,7 @@ memarea_clear(memarea_t *area)
if (area->first->next_chunk) {
for (chunk = area->first->next_chunk; chunk; chunk = next) {
next = chunk->next_chunk;
- chunk_free_unchecked(chunk);
+ memarea_chunk_free_unchecked(chunk);
}
area->first->next_chunk = NULL;
}
diff --git a/src/common/pubsub.c b/src/common/pubsub.c
new file mode 100644
index 0000000000..b3faf40e00
--- /dev/null
+++ b/src/common/pubsub.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file pubsub.c
+ *
+ * \brief DOCDOC
+ */
+
+#include "orconfig.h"
+#include "pubsub.h"
+#include "container.h"
+
+/** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping
+ * them sorted in priority order. */
+static void
+subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s)
+{
+ int i;
+ smartlist_t *sl = topic->subscribers;
+ for (i = 0; i < smartlist_len(sl); ++i) {
+ pubsub_subscriber_t *other = smartlist_get(sl, i);
+ if (s->priority < other->priority) {
+ break;
+ }
+ }
+ smartlist_insert(sl, i, s);
+}
+
+/**
+ * Add a new subscriber to <b>topic</b>, where (when an event is triggered),
+ * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>.
+ * Return a handle to the subscribe which can later be passed to
+ * pubsub_unsubscribe_().
+ *
+ * Functions are called in priority order, from lowest to highest.
+ *
+ * See pubsub.h for <b>subscribe_flags</b>.
+ */
+const pubsub_subscriber_t *
+pubsub_subscribe_(pubsub_topic_t *topic,
+ pubsub_subscriber_fn_t fn,
+ void *subscriber_data,
+ unsigned subscribe_flags,
+ unsigned priority)
+{
+ tor_assert(! topic->locked);
+ if (subscribe_flags & SUBSCRIBE_ATSTART) {
+ tor_assert(topic->n_events_fired == 0);
+ }
+ pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r));
+ r->priority = priority;
+ r->subscriber_flags = subscribe_flags;
+ r->fn = fn;
+ r->subscriber_data = subscriber_data;
+ if (topic->subscribers == NULL) {
+ topic->subscribers = smartlist_new();
+ }
+ subscriber_insert(topic, r);
+ return r;
+}
+
+/**
+ * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this
+ * function, <b>s</b> may no longer be used.
+ */
+int
+pubsub_unsubscribe_(pubsub_topic_t *topic,
+ const pubsub_subscriber_t *s)
+{
+ tor_assert(! topic->locked);
+ smartlist_t *sl = topic->subscribers;
+ if (sl == NULL)
+ return -1;
+ int i = smartlist_pos(sl, s);
+ if (i == -1)
+ return -1;
+ pubsub_subscriber_t *tmp = smartlist_get(sl, i);
+ tor_assert(tmp == s);
+ smartlist_del_keeporder(sl, i);
+ tor_free(tmp);
+ return 0;
+}
+
+/**
+ * For every subscriber s in <b>topic</b>, invoke notify_fn on s and
+ * event_data. Return 0 if there were no nonzero return values, and -1 if
+ * there were any.
+ */
+int
+pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
+ void *event_data, unsigned notify_flags)
+{
+ tor_assert(! topic->locked);
+ (void) notify_flags;
+ smartlist_t *sl = topic->subscribers;
+ int n_bad = 0;
+ ++topic->n_events_fired;
+ if (sl == NULL)
+ return -1;
+ topic->locked = 1;
+ SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
+ int r = notify_fn(s, event_data);
+ if (r != 0)
+ ++n_bad;
+ } SMARTLIST_FOREACH_END(s);
+ topic->locked = 0;
+ return (n_bad == 0) ? 0 : -1;
+}
+
+/**
+ * Release all storage held by <b>topic</b>.
+ */
+void
+pubsub_clear_(pubsub_topic_t *topic)
+{
+ tor_assert(! topic->locked);
+
+ smartlist_t *sl = topic->subscribers;
+ if (sl == NULL)
+ return;
+ SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
+ tor_free(s);
+ } SMARTLIST_FOREACH_END(s);
+ smartlist_free(sl);
+ topic->subscribers = NULL;
+ topic->n_events_fired = 0;
+}
+
diff --git a/src/common/pubsub.h b/src/common/pubsub.h
new file mode 100644
index 0000000000..09e492ec4f
--- /dev/null
+++ b/src/common/pubsub.h
@@ -0,0 +1,177 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file pubsub.h
+ * \brief Macros to implement publish/subscribe abstractions.
+ *
+ * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use
+ * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T).
+ *
+ * Doing this will declare the following types:
+ * typedef struct T_event_data_t T_event_data_t; // you define this struct
+ * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too.
+ * typedef struct T_subscriber_t T_subscriber_t; // opaque
+ * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*);
+ *
+ * and it will declare the following functions:
+ * const T_subscriber_t *T_subscribe(T_subscriber_fn_t,
+ * T_subscriber_data_t *,
+ * unsigned flags,
+ * unsigned priority);
+ * int T_unsubscribe(const T_subscriber_t *)
+ *
+ * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which declares:
+ * static int T_notify(T_event_data_t *, unsigned notify_flags);
+ * static void T_clear(void);
+ *
+ * And in some C file, you would define these functions with:
+ * IMPLEMENT_PUBSUB_TOPIC(static, T).
+ *
+ * The implementations will be small typesafe wrappers over generic versions
+ * of the above functions.
+ *
+ * To use the typesafe functions, you add any number of subscribers with
+ * T_subscribe(). Each has an associated function pointer, data pointer,
+ * and priority. Later, you can invoke T_notify() to declare that the
+ * event has occurred. Each of the subscribers will be invoked once.
+ **/
+
+#ifndef TOR_PUBSUB_H
+#define TOR_PUBSUB_H
+
+#include "torint.h"
+
+/**
+ * Flag for T_subscribe: die with an assertion failure if the event
+ * have ever been published before. Used when a subscriber must absolutely
+ * never have missed an event.
+ */
+#define SUBSCRIBE_ATSTART (1u<<0)
+
+#define DECLARE_PUBSUB_STRUCT_TYPES(name) \
+ /* You define this type. */ \
+ typedef struct name ## _event_data_t name ## _event_data_t; \
+ /* You define this type. */ \
+ typedef struct name ## _subscriber_data_t name ## _subscriber_data_t;
+
+#define DECLARE_PUBSUB_TOPIC(name) \
+ /* This type is opaque. */ \
+ typedef struct name ## _subscriber_t name ## _subscriber_t; \
+ /* You declare functions matching this type. */ \
+ typedef int (*name ## _subscriber_fn_t)( \
+ name ## _event_data_t *data, \
+ name ## _subscriber_data_t *extra); \
+ /* Call this function to subscribe to a topic. */ \
+ const name ## _subscriber_t *name ## _subscribe( \
+ name##_subscriber_fn_t subscriber, \
+ name##_subscriber_data_t *extra_data, \
+ unsigned flags, \
+ unsigned priority); \
+ /* Call this function to unsubscribe from a topic. */ \
+ int name ## _unsubscribe(const name##_subscriber_t *s);
+
+#define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \
+ /* Call this function to notify all subscribers. Flags not yet used. */ \
+ linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \
+ /* Call this function to release storage held by the topic. */ \
+ linkage void name ## _clear(void);
+
+/**
+ * Type used to hold a generic function for a subscriber.
+ *
+ * [Yes, it is safe to cast to this, so long as we cast back to the original
+ * type before calling. From C99: "A pointer to a function of one type may be
+ * converted to a pointer to a function of another type and back again; the
+ * result shall compare equal to the original pointer."]
+*/
+typedef int (*pubsub_subscriber_fn_t)(void *, void *);
+
+/**
+ * Helper type to implement pubsub abstraction. Don't use this directly.
+ * It represents a subscriber.
+ */
+typedef struct pubsub_subscriber_t {
+ /** Function to invoke when the event triggers. */
+ pubsub_subscriber_fn_t fn;
+ /** Data associated with this subscriber. */
+ void *subscriber_data;
+ /** Priority for this subscriber. Low priorities happen first. */
+ unsigned priority;
+ /** Flags set on this subscriber. Not yet used.*/
+ unsigned subscriber_flags;
+} pubsub_subscriber_t;
+
+/**
+ * Helper type to implement pubsub abstraction. Don't use this directly.
+ * It represents a topic, and keeps a record of subscribers.
+ */
+typedef struct pubsub_topic_t {
+ /** List of subscribers to this topic. May be NULL. */
+ struct smartlist_t *subscribers;
+ /** Total number of times that pubsub_notify_() has ever been called on this
+ * topic. */
+ uint64_t n_events_fired;
+ /** True iff we're running 'notify' on this topic, and shouldn't allow
+ * any concurrent modifications or events. */
+ unsigned locked;
+} pubsub_topic_t;
+
+const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic,
+ pubsub_subscriber_fn_t fn,
+ void *subscriber_data,
+ unsigned subscribe_flags,
+ unsigned priority);
+int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub);
+void pubsub_clear_(pubsub_topic_t *topic);
+typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber,
+ void *notify_data);
+int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
+ void *notify_data, unsigned notify_flags);
+
+#define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \
+ static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \
+ const name ## _subscriber_t * \
+ name ## _subscribe(name##_subscriber_fn_t subscriber, \
+ name##_subscriber_data_t *extra_data, \
+ unsigned flags, \
+ unsigned priority) \
+ { \
+ const pubsub_subscriber_t *s; \
+ s = pubsub_subscribe_(&name##_topic_, \
+ (pubsub_subscriber_fn_t)subscriber, \
+ extra_data, \
+ flags, \
+ priority); \
+ return (const name##_subscriber_t *)s; \
+ } \
+ int \
+ name ## _unsubscribe(const name##_subscriber_t *subscriber) \
+ { \
+ return pubsub_unsubscribe_(&name##_topic_, \
+ (const pubsub_subscriber_t *)subscriber); \
+ } \
+ static int \
+ name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \
+ void *notify_data) \
+ { \
+ name ## _subscriber_fn_t fn; \
+ fn = (name ## _subscriber_fn_t) subscriber->fn; \
+ return fn(notify_data, subscriber->subscriber_data); \
+ } \
+ notify_linkage int \
+ name ## _notify(name ## _event_data_t *event_data, unsigned flags) \
+ { \
+ return pubsub_notify_(&name##_topic_, \
+ name##_call_the_notify_fn_, \
+ event_data, \
+ flags); \
+ } \
+ notify_linkage void \
+ name ## _clear(void) \
+ { \
+ pubsub_clear_(&name##_topic_); \
+ }
+
+#endif /* TOR_PUBSUB_H */
+
diff --git a/src/common/timers.c b/src/common/timers.c
new file mode 100644
index 0000000000..5d8d1feafd
--- /dev/null
+++ b/src/common/timers.c
@@ -0,0 +1,297 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file timers.c
+ * \brief Wrapper around William Ahern's fast hierarchical timer wheel
+ * implementation, to tie it in with a libevent backend.
+ *
+ * Only use these functions from the main thread.
+ *
+ * The main advantage of tor_timer_t over using libevent's timers is that
+ * they're way more efficient if we need to have thousands or millions of
+ * them. For more information, see
+ * http://www.25thandclement.com/~william/projects/timeout.c.html
+ *
+ * Periodic timers are available in the backend, but I've turned them off.
+ * We can turn them back on if needed.
+ */
+
+/* Notes:
+ *
+ * The use of tor_gettimeofday_cached_monotonic() is kind of ugly. It would
+ * be neat to fix it.
+ *
+ * Having a way to free all timers on shutdown would free people from the
+ * need to track them. Not sure if that's clever though.
+ *
+ * In an ideal world, Libevent would just switch to use this backend, and we
+ * could throw this file away. But even if Libevent does switch, we'll be
+ * stuck with legacy libevents for some time.
+ */
+
+#include "orconfig.h"
+
+#include "compat.h"
+#include "compat_libevent.h"
+#include "timers.h"
+#include "torlog.h"
+#include "util.h"
+
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/event.h>
+#else
+#include <event.h>
+#endif
+
+struct timeout_cb {
+ timer_cb_fn_t cb;
+ void *arg;
+};
+
+/*
+ * These definitions are for timeouts.c and timeouts.h.
+ */
+#ifdef __GNUC__
+/* We're not exposing any of the functions outside this file. */
+#define TIMEOUT_PUBLIC __attribute__((__unused__)) static
+#else
+/* We're not exposing any of the functions outside this file. */
+#define TIMEOUT_PUBLIC static
+#endif
+/* We're not using periodic events. */
+#define TIMEOUT_DISABLE_INTERVALS
+/* We always know the global_timeouts object, so we don't need each timeout
+ * to keep a pointer to it. */
+#define TIMEOUT_DISABLE_RELATIVE_ACCESS
+/* We're providing our own struct timeout_cb. */
+#define TIMEOUT_CB_OVERRIDE
+/* We're going to support timers that are pretty far out in advance. Making
+ * this big can be inefficient, but having a significant number of timers
+ * above TIMEOUT_MAX can also be super-inefficent. Choosing 5 here sets
+ * timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */
+#define WHEEL_NUM 5
+#include "src/ext/timeouts/timeout.c"
+
+static struct timeouts *global_timeouts = NULL;
+static struct event *global_timer_event = NULL;
+
+/** We need to choose this value carefully. Because we're using timer wheels,
+ * it actually costs us to have extra resolution we don't use. So for now,
+ * I'm going to define our resolution as .1 msec, and hope that's good enough.
+ *
+ * Note that two of the most popular libevent backends (epoll without timerfd,
+ * and windows select), simply can't support sub-millisecond resolution,
+ * do this is optimistic for a lot of users.
+ */
+#define USEC_PER_TICK 100
+
+/** One million microseconds in a second */
+#define USEC_PER_SEC 1000000
+
+/** Check at least once every N seconds. */
+#define MIN_CHECK_SECONDS 3600
+
+/** Check at least once every N ticks. */
+#define MIN_CHECK_TICKS \
+ (((timeout_t)MIN_CHECK_SECONDS) * (1000000 / USEC_PER_TICK))
+
+/**
+ * Convert the timeval in <b>tv</b> to a timeout_t, and return it.
+ *
+ * The output resolution is set by USEC_PER_TICK, and the time corresponding
+ * to 0 is the same as the time corresponding to 0 from
+ * tor_gettimeofday_cached_monotonic().
+ */
+static timeout_t
+tv_to_timeout(const struct timeval *tv)
+{
+ uint64_t usec = tv->tv_usec;
+ usec += ((uint64_t)USEC_PER_SEC) * tv->tv_sec;
+ return usec / USEC_PER_TICK;
+}
+
+/**
+ * Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>
+ */
+static void
+timeout_to_tv(timeout_t t, struct timeval *tv_out)
+{
+ t *= USEC_PER_TICK;
+ tv_out->tv_usec = (int)(t % USEC_PER_SEC);
+ tv_out->tv_sec = (time_t)(t / USEC_PER_SEC);
+}
+
+/**
+ * Update the timer <b>tv</b> to the current time in <b>tv</b>.
+ */
+static void
+timer_advance_to_cur_time(const struct timeval *tv)
+{
+ timeout_t cur_tick = tv_to_timeout(tv);
+ if (BUG(cur_tick < timeouts_get_curtime(global_timeouts))) {
+ cur_tick = timeouts_get_curtime(global_timeouts); // LCOV_EXCL_LINE
+ }
+ timeouts_update(global_timeouts, cur_tick);
+}
+
+/**
+ * Adjust the time at which the libevent timer should fire based on
+ * the next-expiring time in <b>global_timeouts</b>
+ */
+static void
+libevent_timer_reschedule(void)
+{
+ struct timeval now;
+ tor_gettimeofday_cached_monotonic(&now);
+ timer_advance_to_cur_time(&now);
+
+ timeout_t delay = timeouts_timeout(global_timeouts);
+ struct timeval d;
+ if (delay > MIN_CHECK_TICKS)
+ delay = MIN_CHECK_TICKS;
+ timeout_to_tv(delay, &d);
+ event_add(global_timer_event, &d);
+}
+
+/**
+ * Invoked when the libevent timer has expired: see which tor_timer_t events
+ * have fired, activate their callbacks, and reschedule the libevent timer.
+ */
+static void
+libevent_timer_callback(evutil_socket_t fd, short what, void *arg)
+{
+ (void)fd;
+ (void)what;
+ (void)arg;
+
+ struct timeval now;
+ tor_gettimeofday_cache_clear();
+ tor_gettimeofday_cached_monotonic(&now);
+ timer_advance_to_cur_time(&now);
+
+ tor_timer_t *t;
+ while ((t = timeouts_get(global_timeouts))) {
+ t->callback.cb(t, t->callback.arg, &now);
+ }
+
+ tor_gettimeofday_cache_clear();
+ libevent_timer_reschedule();
+}
+
+/**
+ * Initialize the timers subsystem. Requires that libevent has already been
+ * initialized.
+ */
+void
+timers_initialize(void)
+{
+ if (BUG(global_timeouts))
+ return; // LCOV_EXCL_LINE
+
+ timeout_error_t err;
+ global_timeouts = timeouts_open(0, &err);
+ if (!global_timeouts) {
+ // LCOV_EXCL_START -- this can only fail on malloc failure.
+ log_err(LD_BUG, "Unable to open timer backend: %s", strerror(err));
+ tor_assert(0);
+ // LCOV_EXCL_STOP
+ }
+
+ struct event *timer_event;
+ timer_event = tor_event_new(tor_libevent_get_base(),
+ -1, 0, libevent_timer_callback, NULL);
+ tor_assert(timer_event);
+ global_timer_event = timer_event;
+
+ libevent_timer_reschedule();
+}
+
+/**
+ * Release all storage held in the timers subsystem. Does not fire timers.
+ */
+void
+timers_shutdown(void)
+{
+ if (global_timer_event) {
+ tor_event_free(global_timer_event);
+ global_timer_event = NULL;
+ }
+ if (global_timeouts) {
+ timeouts_close(global_timeouts);
+ global_timeouts = NULL;
+ }
+}
+
+/**
+ * Allocate and return a new timer, with given callback and argument.
+ */
+tor_timer_t *
+timer_new(timer_cb_fn_t cb, void *arg)
+{
+ tor_timer_t *t = tor_malloc(sizeof(tor_timer_t));
+ timeout_init(t, 0);
+ timer_set_cb(t, cb, arg);
+ return t;
+}
+
+/**
+ * Release all storage held by <b>t</b>, and unschedule it if was already
+ * scheduled.
+ */
+void
+timer_free(tor_timer_t *t)
+{
+ if (! t)
+ return;
+
+ timeouts_del(global_timeouts, t);
+ tor_free(t);
+}
+
+/**
+ * Change the callback and argument associated with a timer <b>t</b>.
+ */
+void
+timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg)
+{
+ t->callback.cb = cb;
+ t->callback.arg = arg;
+}
+
+/**
+ * Schedule the timer t to fire at the current time plus a delay of <b>tv</b>.
+ * All times are relative to tor_gettimeofday_cached_monotonic.
+ */
+void
+timer_schedule(tor_timer_t *t, const struct timeval *tv)
+{
+ const timeout_t when = tv_to_timeout(tv);
+ struct timeval now;
+ tor_gettimeofday_cached_monotonic(&now);
+ timer_advance_to_cur_time(&now);
+
+ /* Take the old timeout value. */
+ timeout_t to = timeouts_timeout(global_timeouts);
+
+ timeouts_add(global_timeouts, t, when);
+
+ /* Should we update the libevent timer? */
+ if (to <= when) {
+ return; /* we're already going to fire before this timer would trigger. */
+ }
+ libevent_timer_reschedule();
+}
+
+/**
+ * Cancel the timer <b>t</b> if it is currently scheduled. (It's okay to call
+ * this on an unscheduled timer.
+ */
+void
+timer_disable(tor_timer_t *t)
+{
+ timeouts_del(global_timeouts, t);
+ /* We don't reschedule the libevent timer here, since it's okay if it fires
+ * early. */
+}
+
diff --git a/src/common/timers.h b/src/common/timers.h
new file mode 100644
index 0000000000..594cf38a64
--- /dev/null
+++ b/src/common/timers.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_TIMERS_H
+#define TOR_TIMERS_H
+
+#include "orconfig.h"
+#include "testsupport.h"
+
+typedef struct timeout tor_timer_t;
+typedef void (*timer_cb_fn_t)(tor_timer_t *, void *, const struct timeval *);
+tor_timer_t *timer_new(timer_cb_fn_t cb, void *arg);
+void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg);
+void timer_schedule(tor_timer_t *t, const struct timeval *delay);
+void timer_disable(tor_timer_t *t);
+void timer_free(tor_timer_t *t);
+
+void timers_initialize(void);
+void timers_shutdown(void);
+
+#endif
+
diff --git a/src/common/util.c b/src/common/util.c
index f3effe0957..78afe5954f 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -105,23 +105,6 @@
#endif
/* =====
- * Assertion helper.
- * ===== */
-/** Helper for tor_assert: report the assertion failure. */
-void
-tor_assertion_failed_(const char *fname, unsigned int line,
- const char *func, const char *expr)
-{
- char buf[256];
- log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
- fname, line, func, expr);
- tor_snprintf(buf, sizeof(buf),
- "Assertion %s failed in %s at %s:%u",
- expr, func, fname, line);
- log_backtrace(LOG_ERR, LD_BUG, buf);
-}
-
-/* =====
* Memory management
* ===== */
#ifdef USE_DMALLOC
@@ -530,21 +513,6 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
return number;
}
-/** Return the lowest x in [INT64_MIN, INT64_MAX] such that x is at least
- * <b>number</b>, and x modulo <b>divisor</b> == 0. If no such x can be
- * expressed as an int64_t, return INT64_MAX */
-int64_t
-round_int64_to_next_multiple_of(int64_t number, int64_t divisor)
-{
- tor_assert(divisor > 0);
- if (INT64_MAX - divisor + 1 < number)
- return INT64_MAX;
- if (number >= 0)
- number += divisor - 1;
- number -= number % divisor;
- return number;
-}
-
/** Transform a random value <b>p</b> from the uniform distribution in
* [0.0, 1.0[ into a Laplace distributed value with location parameter
* <b>mu</b> and scale parameter <b>b</b>. Truncate the final result
@@ -3079,7 +3047,7 @@ digit_to_num(char d)
* success, store the result in <b>out</b>, advance bufp to the next
* character, and return 0. On failure, return -1. */
static int
-scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
+scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base)
{
unsigned long result = 0;
int scanned_so_far = 0;
@@ -3092,7 +3060,7 @@ scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
&& scanned_so_far < width) {
- int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
+ unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
// Check for overflow beforehand, without actually causing any overflow
// This preserves functionality on compilers that don't wrap overflow
// (i.e. that trap or optimise away overflow)
@@ -3138,14 +3106,15 @@ scan_signed(const char **bufp, long *out, int width)
if (neg && result > 0) {
if (result > ((unsigned long)LONG_MAX) + 1)
return -1; /* Underflow */
- // Avoid overflow on the cast to signed long when result is LONG_MIN
- // by subtracting 1 from the unsigned long positive value,
- // then, after it has been cast to signed and negated,
- // subtracting the original 1 (the double-subtraction is intentional).
- // Otherwise, the cast to signed could cause a temporary long
- // to equal LONG_MAX + 1, which is undefined.
- // We avoid underflow on the subtraction by treating -0 as positive.
- *out = (-(long)(result - 1)) - 1;
+ else if (result == ((unsigned long)LONG_MAX) + 1)
+ *out = LONG_MIN;
+ else {
+ /* We once had a far more clever no-overflow conversion here, but
+ * some versions of GCC apparently ran it into the ground. Now
+ * we just check for LONG_MIN explicitly.
+ */
+ *out = -(long)result;
+ }
} else {
if (result > LONG_MAX)
return -1; /* Overflow */
@@ -3291,8 +3260,10 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap)
*out = lng;
} else {
int *out = va_arg(ap, int *);
+#if LONG_MAX > INT_MAX
if (lng < INT_MIN || lng > INT_MAX)
return n_matched;
+#endif
*out = (int)lng;
}
++pattern;
diff --git a/src/common/util.h b/src/common/util.h
index ebcf88b32d..4c5070e65b 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -22,6 +22,7 @@
/* for the correct alias to struct stat */
#include <sys/stat.h>
#endif
+#include "util_bug.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -33,41 +34,6 @@
#define O_NOFOLLOW 0
#endif
-/* Replace assert() with a variant that sends failures to the log before
- * calling assert() normally.
- */
-#ifdef NDEBUG
-/* Nobody should ever want to build with NDEBUG set. 99% of our asserts will
- * be outside the critical path anyway, so it's silly to disable bug-checking
- * throughout the entire program just because a few asserts are slowing you
- * down. Profile, optimize the critical path, and keep debugging on.
- *
- * And I'm not just saying that because some of our asserts check
- * security-critical properties.
- */
-#error "Sorry; we don't support building with NDEBUG."
-#endif
-
-/* Sometimes we don't want to use assertions during branch coverage tests; it
- * leads to tons of unreached branches which in reality are only assertions we
- * didn't hit. */
-#if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
-#define tor_assert(a) STMT_BEGIN \
- (void)(a); \
- STMT_END
-#else
-/** Like assert(3), but send assertion failures to the log as well as to
- * stderr. */
-#define tor_assert(expr) STMT_BEGIN \
- if (PREDICT_UNLIKELY(!(expr))) { \
- tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \
- abort(); \
- } STMT_END
-#endif
-
-void tor_assertion_failed_(const char *fname, unsigned int line,
- const char *func, const char *expr);
-
/* If we're building with dmalloc, we want all of our memory allocation
* functions to take an extra file/line pair of arguments. If not, not.
* We define DMALLOC_PARAMS to the extra parameters to insert in the
@@ -81,11 +47,6 @@ void tor_assertion_failed_(const char *fname, unsigned int line,
#define DMALLOC_ARGS
#endif
-/** Define this if you want Tor to crash when any problem comes up,
- * so you can get a coredump and track things down. */
-// #define tor_fragile_assert() tor_assert(0)
-#define tor_fragile_assert()
-
/* Memory management */
void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
@@ -184,7 +145,6 @@ uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
-int64_t round_int64_to_next_multiple_of(int64_t number, int64_t divisor);
int64_t sample_laplace_distribution(double mu, double b, double p);
int64_t add_laplace_noise(int64_t signal, double random, double delta_f,
double epsilon);
diff --git a/src/common/util_bug.c b/src/common/util_bug.c
new file mode 100644
index 0000000000..e3e1d6df90
--- /dev/null
+++ b/src/common/util_bug.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file util_bug.c
+ **/
+
+#include "orconfig.h"
+#include "util_bug.h"
+#include "torlog.h"
+#include "backtrace.h"
+
+/** Helper for tor_assert: report the assertion failure. */
+void
+tor_assertion_failed_(const char *fname, unsigned int line,
+ const char *func, const char *expr)
+{
+ char buf[256];
+ log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
+ fname, line, func, expr);
+ tor_snprintf(buf, sizeof(buf),
+ "Assertion %s failed in %s at %s:%u",
+ expr, func, fname, line);
+ log_backtrace(LOG_ERR, LD_BUG, buf);
+}
+
+/** Helper for tor_assert_nonfatal: report the assertion failure. */
+void
+tor_bug_occurred_(const char *fname, unsigned int line,
+ const char *func, const char *expr,
+ int once)
+{
+ char buf[256];
+ const char *once_str = once ?
+ " (Future instances of this warning will be silenced.)": "";
+ if (! expr) {
+ log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s",
+ fname, line, func, once_str);
+ tor_snprintf(buf, sizeof(buf),
+ "Line unexpectedly reached at %s at %s:%u",
+ func, fname, line);
+ } else {
+ log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s",
+ fname, line, func, expr, once_str);
+ tor_snprintf(buf, sizeof(buf),
+ "Non-fatal assertion %s failed in %s at %s:%u",
+ expr, func, fname, line);
+ }
+ log_backtrace(LOG_WARN, LD_BUG, buf);
+}
+
diff --git a/src/common/util_bug.h b/src/common/util_bug.h
new file mode 100644
index 0000000000..36056aa4bd
--- /dev/null
+++ b/src/common/util_bug.h
@@ -0,0 +1,150 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file util_bug.h
+ **/
+
+#ifndef TOR_UTIL_BUG_H
+#define TOR_UTIL_BUG_H
+
+#include "orconfig.h"
+#include "compat.h"
+#include "testsupport.h"
+
+/* Replace assert() with a variant that sends failures to the log before
+ * calling assert() normally.
+ */
+#ifdef NDEBUG
+/* Nobody should ever want to build with NDEBUG set. 99% of our asserts will
+ * be outside the critical path anyway, so it's silly to disable bug-checking
+ * throughout the entire program just because a few asserts are slowing you
+ * down. Profile, optimize the critical path, and keep debugging on.
+ *
+ * And I'm not just saying that because some of our asserts check
+ * security-critical properties.
+ */
+#error "Sorry; we don't support building with NDEBUG."
+#endif
+
+/* Sometimes we don't want to use assertions during branch coverage tests; it
+ * leads to tons of unreached branches which in reality are only assertions we
+ * didn't hit. */
+#if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
+#define tor_assert(a) STMT_BEGIN \
+ (void)(a); \
+ STMT_END
+#else
+/** Like assert(3), but send assertion failures to the log as well as to
+ * stderr. */
+#define tor_assert(expr) STMT_BEGIN \
+ if (PREDICT_UNLIKELY(!(expr))) { \
+ tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \
+ abort(); \
+ } STMT_END
+#endif
+
+#define tor_assert_unreached() tor_assert(0)
+
+/* Non-fatal bug assertions. The "unreached" variants mean "this line should
+ * never be reached." The "once" variants mean "Don't log a warning more than
+ * once".
+ *
+ * The 'BUG' macro checks a boolean condition and logs an error message if it
+ * is true. Example usage:
+ * if (BUG(x == NULL))
+ * return -1;
+ */
+
+#ifdef ALL_BUGS_ARE_FATAL
+#define tor_assert_nonfatal_unreached() tor_assert(0)
+#define tor_assert_nonfatal(cond) tor_assert((cond))
+#define tor_assert_nonfatal_unreached_once() tor_assert(0)
+#define tor_assert_nonfatal_once(cond) tor_assert((cond))
+#define BUG(cond) \
+ (PREDICT_UNLIKELY(cond) ? \
+ (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,#cond), abort(), 1) \
+ : 0)
+#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
+#define tor_assert_nonfatal_unreached() STMT_NIL
+#define tor_assert_nonfatal(cond) ((void)(cond))
+#define tor_assert_nonfatal_unreached_once() STMT_NIL
+#define tor_assert_nonfatal_once(cond) ((void)(cond))
+#define BUG(cond) (PREDICT_UNLIKELY(cond) ? 1 : 0)
+#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
+#define tor_assert_nonfatal_unreached() STMT_BEGIN \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0); \
+ STMT_END
+#define tor_assert_nonfatal(cond) STMT_BEGIN \
+ if (PREDICT_UNLIKELY(!(cond))) { \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0); \
+ } \
+ STMT_END
+#define tor_assert_nonfatal_unreached_once() STMT_BEGIN \
+ static int warning_logged__ = 0; \
+ if (!warning_logged__) { \
+ warning_logged__ = 1; \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1); \
+ } \
+ STMT_END
+#define tor_assert_nonfatal_once(cond) STMT_BEGIN \
+ static int warning_logged__ = 0; \
+ if (!warning_logged__ && PREDICT_UNLIKELY(!(cond))) { \
+ warning_logged__ = 1; \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1); \
+ } \
+ STMT_END
+#define BUG(cond) \
+ (PREDICT_UNLIKELY(cond) ? \
+ (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,#cond,0), 1) \
+ : 0)
+#endif
+
+#ifdef __GNUC__
+#define IF_BUG_ONCE__(cond,var) \
+ if (({ \
+ static int var = 0; \
+ int bool_result = (cond); \
+ if (PREDICT_UNLIKELY(bool_result) && !var) { \
+ var = 1; \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1); \
+ } \
+ PREDICT_UNLIKELY(bool_result); }))
+#else
+#define IF_BUG_ONCE__(cond,var) \
+ static int var = 0; \
+ if (PREDICT_UNLIKELY(cond)) ? \
+ (var ? 1 : \
+ (var=1, \
+ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1), \
+ 1)) \
+ : 0)
+#endif
+#define IF_BUG_ONCE_VARNAME_(a) \
+ warning_logged_on_ ## a ## __
+#define IF_BUG_ONCE_VARNAME__(a) \
+ IF_BUG_ONCE_VARNAME_(a)
+
+/** This macro behaves as 'if (bug(x))', except that it only logs its
+ * warning once, no matter how many times it triggers.
+ */
+
+#define IF_BUG_ONCE(cond) \
+ IF_BUG_ONCE__((cond), \
+ IF_BUG_ONCE_VARNAME__(__LINE__))
+
+/** Define this if you want Tor to crash when any problem comes up,
+ * so you can get a coredump and track things down. */
+// #define tor_fragile_assert() tor_assert_unreached(0)
+#define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
+
+void tor_assertion_failed_(const char *fname, unsigned int line,
+ const char *func, const char *expr);
+void tor_bug_occurred_(const char *fname, unsigned int line,
+ const char *func, const char *expr,
+ int once);
+
+#endif
+