Skip to content

Commit 73d581e

Browse files
fix(vm): Fuzzer executed, solving some stackoverflows and other errors.
1 parent 8c40aeb commit 73d581e

6 files changed

Lines changed: 36 additions & 14 deletions

File tree

compiler/src/modules/parser/types.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,9 @@ pub(super) fn parse_string(s: &str) -> String {
402402
let is_raw = has_raw_prefix(s);
403403
let s = s.trim_start_matches(|c: char| "bBrRuU".contains(c));
404404
let inner = if s.starts_with("\"\"\"") || s.starts_with("'''") {
405-
&s[3..s.len() - 3]
405+
s.get(3..s.len().saturating_sub(3)).unwrap_or("")
406406
} else {
407-
&s[1..s.len() - 1]
407+
s.get(1..s.len().saturating_sub(1)).unwrap_or("")
408408
};
409409
if is_raw { inner.to_string() } else { unescape(inner) }
410410
}
@@ -419,12 +419,12 @@ pub(super) fn parse_bytes_literal(s: &str) -> alloc::vec::Vec<u8> {
419419
i += 1;
420420
}
421421
// Strip triple or single quotes.
422-
let body = if bytes.len() >= i + 6
422+
let body: &[u8] = if bytes.len() >= i + 6
423423
&& (bytes[i..i + 3] == *b"\"\"\"" || bytes[i..i + 3] == *b"'''")
424424
{
425425
&bytes[i + 3..bytes.len() - 3]
426426
} else {
427-
&bytes[i + 1..bytes.len() - 1]
427+
bytes.get(i + 1..bytes.len().saturating_sub(1)).unwrap_or(&[])
428428
};
429429
if is_raw { return body.to_vec(); }
430430

compiler/src/modules/vm/builtins/sequence.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ impl<'a> VM<'a> {
6868
HeapObj::Tuple(v) => v.len() as i64,
6969
HeapObj::Dict(v) => v.borrow().len() as i64,
7070
HeapObj::Set(v) => v.borrow().len() as i64,
71-
HeapObj::Range(s,e,st) => { let st=*st; ((e-s+st-st.signum())/st).max(0) }
71+
HeapObj::Range(s,e,st) => {
72+
let (s, e, st) = (*s as i128, *e as i128, *st as i128);
73+
if st == 0 { return Err(cold_value("range() step cannot be zero")); }
74+
(((e - s + st - st.signum()) / st).max(0)) as i64
75+
}
7276
_ => return Err(cold_type("object has no len()")),
7377
}} else { return Err(cold_type("object has no len()")); };
7478
self.push(Val::int(n)); Ok(())
@@ -237,8 +241,17 @@ impl<'a> VM<'a> {
237241
HeapObj::Range(s, e, st) if include_range => {
238242
let (mut cur, end, step) = (*s, *e, *st);
239243
let mut out = Vec::new();
240-
if step > 0 { while cur < end { out.push(Val::int(cur)); cur += step; } }
241-
else { while cur > end { out.push(Val::int(cur)); cur += step; } }
244+
if step > 0 {
245+
while cur < end {
246+
out.push(Val::int(cur));
247+
match cur.checked_add(step) { Some(n) => cur = n, None => break }
248+
}
249+
} else {
250+
while cur > end {
251+
out.push(Val::int(cur));
252+
match cur.checked_add(step) { Some(n) => cur = n, None => break }
253+
}
254+
}
242255
Some(out)
243256
}
244257
HeapObj::Dict(d) => Some(d.borrow().keys().collect()),

compiler/src/modules/vm/handlers/builtin_methods/list.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub fn insert(vm: &mut VM, recv: Val, pos: &[Val]) -> Result<(), VmErr> {
6060
list_mut(vm, recv, "insert: receiver is not a list", |list| {
6161
let i = pos[0].as_int();
6262
let ui = if i < 0 {
63-
(list.len() as i64 + i).max(0) as usize
63+
(list.len() as i64).saturating_add(i).max(0) as usize
6464
} else {
6565
(i as usize).min(list.len())
6666
};
@@ -87,7 +87,11 @@ pub fn pop(vm: &mut VM, recv: Val, pos: &[Val]) -> Result<(), VmErr> {
8787
if pos.is_empty() { return Ok(list.pop().unwrap()); }
8888
if !pos[0].is_int() { return Err(cold_type("list indices must be integers")); }
8989
let i = pos[0].as_int();
90-
let ui = if i < 0 { (list.len() as i64 + i) as usize } else { i as usize };
90+
let ui = if i < 0 {
91+
let adj = (list.len() as i64).saturating_add(i);
92+
if adj < 0 { return Err(cold_value("pop index out of range")); }
93+
adj as usize
94+
} else { i as usize };
9195
if ui >= list.len() { return Err(cold_value("pop index out of range")); }
9296
Ok(list.remove(ui))
9397
})?;

compiler/src/modules/vm/handlers/builtin_methods/string.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ pub fn rpartition(vm: &mut VM, recv: Val, pos: &[Val]) -> Result<(), VmErr> {
235235
pub fn center(vm: &mut VM, recv: Val, pos: &[Val]) -> Result<(), VmErr> {
236236
let s = recv_str(vm, recv)?;
237237
if !pos[0].is_int() { return Err(cold_type("center() width must be an integer")); }
238-
let width = pos[0].as_int() as usize;
238+
let width = pos[0].as_int().max(0) as usize;
239239
let fill = if pos.len() > 1 {
240240
val_to_str(vm, pos[1])?.chars().next().unwrap_or(' ')
241241
} else { ' ' };
@@ -251,7 +251,7 @@ pub fn center(vm: &mut VM, recv: Val, pos: &[Val]) -> Result<(), VmErr> {
251251
pub fn zfill(vm: &mut VM, recv: Val, pos: &[Val]) -> Result<(), VmErr> {
252252
if !pos[0].is_int() { return Err(cold_type("zfill() requires an integer argument")); }
253253
let s = recv_str(vm, recv)?;
254-
let width = pos[0].as_int() as usize;
254+
let width = pos[0].as_int().max(0) as usize;
255255
let nchars = s.chars().count();
256256
let out = if nchars >= width {
257257
s

compiler/src/modules/vm/ops.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,18 +389,21 @@ impl<'a> VM<'a> {
389389
let n = count.max(0) as usize;
390390
match self.heap.get(seq_val) {
391391
HeapObj::Str(s) => {
392+
s.len().checked_mul(n).ok_or(cold_overflow())?;
392393
let r = s.repeat(n);
393394
return self.heap.alloc(HeapObj::Str(r));
394395
}
395396
HeapObj::List(rc) => {
396397
let src = rc.borrow().clone();
397-
let mut out = Vec::with_capacity(src.len() * n);
398+
let cap = src.len().checked_mul(n).ok_or(cold_overflow())?;
399+
let mut out = Vec::with_capacity(cap);
398400
for _ in 0..n { out.extend_from_slice(&src); }
399401
return self.heap.alloc(HeapObj::List(Rc::new(RefCell::new(out))));
400402
}
401403
HeapObj::Tuple(v) => {
402404
let src = v.clone();
403-
let mut out = Vec::with_capacity(src.len() * n);
405+
let cap = src.len().checked_mul(n).ok_or(cold_overflow())?;
406+
let mut out = Vec::with_capacity(cap);
404407
for _ in 0..n { out.extend_from_slice(&src); }
405408
return self.heap.alloc(HeapObj::Tuple(out));
406409
}

compiler/tests/cases/vm.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1780,5 +1780,7 @@
17801780
{"src": "print(sorted([3, 1, 2], reverse=True))", "output": ["[3, 2, 1]"]},
17811781
{"src": "print(sorted([3, 1, 2], key=lambda x: -x, reverse=False))", "output": ["[3, 2, 1]"]},
17821782
{"src": "lst = [3, 1, 2]; lst.sort(reverse=True); print(lst)", "output": ["[3, 2, 1]"]},
1783-
{"src": "lst = [3, 1, 2]; lst.sort(key=lambda x: -x); print(lst)", "output": ["[3, 2, 1]"]}
1783+
{"src": "lst = [3, 1, 2]; lst.sort(key=lambda x: -x); print(lst)", "output": ["[3, 2, 1]"]},
1784+
{"src": "print('x'.center(-1000000000))", "output": ["x"]},
1785+
{"src": "print('5'.zfill(-1000000000))", "output": ["5"]}
17841786
]

0 commit comments

Comments
 (0)