Skip to content

Commit f6b83d4

Browse files
committed
Support arbitrary::Arbitrary
num-bigint already supports quickcheck::Arbitrary which works roughly like arbitrary::Arbitrary. arbitrary::Arbitrary used by cargo-fuzz and makes it easier to use num-bigint BigInt and BigUint in projects that want to fuzz that way.
1 parent 7562ab2 commit f6b83d4

File tree

7 files changed

+86
-15
lines changed

7 files changed

+86
-15
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ exclude = ["/bors.toml", "/ci/*", "/.github/*"]
1515
edition = "2018"
1616

1717
[package.metadata.docs.rs]
18-
features = ["std", "serde", "rand", "quickcheck"]
18+
features = ["std", "serde", "rand", "quickcheck", "arbitrary"]
1919

2020
[[bench]]
2121
name = "bigint"
@@ -60,6 +60,11 @@ optional = true
6060
version = "0.9"
6161
default-features = false
6262

63+
[dependencies.arbitrary]
64+
optional = true
65+
version = "0.4"
66+
default-features = false
67+
6368
[features]
6469
default = ["std"]
6570
std = ["num-integer/std", "num-traits/std"]

fuzz/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
target
2+
corpus
3+
artifacts

fuzz/Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "num-bigint-fuzz"
3+
version = "0.0.0"
4+
authors = ["Automatically generated"]
5+
publish = false
6+
edition = "2018"
7+
8+
[package.metadata]
9+
cargo-fuzz = true
10+
11+
[dependencies]
12+
libfuzzer-sys = "0.3"
13+
14+
[dependencies.num-bigint]
15+
path = ".."
16+
features = ["arbitrary"]
17+
18+
# Prevent this from interfering with workspaces
19+
[workspace]
20+
members = ["."]
21+
22+
[[bin]]
23+
name = "fuzz_target_1"
24+
path = "fuzz_targets/fuzz_target_1.rs"
25+
test = false
26+
doc = false

fuzz/fuzz_targets/fuzz_target_1.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
use num_bigint::BigUint;
4+
5+
fuzz_target!(|a: BigUint| {
6+
assert_eq!((&a * &a).sqrt(), a);
7+
});

src/bigint.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// `Add`/`Sub` ops may flip from `BigInt` to its `BigUint` magnitude
22
#![allow(clippy::suspicious_arithmetic_impl)]
33

4-
#[cfg(feature = "quickcheck")]
4+
#[cfg(any(feature = "quickcheck", feature = "arbitrary"))]
55
use crate::std_alloc::Box;
66
use crate::std_alloc::{String, Vec};
77
use core::cmp::Ordering::{self, Equal, Greater, Less};
@@ -39,9 +39,6 @@ use crate::TryFromBigIntError;
3939
use crate::IsizePromotion;
4040
use crate::UsizePromotion;
4141

42-
#[cfg(feature = "quickcheck")]
43-
use quickcheck::{Arbitrary, Gen};
44-
4542
/// A Sign is a `BigInt`'s composing element.
4643
#[derive(PartialEq, PartialOrd, Eq, Ord, Copy, Clone, Debug, Hash)]
4744
pub enum Sign {
@@ -141,8 +138,8 @@ impl Clone for BigInt {
141138
}
142139

143140
#[cfg(feature = "quickcheck")]
144-
impl Arbitrary for BigInt {
145-
fn arbitrary<G: Gen>(g: &mut G) -> Self {
141+
impl quickcheck::Arbitrary for BigInt {
142+
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
146143
let positive = bool::arbitrary(g);
147144
let sign = if positive { Sign::Plus } else { Sign::Minus };
148145
Self::from_biguint(sign, BigUint::arbitrary(g))
@@ -155,6 +152,26 @@ impl Arbitrary for BigInt {
155152
}
156153
}
157154

155+
#[cfg(feature = "arbitrary")]
156+
mod abitrary_impl {
157+
use super::*;
158+
use arbitrary::{Arbitrary, Result, Unstructured};
159+
160+
impl Arbitrary for BigInt {
161+
fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
162+
let positive = bool::arbitrary(u)?;
163+
let sign = if positive { Sign::Plus } else { Sign::Minus };
164+
Ok(Self::from_biguint(sign, BigUint::arbitrary(u)?))
165+
}
166+
167+
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
168+
let sign = self.sign();
169+
let unsigned_shrink = self.data.shrink();
170+
Box::new(unsigned_shrink.map(move |x| BigInt::from_biguint(sign, x)))
171+
}
172+
}
173+
}
174+
158175
impl hash::Hash for BigInt {
159176
#[inline]
160177
fn hash<H: hash::Hasher>(&self, state: &mut H) {

src/biguint.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[cfg(feature = "quickcheck")]
1+
#[cfg(any(feature = "quickcheck", feature = "arbitrary"))]
22
use crate::std_alloc::Box;
33
use crate::std_alloc::{Cow, String, Vec};
44
use core::cmp;
@@ -45,9 +45,6 @@ use crate::ParseBigIntError;
4545
#[cfg(has_try_from)]
4646
use crate::TryFromBigIntError;
4747

48-
#[cfg(feature = "quickcheck")]
49-
use quickcheck::{Arbitrary, Gen};
50-
5148
/// A big unsigned integer type.
5249
#[derive(Debug)]
5350
pub struct BigUint {
@@ -71,8 +68,8 @@ impl Clone for BigUint {
7168
}
7269

7370
#[cfg(feature = "quickcheck")]
74-
impl Arbitrary for BigUint {
75-
fn arbitrary<G: Gen>(g: &mut G) -> Self {
71+
impl quickcheck::Arbitrary for BigUint {
72+
fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
7673
// Use arbitrary from Vec
7774
biguint_from_vec(Vec::<BigDigit>::arbitrary(g))
7875
}
@@ -83,6 +80,22 @@ impl Arbitrary for BigUint {
8380
}
8481
}
8582

83+
#[cfg(feature = "arbitrary")]
84+
mod abitrary_impl {
85+
use super::*;
86+
use arbitrary::{Arbitrary, Result, Unstructured};
87+
88+
impl Arbitrary for BigUint {
89+
fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
90+
Ok(biguint_from_vec(Vec::<BigDigit>::arbitrary(u)?))
91+
}
92+
93+
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
94+
Box::new(self.data.shrink().map(biguint_from_vec))
95+
}
96+
}
97+
}
98+
8699
impl hash::Hash for BigUint {
87100
#[inline]
88101
fn hash<H: hash::Hasher>(&self, state: &mut H) {

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ extern crate std;
9494
#[cfg(feature = "std")]
9595
mod std_alloc {
9696
pub(crate) use std::borrow::Cow;
97-
#[cfg(feature = "quickcheck")]
97+
#[cfg(any(feature = "quickcheck", feature = "arbitrary"))]
9898
pub(crate) use std::boxed::Box;
9999
pub(crate) use std::string::String;
100100
pub(crate) use std::vec::Vec;
@@ -107,7 +107,7 @@ extern crate alloc;
107107
#[cfg(not(feature = "std"))]
108108
mod std_alloc {
109109
pub(crate) use alloc::borrow::Cow;
110-
#[cfg(feature = "quickcheck")]
110+
#[cfg(any(feature = "quickcheck", feature = "arbitrary"))]
111111
pub(crate) use alloc::boxed::Box;
112112
pub(crate) use alloc::string::String;
113113
pub(crate) use alloc::vec::Vec;

0 commit comments

Comments
 (0)