Skip to content

Commit a656565

Browse files
Fix potential panics in expression engine (#31)
* Fix potential panics in min/max and division by zero * Update GitHub Actions and fix potential panics * Fix panics in min/max/div and update GitHub Actions --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 7dc211e commit a656565

8 files changed

Lines changed: 102 additions & 20 deletions

File tree

.github/workflows/Build.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- aarch64-unknown-linux-gnu
2323
fail-fast: false
2424
steps:
25-
- uses: actions/checkout@v3
25+
- uses: actions/checkout@v4
2626
- uses: dtolnay/rust-toolchain@master
2727
with:
2828
toolchain: ${{ matrix.version }}
@@ -34,7 +34,7 @@ jobs:
3434
- name: ignored test
3535
run: cargo test -- --ignored || true
3636
if: matrix.version == 'nightly'
37-
- uses: actions/upload-artifact@v3
37+
- uses: actions/upload-artifact@v4
3838
if: failure()
3939
with:
4040
name: linux ${{ matrix.version }}
@@ -55,15 +55,15 @@ jobs:
5555
- x86_64-pc-windows-msvc
5656
fail-fast: false
5757
steps:
58-
- uses: actions/checkout@v3
58+
- uses: actions/checkout@v4
5959
- uses: dtolnay/rust-toolchain@master
6060
with:
6161
toolchain: ${{ matrix.version }}
6262
- name: cache
6363
uses: Swatinem/rust-cache@v2
6464
- name: test
6565
run: cargo test
66-
- uses: actions/upload-artifact@v3
66+
- uses: actions/upload-artifact@v4
6767
if: failure()
6868
with:
6969
name: windows ${{ matrix.version }}
@@ -81,15 +81,15 @@ jobs:
8181
- x86_64-apple-darwin
8282
fail-fast: false
8383
steps:
84-
- uses: actions/checkout@v3
84+
- uses: actions/checkout@v4
8585
- uses: dtolnay/rust-toolchain@master
8686
with:
8787
toolchain: ${{ matrix.version }}
8888
- name: cache
8989
uses: Swatinem/rust-cache@v2
9090
- name: test
9191
run: cargo test
92-
- uses: actions/upload-artifact@v3
92+
- uses: actions/upload-artifact@v4
9393
#if: failure()
9494
with:
9595
name: mac ${{ matrix.version }}

.github/workflows/coverage.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ jobs:
1010
options: --security-opt seccomp=unconfined
1111
steps:
1212
- name: Checkout repository
13-
uses: actions/checkout@v3
13+
uses: actions/checkout@v4
1414

1515
- name: Generate code coverage
1616
run: |
1717
cargo tarpaulin --verbose --all-features --workspace --timeout 120 --out Xml
1818
1919
- name: Upload to codecov.io
20-
uses: codecov/codecov-action@v2
20+
uses: codecov/codecov-action@v4
2121
with:
2222
token: ${{secrets.CODECOV_TOKEN}} # not required for public repos
2323
fail_ci_if_error: true

.github/workflows/rust-clippy.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,13 @@ jobs:
2828
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
2929
steps:
3030
- name: Checkout code
31-
uses: actions/checkout@v2
31+
uses: actions/checkout@v4
3232

3333
- name: Install Rust toolchain
34-
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af #@v1
34+
uses: dtolnay/rust-toolchain@master
3535
with:
36-
profile: minimal
3736
toolchain: stable
3837
components: clippy
39-
override: true
4038

4139
- name: Install required cargo
4240
run: cargo install clippy-sarif sarif-fmt
@@ -49,7 +47,7 @@ jobs:
4947
continue-on-error: true
5048

5149
- name: Upload analysis results to GitHub
52-
uses: github/codeql-action/upload-sarif@v2
50+
uses: github/codeql-action/upload-sarif@v3
5351
with:
5452
sarif_file: rust-clippy-results.sarif
5553
wait-for-processing: true

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616

1717
steps:
18-
- uses: actions/checkout@v3
18+
- uses: actions/checkout@v4
1919
- name: Build
2020
run: cargo build --verbose
2121
- name: Run tests

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub enum Error {
3030
InvalidInteger,
3131
InvalidFloat,
3232
ExpectBinOpToken,
33+
ParamEmpty(String),
34+
DivByZero,
3335
}
3436

3537
#[cfg(not(tarpaulin_include))]
@@ -67,6 +69,8 @@ impl fmt::Display for Error {
6769
InvalidInteger => write!(f, "invalid integer"),
6870
InvalidFloat => write!(f, "invalid float"),
6971
ExpectBinOpToken => write!(f, "expect bin op token"),
72+
ParamEmpty(name) => write!(f, "param empty: {}", name),
73+
DivByZero => write!(f, "division by zero"),
7074
}
7175
}
7276
}

src/function.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ impl InnerFunctionManager {
3030
min = Some(num);
3131
}
3232
}
33-
Ok(Value::Number(min.unwrap()))
33+
if let Some(min) = min {
34+
Ok(Value::Number(min))
35+
} else {
36+
Err(Error::ParamEmpty("min".to_string()))
37+
}
3438
}),
3539
);
3640

@@ -44,7 +48,11 @@ impl InnerFunctionManager {
4448
max = Some(num);
4549
}
4650
}
47-
Ok(Value::Number(max.unwrap()))
51+
if let Some(max) = max {
52+
Ok(Value::Number(max))
53+
} else {
54+
Err(Error::ParamEmpty("max".to_string()))
55+
}
4856
}),
4957
);
5058

src/lib.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,56 @@ mod tests {
257257
assert!(ans.is_ok());
258258
assert_eq!(ans.unwrap(), Value::from(89));
259259
}
260+
261+
#[test]
262+
fn test_min_no_panic() {
263+
use crate::error::Error;
264+
let input = "min()";
265+
let ctx = create_context!();
266+
let ans = execute(input, ctx);
267+
assert!(ans.is_err());
268+
match ans.unwrap_err() {
269+
Error::ParamEmpty(name) => assert_eq!(name, "min"),
270+
_ => panic!("Expected Error::ParamEmpty"),
271+
}
272+
}
273+
274+
#[test]
275+
fn test_max_no_panic() {
276+
use crate::error::Error;
277+
let input = "max()";
278+
let ctx = create_context!();
279+
let ans = execute(input, ctx);
280+
assert!(ans.is_err());
281+
match ans.unwrap_err() {
282+
Error::ParamEmpty(name) => assert_eq!(name, "max"),
283+
_ => panic!("Expected Error::ParamEmpty"),
284+
}
285+
}
286+
287+
#[test]
288+
fn test_div_zero_no_panic() {
289+
use crate::error::Error;
290+
let input = "5 / 0";
291+
let ctx = create_context!();
292+
let ans = execute(input, ctx);
293+
assert!(ans.is_err());
294+
match ans.unwrap_err() {
295+
Error::DivByZero => (),
296+
_ => panic!("Expected Error::DivByZero"),
297+
}
298+
}
299+
300+
#[test]
301+
fn test_mod_zero_no_panic() {
302+
use crate::error::Error;
303+
let input = "5 % 0";
304+
let ctx = create_context!();
305+
let ans = execute(input, ctx);
306+
assert!(ans.is_err());
307+
match ans.unwrap_err() {
308+
Error::DivByZero => (),
309+
_ => panic!("Expected Error::DivByZero"),
310+
}
311+
}
260312
}

src/operator.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,18 @@ impl InfixOpManager {
6969
"+=" => a += b,
7070
"-=" => a -= b,
7171
"*=" => a *= b,
72-
"/=" => a /= b,
73-
"%=" => a %= b,
72+
"/=" => {
73+
if b.is_zero() {
74+
return Err(Error::DivByZero);
75+
}
76+
a /= b
77+
}
78+
"%=" => {
79+
if b.is_zero() {
80+
return Err(Error::DivByZero);
81+
}
82+
a %= b
83+
}
7484
_ => (),
7585
}
7686
Ok(Value::Number(a))
@@ -189,8 +199,18 @@ impl InfixOpManager {
189199
"+" => a += b,
190200
"-" => a -= b,
191201
"*" => a *= b,
192-
"/" => a /= b,
193-
"%" => a %= b,
202+
"/" => {
203+
if b.is_zero() {
204+
return Err(Error::DivByZero);
205+
}
206+
a /= b
207+
}
208+
"%" => {
209+
if b.is_zero() {
210+
return Err(Error::DivByZero);
211+
}
212+
a %= b
213+
}
194214
_ => (),
195215
}
196216
Ok(Value::from(a))

0 commit comments

Comments
 (0)