summaryrefslogtreecommitdiff
path: root/src/rust
diff options
context:
space:
mode:
Diffstat (limited to 'src/rust')
-rw-r--r--src/rust/Cargo.lock1
-rw-r--r--src/rust/Cargo.toml10
-rw-r--r--src/rust/crypto/Cargo.toml7
-rw-r--r--src/rust/external/Cargo.toml12
-rw-r--r--src/rust/external/external.rs9
-rw-r--r--src/rust/external/lib.rs2
-rw-r--r--src/rust/protover/Cargo.toml7
-rw-r--r--src/rust/protover/errors.rs4
-rw-r--r--src/rust/protover/ffi.rs22
-rw-r--r--src/rust/protover/protoset.rs100
-rw-r--r--src/rust/protover/protover.rs92
-rw-r--r--src/rust/protover/tests/protover.rs14
-rw-r--r--src/rust/smartlist/Cargo.toml7
-rw-r--r--src/rust/smartlist/lib.rs9
-rw-r--r--src/rust/tor_allocate/Cargo.toml7
-rw-r--r--src/rust/tor_allocate/lib.rs5
-rw-r--r--src/rust/tor_log/Cargo.toml6
-rw-r--r--src/rust/tor_log/tor_log.rs8
-rw-r--r--src/rust/tor_rust/Cargo.toml8
-rw-r--r--src/rust/tor_util/Cargo.toml7
20 files changed, 230 insertions, 107 deletions
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 1d2a7359aa..7d6a6635c5 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -26,6 +26,7 @@ version = "0.0.1"
dependencies = [
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
"smartlist 0.0.1",
+ "tor_allocate 0.0.1",
]
[[package]]
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index 4bbadbe535..83f9629660 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -13,13 +13,3 @@ members = [
[profile.release]
debug = true
panic = "abort"
-
-[features]
-default = []
-# If this feature is enabled, test code which calls Tor C code from Rust will
-# execute with `cargo test`. Due to numerous linker issues (#25386), this is
-# currently disabled by default. Crates listed here are those which, in their
-# unittests, doctests, and/or integration tests, call C code.
-test-c-from-rust = [
- "crypto/test-c-from-rust",
-]
diff --git a/src/rust/crypto/Cargo.toml b/src/rust/crypto/Cargo.toml
index d68ac48e28..a7ff7f78d9 100644
--- a/src/rust/crypto/Cargo.toml
+++ b/src/rust/crypto/Cargo.toml
@@ -9,7 +9,6 @@ build = "../build.rs"
[lib]
name = "crypto"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
[dependencies]
libc = "=0.2.39"
@@ -30,3 +29,9 @@ rand_core = { version = "=0.2.0-pre.0", default-features = false }
# execute with `cargo test`. Due to numerous linker issues (#25386), this is
# currently disabled by default.
test-c-from-rust = []
+
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
diff --git a/src/rust/external/Cargo.toml b/src/rust/external/Cargo.toml
index 60ec03be40..5f443645bb 100644
--- a/src/rust/external/Cargo.toml
+++ b/src/rust/external/Cargo.toml
@@ -5,12 +5,16 @@ name = "external"
[dependencies]
libc = "=0.2.39"
-
-[dependencies.smartlist]
-path = "../smartlist"
+smartlist = { path = "../smartlist" }
+tor_allocate = { path = "../tor_allocate" }
[lib]
name = "external"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
+[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
diff --git a/src/rust/external/external.rs b/src/rust/external/external.rs
index 874c7c3153..aa43d2a928 100644
--- a/src/rust/external/external.rs
+++ b/src/rust/external/external.rs
@@ -26,3 +26,12 @@ pub fn c_tor_version_as_new_as(platform: &str, cutoff: &str) -> bool {
result == 1
}
+
+extern "C" {
+ fn tor_is_using_nss() -> c_int;
+}
+
+/// Return true if Tor was built to use NSS.
+pub fn c_tor_is_using_nss() -> bool {
+ 0 != unsafe { tor_is_using_nss() }
+}
diff --git a/src/rust/external/lib.rs b/src/rust/external/lib.rs
index b72a4f6e4c..d68036fcad 100644
--- a/src/rust/external/lib.rs
+++ b/src/rust/external/lib.rs
@@ -8,7 +8,7 @@
//! module implementing this functionality repeatedly.
extern crate libc;
-
+extern crate tor_allocate;
extern crate smartlist;
pub mod crypto_digest;
diff --git a/src/rust/protover/Cargo.toml b/src/rust/protover/Cargo.toml
index a8480e142a..84a7c71c1a 100644
--- a/src/rust/protover/Cargo.toml
+++ b/src/rust/protover/Cargo.toml
@@ -4,6 +4,11 @@ version = "0.0.1"
name = "protover"
[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
[dependencies]
libc = "=0.2.39"
@@ -26,5 +31,3 @@ path = "../tor_log"
[lib]
name = "protover"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
-
diff --git a/src/rust/protover/errors.rs b/src/rust/protover/errors.rs
index 71fbc53e17..f26a48b019 100644
--- a/src/rust/protover/errors.rs
+++ b/src/rust/protover/errors.rs
@@ -18,6 +18,7 @@ pub enum ProtoverError {
ExceedsExpansionLimit,
UnknownProtocol,
ExceedsNameLimit,
+ InvalidProtocol,
}
/// Descriptive error messages for `ProtoverError` variants.
@@ -48,6 +49,9 @@ impl Display for ProtoverError {
ProtoverError::ExceedsNameLimit => {
write!(f, "An unrecognised protocol name was too long.")
}
+ ProtoverError::InvalidProtocol => {
+ write!(f, "A protocol name includes invalid characters.")
+ }
}
}
}
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
index 0c28d032c6..ac149fbbbc 100644
--- a/src/rust/protover/ffi.rs
+++ b/src/rust/protover/ffi.rs
@@ -62,6 +62,9 @@ pub extern "C" fn protover_all_supported(
};
if let Some(unsupported) = relay_proto_entry.all_supported() {
+ if missing_out.is_null() {
+ return 0;
+ }
let c_unsupported: CString = match CString::new(unsupported.to_string()) {
Ok(n) => n,
Err(_) => return 1,
@@ -184,11 +187,7 @@ pub extern "C" fn protover_get_supported_protocols() -> *const c_char {
//
// Why is the threshold a signed integer? —isis
#[no_mangle]
-pub extern "C" fn protover_compute_vote(
- list: *const Stringlist,
- threshold: c_int,
- allow_long_proto_names: bool,
-) -> *mut c_char {
+pub extern "C" fn protover_compute_vote(list: *const Stringlist, threshold: c_int) -> *mut c_char {
if list.is_null() {
return allocate_and_copy_string("");
}
@@ -200,16 +199,9 @@ pub extern "C" fn protover_compute_vote(
let mut proto_entries: Vec<UnvalidatedProtoEntry> = Vec::new();
for datum in data {
- let entry: UnvalidatedProtoEntry = if allow_long_proto_names {
- match UnvalidatedProtoEntry::from_str_any_len(datum.as_str()) {
- Ok(n) => n,
- Err(_) => continue,
- }
- } else {
- match datum.parse() {
- Ok(n) => n,
- Err(_) => continue,
- }
+ let entry: UnvalidatedProtoEntry = match datum.parse() {
+ Ok(n) => n,
+ Err(_) => continue,
};
proto_entries.push(entry);
}
diff --git a/src/rust/protover/protoset.rs b/src/rust/protover/protoset.rs
index db33592f95..aa8d243bad 100644
--- a/src/rust/protover/protoset.rs
+++ b/src/rust/protover/protoset.rs
@@ -4,6 +4,8 @@
//! Sets for lazily storing ordered, non-overlapping ranges of integers.
+use std::cmp;
+use std::iter;
use std::slice;
use std::str::FromStr;
use std::u32;
@@ -174,7 +176,7 @@ impl ProtoSet {
if low == u32::MAX || high == u32::MAX {
return Err(ProtoverError::ExceedsMax);
}
- if low < last_high {
+ if low <= last_high {
return Err(ProtoverError::Overlap);
} else if low > high {
return Err(ProtoverError::LowGreaterThanHigh);
@@ -240,8 +242,8 @@ impl ProtoSet {
false
}
- /// Retain only the `Version`s in this `ProtoSet` for which the predicate
- /// `F` returns `true`.
+ /// Returns all the `Version`s in `self` which are not also in the `other`
+ /// `ProtoSet`.
///
/// # Examples
///
@@ -250,25 +252,45 @@ impl ProtoSet {
/// use protover::protoset::ProtoSet;
///
/// # fn do_test() -> Result<bool, ProtoverError> {
- /// let mut protoset: ProtoSet = "1,3-5,9".parse()?;
+ /// let protoset: ProtoSet = "1,3-6,10-12,15-16".parse()?;
+ /// let other: ProtoSet = "2,5-7,9-11,14-20".parse()?;
///
- /// // Keep only versions less than or equal to 8:
- /// protoset.retain(|x| x <= &8);
+ /// let subset: ProtoSet = protoset.and_not_in(&other);
///
- /// assert_eq!(protoset.expand(), vec![1, 3, 4, 5]);
+ /// assert_eq!(subset.expand(), vec![1, 3, 4, 12]);
/// #
/// # Ok(true)
/// # }
/// # fn main() { do_test(); } // wrap the test so we can use the ? operator
/// ```
- // XXX we could probably do something more efficient here. —isis
- pub fn retain<F>(&mut self, f: F)
- where
- F: FnMut(&Version) -> bool,
- {
- let mut expanded: Vec<Version> = self.clone().expand();
- expanded.retain(f);
- *self = expanded.into();
+ pub fn and_not_in(&self, other: &Self) -> Self {
+ if self.is_empty() || other.is_empty() {
+ return self.clone();
+ }
+
+ let pairs = self.iter().flat_map(|&(lo, hi)| {
+ let the_end = (hi + 1, hi + 1); // special case to mark the end of the range.
+ let excluded_ranges = other
+ .iter()
+ .cloned() // have to be owned tuples, to match iter::once(the_end).
+ .skip_while(move|&(_, hi2)| hi2 < lo) // skip the non-overlapping ranges.
+ .take_while(move|&(lo2, _)| lo2 <= hi) // take all the overlapping ones.
+ .chain(iter::once(the_end));
+
+ let mut nextlo = lo;
+ excluded_ranges.filter_map(move |(excluded_lo, excluded_hi)| {
+ let pair = if nextlo < excluded_lo {
+ Some((nextlo, excluded_lo - 1))
+ } else {
+ None
+ };
+ nextlo = cmp::min(excluded_hi, u32::MAX - 1) + 1;
+ pair
+ })
+ });
+
+ let pairs = pairs.collect();
+ ProtoSet::is_ok(ProtoSet { pairs }).expect("should be already sorted")
}
}
@@ -330,23 +352,25 @@ impl FromStr for ProtoSet {
/// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("3-"));
/// assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1-,4"));
///
- /// // Things which would get parsed into an _empty_ `ProtoSet` are,
- /// // however, legal, and result in an empty `ProtoSet`:
+ /// // An empty string is, however, legal, and results in an
+ /// // empty `ProtoSet`:
/// assert_eq!(Ok(ProtoSet::default()), ProtoSet::from_str(""));
- /// assert_eq!(Ok(ProtoSet::default()), ProtoSet::from_str(",,,"));
/// #
/// # Ok(protoset)
/// # }
/// # fn main() { do_test(); } // wrap the test so we can use the ? operator
/// ```
fn from_str(version_string: &str) -> Result<Self, Self::Err> {
+ // If we were passed in an empty string, then return an empty ProtoSet.
+ if version_string.is_empty() {
+ return Ok(Self::default());
+ }
+
let mut pairs: Vec<(Version, Version)> = Vec::new();
let pieces: ::std::str::Split<char> = version_string.split(',');
for p in pieces {
- if p.is_empty() {
- continue;
- } else if p.contains('-') {
+ if p.contains('-') {
let mut pair = p.splitn(2, '-');
let low = pair.next().ok_or(ProtoverError::Unparseable)?;
@@ -355,24 +379,14 @@ impl FromStr for ProtoSet {
let lo: Version = low.parse().or(Err(ProtoverError::Unparseable))?;
let hi: Version = high.parse().or(Err(ProtoverError::Unparseable))?;
- if lo == u32::MAX || hi == u32::MAX {
- return Err(ProtoverError::ExceedsMax);
- }
pairs.push((lo, hi));
} else {
let v: u32 = p.parse().or(Err(ProtoverError::Unparseable))?;
- if v == u32::MAX {
- return Err(ProtoverError::ExceedsMax);
- }
pairs.push((v, v));
}
}
- // If we were passed in an empty string, or
- // simply a comma, or a pile of commas, then return an empty ProtoSet.
- if pairs.len() == 0 {
- return Ok(ProtoSet::default());
- }
+
ProtoSet::from_slice(&pairs[..])
}
}
@@ -521,7 +535,6 @@ mod test {
test_protoset_contains_versions!(&[1], "1");
test_protoset_contains_versions!(&[1, 2], "1,2");
test_protoset_contains_versions!(&[1, 2, 3], "1-3");
- test_protoset_contains_versions!(&[0, 1], "0-1");
test_protoset_contains_versions!(&[1, 2, 5], "1-2,5");
test_protoset_contains_versions!(&[1, 3, 4, 5], "1,3-5");
test_protoset_contains_versions!(&[42, 55, 56, 57, 58], "42,55-58");
@@ -538,6 +551,13 @@ mod test {
}
#[test]
+ fn test_versions_from_str_commas() {
+ assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str(","));
+ assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,,2"));
+ assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("1,2,"));
+ }
+
+ #[test]
fn test_versions_from_str_hyphens() {
assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("--1"));
assert_eq!(Err(ProtoverError::Unparseable), ProtoSet::from_str("-1-2"));
@@ -597,9 +617,9 @@ mod test {
#[test]
fn test_protoset_contains() {
- let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 5), (7, 9), (13, 14)]).unwrap();
+ let protoset: ProtoSet = ProtoSet::from_slice(&[(1, 5), (7, 9), (13, 14)]).unwrap();
- for x in 0..6 {
+ for x in 1..6 {
assert!(protoset.contains(&x), format!("should contain {}", x));
}
for x in 7..10 {
@@ -615,10 +635,10 @@ mod test {
}
#[test]
- fn test_protoset_contains_0_3() {
- let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 3)]).unwrap();
+ fn test_protoset_contains_1_3() {
+ let protoset: ProtoSet = ProtoSet::from_slice(&[(1, 3)]).unwrap();
- for x in 0..4 {
+ for x in 1..4 {
assert!(protoset.contains(&x), format!("should contain {}", x));
}
}
@@ -640,8 +660,8 @@ mod test {
}
#[test]
- fn test_protoset_from_vec_0_315() {
- assert_protoset_from_vec_contains_all!(0, 1, 2, 3, 15);
+ fn test_protoset_from_vec_1_315() {
+ assert_protoset_from_vec_contains_all!(1, 2, 3, 15);
}
#[test]
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 157027750f..8624afeafa 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -89,11 +89,17 @@ impl fmt::Display for UnknownProtocol {
}
}
+fn is_valid_proto(s: &str) -> bool {
+ s.chars().all(|c| c.is_ascii_alphanumeric() || c == '-')
+}
+
impl FromStr for UnknownProtocol {
type Err = ProtoverError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
- if s.len() <= MAX_PROTOCOL_NAME_LENGTH {
+ if !is_valid_proto(s) {
+ Err(ProtoverError::InvalidProtocol)
+ } else if s.len() <= MAX_PROTOCOL_NAME_LENGTH {
Ok(UnknownProtocol(s.to_string()))
} else {
Err(ProtoverError::ExceedsNameLimit)
@@ -105,6 +111,9 @@ impl UnknownProtocol {
/// Create an `UnknownProtocol`, ignoring whether or not it
/// exceeds MAX_PROTOCOL_NAME_LENGTH.
fn from_str_any_len(s: &str) -> Result<Self, ProtoverError> {
+ if !is_valid_proto(s) {
+ return Err(ProtoverError::InvalidProtocol);
+ }
Ok(UnknownProtocol(s.to_string()))
}
}
@@ -115,6 +124,17 @@ impl From<Protocol> for UnknownProtocol {
}
}
+#[cfg(feature = "test_linking_hack")]
+fn have_linkauth_v1() -> bool {
+ true
+}
+
+#[cfg(not(feature = "test_linking_hack"))]
+fn have_linkauth_v1() -> bool {
+ use external::c_tor_is_using_nss;
+ !c_tor_is_using_nss()
+}
+
/// Get a CStr representation of current supported protocols, for
/// passing to C, or for converting to a `&str` for Rust.
///
@@ -132,18 +152,33 @@ impl From<Protocol> for UnknownProtocol {
///
// C_RUST_COUPLED: protover.c `protover_get_supported_protocols`
pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
- cstr!(
- "Cons=1-2 \
- Desc=1-2 \
- DirCache=1-2 \
- HSDir=1-2 \
- HSIntro=3-4 \
- HSRend=1-2 \
- Link=1-5 \
- LinkAuth=1,3 \
- Microdesc=1-2 \
- Relay=1-2"
- )
+ if !have_linkauth_v1() {
+ cstr!(
+ "Cons=1-2 \
+ Desc=1-2 \
+ DirCache=1-2 \
+ HSDir=1-2 \
+ HSIntro=3-4 \
+ HSRend=1-2 \
+ Link=1-5 \
+ LinkAuth=3 \
+ Microdesc=1-2 \
+ Relay=1-2"
+ )
+ } else {
+ cstr!(
+ "Cons=1-2 \
+ Desc=1-2 \
+ DirCache=1-2 \
+ HSDir=1-2 \
+ HSIntro=3-4 \
+ HSRend=1-2 \
+ Link=1-5 \
+ LinkAuth=1,3 \
+ Microdesc=1-2 \
+ Relay=1-2"
+ )
+ }
}
/// A map of protocol names to the versions of them which are supported.
@@ -345,7 +380,6 @@ impl UnvalidatedProtoEntry {
let maybe_supported_versions: Option<&ProtoSet> = supported.get(&supported_protocol);
let supported_versions: &ProtoSet;
- let mut unsupported_versions: ProtoSet;
// If the protocol wasn't in the map, then we don't know about it
// and don't support any of its versions. Add its versions to the
@@ -358,8 +392,7 @@ impl UnvalidatedProtoEntry {
} else {
supported_versions = maybe_supported_versions.unwrap();
}
- unsupported_versions = versions.clone();
- unsupported_versions.retain(|x| !supported_versions.contains(x));
+ let unsupported_versions = versions.and_not_in(supported_versions);
if !unsupported_versions.is_empty() {
unsupported.insert(protocol.clone(), unsupported_versions);
@@ -772,6 +805,29 @@ mod test {
use super::*;
+ macro_rules! parse_proto {
+ ($e:expr) => {{
+ let proto: Result<UnknownProtocol, _> = $e.parse();
+ let proto2 = UnknownProtocol::from_str_any_len($e);
+ assert_eq!(proto, proto2);
+ proto
+ }};
+ }
+
+ #[test]
+ fn test_protocol_from_str() {
+ assert!(parse_proto!("Cons").is_ok());
+ assert!(parse_proto!("123").is_ok());
+ assert!(parse_proto!("1-2-3").is_ok());
+
+ let err = Err(ProtoverError::InvalidProtocol);
+ assert_eq!(err, parse_proto!("a_b_c"));
+ assert_eq!(err, parse_proto!("a b"));
+ assert_eq!(err, parse_proto!("a,"));
+ assert_eq!(err, parse_proto!("b."));
+ assert_eq!(err, parse_proto!("é"));
+ }
+
macro_rules! assert_protoentry_is_parseable {
($e:expr) => {
let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse();
@@ -862,10 +918,10 @@ mod test {
#[test]
fn test_protoentry_all_supported_unsupported_low_version() {
- let protocols: UnvalidatedProtoEntry = "Cons=0-1".parse().unwrap();
+ let protocols: UnvalidatedProtoEntry = "HSIntro=2-3".parse().unwrap();
let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
assert_eq!(true, unsupported.is_some());
- assert_eq!("Cons=0", &unsupported.unwrap().to_string());
+ assert_eq!("HSIntro=2", &unsupported.unwrap().to_string());
}
#[test]
diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs
index a091e692d6..86e276cf73 100644
--- a/src/rust/protover/tests/protover.rs
+++ b/src/rust/protover/tests/protover.rs
@@ -106,10 +106,10 @@ fn protocol_all_supported_with_unsupported_versions() {
#[test]
fn protocol_all_supported_with_unsupported_low_version() {
- let protocols: UnvalidatedProtoEntry = "Cons=0-1".parse().unwrap();
+ let protocols: UnvalidatedProtoEntry = "HSIntro=2-3".parse().unwrap();
let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
assert_eq!(true, unsupported.is_some());
- assert_eq!("Cons=0", &unsupported.unwrap().to_string());
+ assert_eq!("HSIntro=2", &unsupported.unwrap().to_string());
}
#[test]
@@ -364,18 +364,18 @@ fn protover_all_supported_should_exclude_some_versions_and_entire_protocols() {
#[test]
fn protover_all_supported_should_not_dos_anyones_computer() {
- let proto: UnvalidatedProtoEntry = "Sleen=0-2147483648".parse().unwrap();
+ let proto: UnvalidatedProtoEntry = "Link=1-2147483648".parse().unwrap();
let result: String = proto.all_supported().unwrap().to_string();
- assert_eq!(result, "Sleen=0-2147483648".to_string());
+ assert_eq!(result, "Link=6-2147483648".to_string());
}
#[test]
fn protover_all_supported_should_not_dos_anyones_computer_max_versions() {
- let proto: UnvalidatedProtoEntry = "Sleen=0-4294967294".parse().unwrap();
+ let proto: UnvalidatedProtoEntry = "Link=1-4294967294".parse().unwrap();
let result: String = proto.all_supported().unwrap().to_string();
- assert_eq!(result, "Sleen=0-4294967294".to_string());
+ assert_eq!(result, "Link=6-4294967294".to_string());
}
#[test]
@@ -398,7 +398,7 @@ fn protover_unvalidatedprotoentry_should_err_entirely_unparseable_things() {
#[test]
fn protover_all_supported_over_maximum_limit() {
- let proto: Result<UnvalidatedProtoEntry, ProtoverError> = "Sleen=0-4294967295".parse();
+ let proto: Result<UnvalidatedProtoEntry, ProtoverError> = "Sleen=1-4294967295".parse();
assert_eq!(Err(ProtoverError::ExceedsMax), proto);
}
diff --git a/src/rust/smartlist/Cargo.toml b/src/rust/smartlist/Cargo.toml
index 6ddcbee8e9..a5afe7bf74 100644
--- a/src/rust/smartlist/Cargo.toml
+++ b/src/rust/smartlist/Cargo.toml
@@ -9,5 +9,10 @@ libc = "0.2.39"
[lib]
name = "smartlist"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
+[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
diff --git a/src/rust/smartlist/lib.rs b/src/rust/smartlist/lib.rs
index 2716842af2..34d0b907ed 100644
--- a/src/rust/smartlist/lib.rs
+++ b/src/rust/smartlist/lib.rs
@@ -6,3 +6,12 @@ extern crate libc;
mod smartlist;
pub use smartlist::*;
+
+// When testing we may be compiled with sanitizers which are incompatible with
+// Rust's default allocator, jemalloc (unsure why at this time). Most crates
+// link to `tor_allocate` which switches by default to a non-jemalloc allocator,
+// but we don't already depend on `tor_allocate` so make sure that while testing
+// we don't use jemalloc. (but rather malloc/free)
+#[global_allocator]
+#[cfg(test)]
+static A: std::alloc::System = std::alloc::System;
diff --git a/src/rust/tor_allocate/Cargo.toml b/src/rust/tor_allocate/Cargo.toml
index 468425f115..06ac605f17 100644
--- a/src/rust/tor_allocate/Cargo.toml
+++ b/src/rust/tor_allocate/Cargo.toml
@@ -9,5 +9,10 @@ libc = "=0.2.39"
[lib]
name = "tor_allocate"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
+[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs
index 5a355bc8d6..1cfa0b5178 100644
--- a/src/rust/tor_allocate/lib.rs
+++ b/src/rust/tor_allocate/lib.rs
@@ -11,5 +11,10 @@
extern crate libc;
+use std::alloc::System;
+
mod tor_allocate;
pub use tor_allocate::*;
+
+#[global_allocator]
+static A: System = System;
diff --git a/src/rust/tor_log/Cargo.toml b/src/rust/tor_log/Cargo.toml
index 9d06299c05..14d9ae803a 100644
--- a/src/rust/tor_log/Cargo.toml
+++ b/src/rust/tor_log/Cargo.toml
@@ -6,9 +6,13 @@ authors = ["The Tor Project"]
[lib]
name = "tor_log"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
[dependencies]
libc = "0.2.39"
diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs
index 5231d0c631..757c74ff49 100644
--- a/src/rust/tor_log/tor_log.rs
+++ b/src/rust/tor_log/tor_log.rs
@@ -89,15 +89,15 @@ pub mod log {
use super::LogSeverity;
use libc::{c_char, c_int};
- /// Severity log types. These mirror definitions in /src/common/torlog.h
- /// C_RUST_COUPLED: src/common/log.c, log domain types
+ /// Severity log types. These mirror definitions in src/lib/log/log.h
+ /// C_RUST_COUPLED: src/lib/log/log.c, log domain types
extern "C" {
static LOG_WARN_: c_int;
static LOG_NOTICE_: c_int;
}
- /// Domain log types. These mirror definitions in /src/common/torlog.h
- /// C_RUST_COUPLED: src/common/log.c, log severity types
+ /// Domain log types. These mirror definitions in src/lib/log/log.h
+ /// C_RUST_COUPLED: src/lib/log/log.c, log severity types
extern "C" {
static LD_NET_: u32;
static LD_GENERAL_: u32;
diff --git a/src/rust/tor_rust/Cargo.toml b/src/rust/tor_rust/Cargo.toml
index 86fad3ee76..35c629882e 100644
--- a/src/rust/tor_rust/Cargo.toml
+++ b/src/rust/tor_rust/Cargo.toml
@@ -6,7 +6,7 @@ version = "0.1.0"
[lib]
name = "tor_rust"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
+crate_type = ["staticlib"]
[dependencies.tor_util]
path = "../tor_util"
@@ -14,3 +14,9 @@ path = "../tor_util"
[dependencies.protover]
path = "../protover"
+[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []
diff --git a/src/rust/tor_util/Cargo.toml b/src/rust/tor_util/Cargo.toml
index a606a280b2..9ffaeda8a6 100644
--- a/src/rust/tor_util/Cargo.toml
+++ b/src/rust/tor_util/Cargo.toml
@@ -6,7 +6,6 @@ version = "0.0.1"
[lib]
name = "tor_util"
path = "lib.rs"
-crate_type = ["rlib", "staticlib"]
[dependencies.tor_allocate]
path = "../tor_allocate"
@@ -17,3 +16,9 @@ path = "../tor_log"
[dependencies]
libc = "=0.2.39"
+[features]
+# We have to define a feature here because doctests don't get cfg(test),
+# and we need to disable some C dependencies when running the doctests
+# because of the various linker issues. See
+# https://github.com/rust-lang/rust/issues/45599
+test_linking_hack = []