Skip to content

Commit

Permalink
Enforce bounds on numeric literals in type constructors
Browse files Browse the repository at this point in the history
Fixes #145
  • Loading branch information
cburgdorf committed Dec 18, 2020
1 parent 8e3189b commit 32c22f1
Show file tree
Hide file tree
Showing 34 changed files with 391 additions and 16 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 25 additions & 1 deletion compiler/tests/compile_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,31 @@ use std::fs;
case("indexed_event.fe", "MoreThanThreeIndexedParams"),
case("unary_minus_on_bool.fe", "TypeError"),
case("type_constructor_from_variable.fe", "NumericLiteralExpected"),
case("needs_mem_copy.fe", "CannotMove")
case("needs_mem_copy.fe", "CannotMove"),
case("numeric_capacity_mismatch/u8_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u8_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u16_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u16_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u32_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u32_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u64_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u64_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u128_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u128_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u256_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/u256_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i8_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i8_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i16_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i16_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i32_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i32_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i64_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i64_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i128_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i128_pos.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i256_neg.fe", "NumericCapacityMismatch"),
case("numeric_capacity_mismatch/i256_pos.fe", "NumericCapacityMismatch")
)]
fn test_compile_errors(fixture_file: &str, expected_error: &str) {
let src = fs::read_to_string(format!("tests/fixtures/compile_errors/{}", fixture_file))
Expand Down
116 changes: 113 additions & 3 deletions compiler/tests/evm_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,17 @@ fn to_2s_complement(val: isize) -> U256 {
return U256::from(val);
} else {
let positive_val = val * -1;
let temp = U256::from(positive_val);
let (negated, _) = temp.overflowing_neg();
return negated + 1;
return get_2s_complement_for_negative(U256::from(positive_val));
}
}

/// To get the 2s complement value for e.g. -128 call
/// get_2s_complement_for_negative(128)
fn get_2s_complement_for_negative(assume_negative: U256) -> U256 {
let (negated, _) = assume_negative.overflowing_neg();
return negated + 1;
}

#[test]
fn test_to_2s_complement() {
let minus_three = U256::from_dec_str(
Expand Down Expand Up @@ -752,6 +757,111 @@ fn strings() {
});
}

#[test]
fn test_numeric_sizes() {
with_executor(&|mut executor| {
let harness = deploy_contract(&mut executor, "numeric_sizes.fe", "Foo", vec![]);

struct SizeConfig {
size: usize,
u_min: ethabi::Token,
i_min: ethabi::Token,
u_max: ethabi::Token,
i_max: ethabi::Token,
}

let zero = uint_token(0);
let u64_max = ethabi::Token::Uint(U256::from(2).pow(U256::from(64)) - 1);
let i64_min = ethabi::Token::Int(get_2s_complement_for_negative(
U256::from(2).pow(U256::from(63)),
));

let u128_max = ethabi::Token::Uint(U256::from(2).pow(U256::from(128)) - 1);
let i128_max = ethabi::Token::Int(U256::from(2).pow(U256::from(127)) - 1);
let i128_min = ethabi::Token::Int(get_2s_complement_for_negative(
U256::from(2).pow(U256::from(127)),
));

let u256_max = ethabi::Token::Uint(U256::MAX);
let i256_max = ethabi::Token::Int(U256::from(2).pow(U256::from(255)) - 1);
let i256_min = ethabi::Token::Int(get_2s_complement_for_negative(
U256::from(2).pow(U256::from(255)),
));

let sizes = [
SizeConfig {
size: 8,
u_min: zero.clone(),
i_min: int_token(-128),
u_max: uint_token(255),
i_max: int_token(127),
},
SizeConfig {
size: 16,
u_min: zero.clone(),
i_min: int_token(-32768),
u_max: uint_token(65535),
i_max: int_token(32767),
},
SizeConfig {
size: 32,
u_min: zero.clone(),
i_min: int_token(-2147483648),
u_max: uint_token(4294967295),
i_max: int_token(2147483647),
},
SizeConfig {
size: 64,
u_min: zero.clone(),
i_min: i64_min.clone(),
u_max: u64_max.clone(),
i_max: int_token(9223372036854775807),
},
SizeConfig {
size: 128,
u_min: zero.clone(),
i_min: i128_min.clone(),
u_max: u128_max.clone(),
i_max: i128_max.clone(),
},
SizeConfig {
size: 256,
u_min: zero.clone(),
i_min: i256_min.clone(),
u_max: u256_max.clone(),
i_max: i256_max.clone(),
},
];

for config in sizes.iter() {
harness.test_function(
&mut executor,
&format!("get_u{}_min", config.size),
vec![],
Some(config.u_min.clone()),
);
harness.test_function(
&mut executor,
&format!("get_u{}_max", config.size),
vec![],
Some(config.u_max.clone()),
);
harness.test_function(
&mut executor,
&format!("get_i{}_min", config.size),
vec![],
Some(config.i_min.clone()),
);
harness.test_function(
&mut executor,
&format!("get_i{}_max", config.size),
vec![],
Some(config.i_max.clone()),
);
}
})
}

#[test]
fn sized_vals_in_sto() {
with_executor(&|mut executor| {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i128:
return i128(-170141183460469231731687303715884105729)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i128:
return i128(170141183460469231731687303715884105728)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i16:
return i16(-32769)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i16:
return i16(32768)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i256:
return i256(-57896044618658097711785492504343953926634992332820282019728792003956564819969)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i256:
return i256(57896044618658097711785492504343953926634992332820282019728792003956564819968)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i32:
return i32(-2147483649)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i32:
return i32(2147483648)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i64:
return i64(-9223372036854775809)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i64:
return i64(9223372036854775808)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i8:
return i8(-129)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> i8:
return i8(128)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u128:
return u128(-1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u128:
return u128(340282366920938463463374607431768211456)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u16:
return u16(-1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u16:
return u16(65536)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u256:
return u256(-1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u256:
return u256(115792089237316195423570985008687907853269984665640564039457584007913129639936)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u32:
return u32(-1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u32:
return u32(4294967296)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u64:
return u64(-1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u64:
return u64(18446744073709551616)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u8:
return u8(-1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
contract Foo:
pub def bar() -> u8:
return u8(256)
73 changes: 73 additions & 0 deletions compiler/tests/fixtures/numeric_sizes.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
contract Foo:

pub def get_u8_min() -> u8:
return u8(0)

pub def get_u16_min() -> u16:
return u16(0)

pub def get_u32_min() -> u32:
return u32(0)

pub def get_u64_min() -> u64:
return u64(0)

pub def get_u128_min() -> u128:
return u128(0)

pub def get_u256_min() -> u256:
return u256(0)

pub def get_i8_min() -> i8:
return i8(-128)

pub def get_i16_min() -> i16:
return i16(-32768)

pub def get_i32_min() -> i32:
return i32(-2147483648)

pub def get_i64_min() -> i64:
return i64(-9223372036854775808)

pub def get_i128_min() -> i128:
return i128(-170141183460469231731687303715884105728)

pub def get_i256_min() -> i256:
return i256(-57896044618658097711785492504343953926634992332820282019728792003956564819968)

pub def get_u8_max() -> u8:
return u8(255)

pub def get_u16_max() -> u16:
return u16(65535)

pub def get_u32_max() -> u32:
return u32(4294967295)

pub def get_u64_max() -> u64:
return u64(18446744073709551615)

pub def get_u128_max() -> u128:
return u128(340282366920938463463374607431768211455)

pub def get_u256_max() -> u256:
return u256(115792089237316195423570985008687907853269984665640564039457584007913129639935)

pub def get_i8_max() -> i8:
return i8(127)

pub def get_i16_max() -> i16:
return i16(32767)

pub def get_i32_max() -> i32:
return i32(2147483647)

pub def get_i64_max() -> i64:
return i64(9223372036854775807)

pub def get_i128_max() -> i128:
return i128(170141183460469231731687303715884105727)

pub def get_i256_max() -> i256:
return i256(57896044618658097711785492504343953926634992332820282019728792003956564819967)
4 changes: 4 additions & 0 deletions newsfragments/145.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Enforce bounds on numeric literals in type constructors.

For instance calling `u8(1000)` or `i8(-250)` will give an error because
the literals `1000` and `-250` do not fit into `u8` or `i8`.
1 change: 1 addition & 0 deletions semantics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ rstest = "0.6.4"
tiny-keccak = { version = "2.0", features = ["keccak"] }
hex = "0.4"
ansi_term = "0.12.1"
num-bigint = "0.3.1"
Loading

0 comments on commit 32c22f1

Please sign in to comment.