Skip to content

Commit b4f7889

Browse files
authored
Merge pull request #963 from schungx/master
Fix integer overflow bug
2 parents 04c48d1 + 7c59555 commit b4f7889

File tree

6 files changed

+51
-31
lines changed

6 files changed

+51
-31
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Rhai Release Notes
22
==================
33

4+
Version 1.22.0
5+
==============
6+
7+
Bug fixes
8+
---------
9+
10+
* (Fuzzing) An integer-overflow bug from an inclusive range in `get_bits` is fixed.
11+
12+
413
Version 1.21.0
514
==============
615

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ serde_json = { version = "1.0.45", default-features = false, features = ["alloc"
3636
unicode-xid = { version = "0.2.0", default-features = false, optional = true }
3737
rust_decimal = { version = "1.16.0", default-features = false, features = ["maths"], optional = true }
3838
getrandom = { version = "0.2.0", optional = true }
39-
rustyline = { version = "13.0.0", optional = true }
39+
rustyline = { version = "15.0.0", optional = true }
4040
document-features = { version = "0.2.0", optional = true }
4141
arbitrary = { version = "1.3.2", optional = true, features = ["derive"] }
4242

@@ -164,7 +164,7 @@ features = ["document-features", "metadata", "serde", "internals", "decimal", "d
164164
[patch.crates-io]
165165
# Notice that a custom modified version of `rustyline` is used which supports bracketed paste on Windows.
166166
# This can be moved to the official version when bracketed paste is added.
167-
rustyline = { git = "https://github.com/schungx/rustyline", branch = "v13" }
167+
rustyline = { git = "https://github.com/schungx/rustyline", branch = "v15_fake" }
168168

169169
# Patch SmartString to resolve an UB issue.
170170
#smartstring = { git = "https://github.com/bodil/smartstring", ref = "refs/pull/34/head" }

codegen/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ pub fn derive_custom_type(input: TokenStream) -> TokenStream {
312312
/// Macro to automatically expose a Rust function, type-def or use statement as `pub` when under the
313313
/// `internals` feature.
314314
///
315-
/// If the `internals` is not enabled, the item will be exposed as `pub(crate)`.
315+
/// If the `internals` feature is not enabled, the item will be exposed as `pub(crate)`.
316316
///
317317
/// In order to avoid confusion, there must not be any visibility modifier on the item.
318318
#[proc_macro_attribute]

src/packages/bit_field.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::eval::calc_index;
22
use crate::plugin::*;
33
use crate::{
44
def_package, ExclusiveRange, InclusiveRange, Position, RhaiResultOf, ERR, INT, INT_BITS,
5-
UNSIGNED_INT,
5+
MAX_USIZE_INT, UNSIGNED_INT,
66
};
77
#[cfg(feature = "no_std")]
88
use std::prelude::v1::*;
@@ -106,6 +106,12 @@ mod bit_field_functions {
106106
pub fn get_bits_range_inclusive(value: INT, range: InclusiveRange) -> RhaiResultOf<INT> {
107107
let from = INT::max(*range.start(), 0);
108108
let to = INT::max(*range.end(), from - 1);
109+
110+
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
111+
if to > MAX_USIZE_INT || (to as usize) >= INT_BITS {
112+
return Err(ERR::ErrorBitFieldBounds(INT_BITS, to, Position::NONE).into());
113+
}
114+
109115
get_bits(value, from, to - from + 1)
110116
}
111117
/// Return a portion of bits in the number as a new number.
@@ -126,6 +132,11 @@ mod bit_field_functions {
126132
if bits <= 0 {
127133
return Ok(0);
128134
}
135+
let bits = if bits > MAX_USIZE_INT {
136+
MAX_USIZE_INT
137+
} else {
138+
bits
139+
};
129140

130141
let bit = calc_index(INT_BITS, start, true, || {
131142
ERR::ErrorBitFieldBounds(INT_BITS, start, Position::NONE).into()

src/tokenizer.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,23 +1195,23 @@ pub trait InputStream {
11951195
///
11961196
/// # Returns
11971197
///
1198-
/// | Type | Return Value |`state.is_within_text_terminated_by` |
1199-
/// |---------------------------|:-----------------------------------:|:------------------------------------:|
1200-
/// |`#"hello"#` |`StringConstant("hello")` |`None` |
1201-
/// |`#"hello`_{EOF}_ |`StringConstant("hello")` |`Some("#")` |
1202-
/// |`####"hello`_{EOF}_ |`StringConstant("hello")` |`Some("####")` |
1203-
/// |`#" "hello" "`_{EOF}_ |`LexError` |`None` |
1204-
/// |`#""hello""#` |`StringConstant("\"hello\"")` |`None` |
1205-
/// |`##"hello #"# world"##` |`StringConstant("hello #\"# world")` |`None` |
1206-
/// |`#"R"#` |`StringConstant("R")` |`None` |
1207-
/// |`#"\x52"#` |`StringConstant("\\x52")` |`None` |
1198+
/// | Type | Return Value |`state.is_within_text_terminated_by` |
1199+
/// |---------------------------|:------------------------------------------------------------:|:------------------------------------:|
1200+
/// |`#"hello"#` |[`StringConstant("hello")`][Token::StringConstant] |`None` |
1201+
/// |`#"hello`_{EOF}_ |[`StringConstant("hello")`][Token::StringConstant] |`Some("#")` |
1202+
/// |`####"hello`_{EOF}_ |[`StringConstant("hello")`][Token::StringConstant] |`Some("####")` |
1203+
/// |`#" "hello" "`_{EOF}_ |[`LexError`] |`None` |
1204+
/// |`#""hello""#` |[`StringConstant("\"hello\"")`][Token::StringConstant] |`None` |
1205+
/// |`##"hello #"# world"##` |[`StringConstant("hello #\"# world")`][Token::StringConstant] |`None` |
1206+
/// |`#"R"#` |[`StringConstant("R")`][Token::StringConstant] |`None` |
1207+
/// |`#"\x52"#` |[`StringConstant("\\x52")`][Token::StringConstant] |`None` |
12081208
///
1209-
/// This function does _not_ throw a `LexError` for an unterminated raw string at _{EOF}_
1209+
/// This function does _not_ throw a [`LexError`] for an unterminated raw string at _{EOF}_
12101210
///
12111211
/// This is to facilitate using this function to parse a script line-by-line, where the end of the
12121212
/// line (i.e. _{EOF}_) is not necessarily the end of the script.
12131213
///
1214-
/// Any time a [`StringConstant`][`Token::StringConstant`] is returned with
1214+
/// Any time a [`StringConstant`][Token::StringConstant] is returned with
12151215
/// `state.is_within_text_terminated_by` set to `Some(_)` is one of the above conditions.
12161216
pub fn parse_raw_string_literal(
12171217
stream: &mut (impl InputStream + ?Sized),
@@ -1321,18 +1321,18 @@ pub fn parse_raw_string_literal(
13211321
///
13221322
/// # Returns
13231323
///
1324-
/// | Type | Return Value |`state.is_within_text_terminated_by`|
1325-
/// |---------------------------------|:--------------------------:|:----------------------------------:|
1326-
/// |`"hello"` |`StringConstant("hello")` |`None` |
1327-
/// |`"hello`_{LF}_ or _{EOF}_ |`LexError` |`None` |
1328-
/// |`"hello\`_{EOF}_ or _{LF}{EOF}_ |`StringConstant("hello")` |`Some('"')` |
1329-
/// |`` `hello``_{EOF}_ |`StringConstant("hello")` |``Some('`')`` |
1330-
/// |`` `hello``_{LF}{EOF}_ |`StringConstant("hello\n")` |``Some('`')`` |
1331-
/// |`` `hello ${`` |`InterpolatedString("hello ")`<br/>next token is `{`|`None` |
1332-
/// |`` } hello` `` |`StringConstant(" hello")` |`None` |
1333-
/// |`} hello`_{EOF}_ |`StringConstant(" hello")` |``Some('`')`` |
1324+
/// | Type | Return Value |`state.is_within_text_terminated_by`|
1325+
/// |---------------------------------|:---------------------------------------------------:|:----------------------------------:|
1326+
/// |`"hello"` |[`StringConstant("hello")`][Token::StringConstant] |`None` |
1327+
/// |`"hello`_{LF}_ or _{EOF}_ |[`LexError`] |`None` |
1328+
/// |`"hello\`_{EOF}_ or _{LF}{EOF}_ |[`StringConstant("hello")`][Token::StringConstant] |`Some('"')` |
1329+
/// |`` `hello``_{EOF}_ |[`StringConstant("hello")`][Token::StringConstant] |``Some('`')`` |
1330+
/// |`` `hello``_{LF}{EOF}_ |[`StringConstant("hello\n")`][Token::StringConstant] |``Some('`')`` |
1331+
/// |`` `hello ${`` |[`InterpolatedString("hello ")`][Token::InterpolatedString]<br/>next token is `{`|`None` |
1332+
/// |`` } hello` `` |[`StringConstant(" hello")`][Token::StringConstant] |`None` |
1333+
/// |`} hello`_{EOF}_ |[`StringConstant(" hello")`][Token::StringConstant] |``Some('`')`` |
13341334
///
1335-
/// This function does not throw a `LexError` for the following conditions:
1335+
/// This function does not throw a [`LexError`] for the following conditions:
13361336
///
13371337
/// * Unterminated literal string at _{EOF}_
13381338
///
@@ -1341,7 +1341,7 @@ pub fn parse_raw_string_literal(
13411341
/// This is to facilitate using this function to parse a script line-by-line, where the end of the
13421342
/// line (i.e. _{EOF}_) is not necessarily the end of the script.
13431343
///
1344-
/// Any time a [`StringConstant`][`Token::StringConstant`] is returned with
1344+
/// Any time a [`StringConstant`][Token::StringConstant] is returned with
13451345
/// `state.is_within_text_terminated_by` set to `Some(_)` is one of the above conditions.
13461346
pub fn parse_string_literal(
13471347
stream: &mut (impl InputStream + ?Sized),

tests/get_set.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,12 @@ fn test_get_set_chain_without_write_back() {
163163

164164
engine
165165
.register_type::<Inner>()
166-
.register_get_set("value", |t: &mut Inner| t.value, |_: NativeCallContext, _: &mut Inner, new: INT| panic!("Inner::value setter called with {}", new))
166+
.register_get_set("value", |t: &mut Inner| t.value, |_: NativeCallContext, _: &mut Inner, new: INT| -> () { panic!("Inner::value setter called with {}", new) })
167167
.register_type::<Outer>()
168-
.register_get_set("inner", |_: NativeCallContext, t: &mut Outer| t.inner.clone(), |_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new));
168+
.register_get_set("inner", |_: NativeCallContext, t: &mut Outer| t.inner.clone(), |_: &mut Outer, new: Inner| -> () { panic!("Outer::inner setter called with {:?}", new) });
169169

170170
#[cfg(not(feature = "no_index"))]
171-
engine.register_indexer_get_set(|t: &mut Outer, n: INT| Inner { value: t.inner.value * n }, |_: &mut Outer, n: INT, new: Inner| panic!("Outer::inner index setter called with {} and {:?}", n, new));
171+
engine.register_indexer_get_set(|t: &mut Outer, n: INT| Inner { value: t.inner.value * n }, |_: &mut Outer, n: INT, new: Inner| -> () { panic!("Outer::inner index setter called with {} and {:?}", n, new) });
172172

173173
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "outer.inner.value").unwrap(), 42);
174174

0 commit comments

Comments
 (0)