Repository: PoloDB/PoloDB (language: rust)

Issue:
Panic caused by overflow in VM::execute when using .skip() in query
I encountered a panic while running a query with polodb_core when using .skip() and .limit(). Here is the code that triggered the crash:
`let books = collection
    .find(doc! {})
    .skip(1)
    .limit(1)
    .run()?;
for book in books {
    println!("name: {:?}", book);
}
`
The following panic occurred:

`thread 'main' panicked at 'attempt to subtract with overflow', C:\Users\polly\.cargo\registry\src\index.crates.io-6f17d22bba15001f\polodb_core-5.1.2\vm\vm.rs:948:46
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14\library/std\src\panicking.rs:662
   1: core::panicking::panic_fmt
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14\library/core\src\panicking.rs:74
   2: core::panicking::panic_const::panic_const_sub_overflow
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14\library/core\src\panicking.rs:181
   3: polodb_core::vm::vm::VM::execute
             at C:\Users\polly\.cargo\registry\src\index.crates.io-6f17d22bba15001f\polodb_core-5.1.2\vm\vm.rs:948
`

polodb_core version: 5.1.2



Discussion / hints:

Fix patch:
diff --git a/src/polodb_core/vm/codegen.rs b/src/polodb_core/vm/codegen.rs
index cdb066ea..94b62a9e 100644
--- a/src/polodb_core/vm/codegen.rs
+++ b/src/polodb_core/vm/codegen.rs
@@ -854,9 +854,11 @@ impl Codegen {
         }
         let next_label = self.new_label();
 
-        for stage_item in &ctx.items {
-            self.emit_goto(DbOp::Call, stage_item.next_label);
+        if let Some(first_item) = ctx.items.first() {
+            self.emit_goto(DbOp::Call, first_item.next_label);
             self.emit_u32(1);
+        } else {
+            panic!("the first item of the pipeline is empty");
         }
 
         // the final pipeline item to emit the final result


Test patch:
diff --git a/src/polodb_core/tests/test_find.rs b/src/polodb_core/tests/test_find.rs
index 019b0fa8..8d747a10 100644
--- a/src/polodb_core/tests/test_find.rs
+++ b/src/polodb_core/tests/test_find.rs
@@ -300,6 +300,18 @@ fn test_find_limit() {
     assert_eq!(result[0].get("name").unwrap().as_str().unwrap(), "apple");
     assert_eq!(result[1].get("name").unwrap().as_str().unwrap(), "banana");
     assert_eq!(result[2].get("name").unwrap().as_str().unwrap(), "orange");
+
+    // skip and limit
+    let result = fruits
+        .find(doc! {})
+        .skip(2)
+        .limit(2)
+        .run()
+        .unwrap()
+        .collect::<Result<Vec<Document>>>()
+        .unwrap();
+    assert_eq!(result.len(), 2);
+    assert_eq!(result[0].get("name").unwrap().as_str().unwrap(), "orange");
 }
 
 #[test]