Skip to content

Commit e3cfba8

Browse files
committed
Merge 'fix 24/48 bit width serial types parsing' from Nikita Sivukhin
For serial types 3 and 5 SQLite uses twos-complement representation of 24bit and 48bit widths integers. Limbo need to follow same Reviewed-by: Jussi Saurio (@jussisaurio) Closes #1020
2 parents c300b4f + 37e2713 commit e3cfba8

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

core/storage/sqlite3_ondisk.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -995,8 +995,11 @@ pub fn read_value(buf: &[u8], serial_type: &SerialType) -> Result<(OwnedValue, u
995995
if buf.len() < 3 {
996996
crate::bail_corrupt_error!("Invalid BEInt24 value");
997997
}
998+
let sign_extension = if buf[0] <= 127 { 0 } else { 255 };
998999
Ok((
999-
OwnedValue::Integer(i32::from_be_bytes([0, buf[0], buf[1], buf[2]]) as i64),
1000+
OwnedValue::Integer(
1001+
i32::from_be_bytes([sign_extension, buf[0], buf[1], buf[2]]) as i64
1002+
),
10001003
3,
10011004
))
10021005
}
@@ -1013,9 +1016,17 @@ pub fn read_value(buf: &[u8], serial_type: &SerialType) -> Result<(OwnedValue, u
10131016
if buf.len() < 6 {
10141017
crate::bail_corrupt_error!("Invalid BEInt48 value");
10151018
}
1019+
let sign_extension = if buf[0] <= 127 { 0 } else { 255 };
10161020
Ok((
10171021
OwnedValue::Integer(i64::from_be_bytes([
1018-
0, 0, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
1022+
sign_extension,
1023+
sign_extension,
1024+
buf[0],
1025+
buf[1],
1026+
buf[2],
1027+
buf[3],
1028+
buf[4],
1029+
buf[5],
10191030
])),
10201031
6,
10211032
))
@@ -1419,6 +1430,18 @@ mod tests {
14191430
#[case(&[], SerialType::ConstInt1, OwnedValue::Integer(1))]
14201431
#[case(&[1, 2, 3], SerialType::Blob(3), OwnedValue::Blob(vec![1, 2, 3].into()))]
14211432
#[case(&[65, 66, 67], SerialType::String(3), OwnedValue::build_text("ABC"))]
1433+
#[case(&[0x80], SerialType::Int8, OwnedValue::Integer(-128))]
1434+
#[case(&[0x80, 0], SerialType::BEInt16, OwnedValue::Integer(-32768))]
1435+
#[case(&[0x80, 0, 0], SerialType::BEInt24, OwnedValue::Integer(-8388608))]
1436+
#[case(&[0x80, 0, 0, 0], SerialType::BEInt32, OwnedValue::Integer(-2147483648))]
1437+
#[case(&[0x80, 0, 0, 0, 0, 0], SerialType::BEInt48, OwnedValue::Integer(-140737488355328))]
1438+
#[case(&[0x80, 0, 0, 0, 0, 0, 0, 0], SerialType::BEInt64, OwnedValue::Integer(-9223372036854775808))]
1439+
#[case(&[0x7f], SerialType::Int8, OwnedValue::Integer(127))]
1440+
#[case(&[0x7f, 0xff], SerialType::BEInt16, OwnedValue::Integer(32767))]
1441+
#[case(&[0x7f, 0xff, 0xff], SerialType::BEInt24, OwnedValue::Integer(8388607))]
1442+
#[case(&[0x7f, 0xff, 0xff, 0xff], SerialType::BEInt32, OwnedValue::Integer(2147483647))]
1443+
#[case(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff], SerialType::BEInt48, OwnedValue::Integer(140737488355327))]
1444+
#[case(&[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], SerialType::BEInt64, OwnedValue::Integer(9223372036854775807))]
14221445
fn test_read_value(
14231446
#[case] buf: &[u8],
14241447
#[case] serial_type: SerialType,

tests/integration/fuzz/grammar_generator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub enum SymbolType {
2626
random_length: usize,
2727
},
2828
Int {
29-
range: Range<i32>,
29+
range: Range<i64>,
3030
},
3131
#[allow(dead_code)]
3232
Optional {
@@ -63,7 +63,7 @@ pub fn rand_str(fixed_prefix: &str, random_length: usize) -> SymbolType {
6363
}
6464
}
6565

66-
pub fn rand_int(range: Range<i32>) -> SymbolType {
66+
pub fn rand_int(range: Range<i64>) -> SymbolType {
6767
SymbolType::Int { range }
6868
}
6969

tests/integration/fuzz/mod.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub mod grammar_generator;
44
mod tests {
55
use std::rc::Rc;
66

7-
use rand::{RngCore, SeedableRng};
7+
use rand::SeedableRng;
88
use rand_chacha::ChaCha8Rng;
99
use rusqlite::params;
1010

@@ -632,11 +632,18 @@ mod tests {
632632
pub fn table_logical_expression_fuzz_ex1() {
633633
let _ = env_logger::try_init();
634634

635-
for queries in [[
636-
"CREATE TABLE t(x)",
637-
"INSERT INTO t VALUES (10)",
638-
"SELECT * FROM t WHERE x = 1 AND 1 OR 0",
639-
]] {
635+
for queries in [
636+
[
637+
"CREATE TABLE t(x)",
638+
"INSERT INTO t VALUES (10)",
639+
"SELECT * FROM t WHERE x = 1 AND 1 OR 0",
640+
],
641+
[
642+
"CREATE TABLE t(x)",
643+
"INSERT INTO t VALUES (-3258184727)",
644+
"SELECT * FROM t",
645+
],
646+
] {
640647
let db = TempDatabase::new_empty();
641648
let limbo_conn = db.connect_limbo();
642649
let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap();
@@ -663,6 +670,15 @@ mod tests {
663670
let (in_op, in_op_builder) = g.create_handle();
664671
let (paren, paren_builder) = g.create_handle();
665672

673+
let number = g
674+
.create()
675+
.choice()
676+
.option_symbol(rand_int(-0xff..0x100))
677+
.option_symbol(rand_int(-0xffff..0x10000))
678+
.option_symbol(rand_int(-0xffffff..0x1000000))
679+
.option_symbol(rand_int(-0xffffffff..0x100000000))
680+
.option_symbol(rand_int(-0xffffffffffff..0x1000000000000))
681+
.build();
666682
value_builder
667683
.choice()
668684
.option(
@@ -673,7 +689,7 @@ mod tests {
673689
.push_str(")")
674690
.build(),
675691
)
676-
.option_symbol(rand_int(0..i32::MAX))
692+
.option(number)
677693
.options_str(["x", "y", "z"])
678694
.option(
679695
g.create()
@@ -742,8 +758,13 @@ mod tests {
742758
log::info!("seed: {}", seed);
743759

744760
for _ in 0..100 {
745-
let (x, y, z) = (rng.next_u32(), rng.next_u32(), rng.next_u32());
761+
let (x, y, z) = (
762+
g.generate(&mut rng, number, 1),
763+
g.generate(&mut rng, number, 1),
764+
g.generate(&mut rng, number, 1),
765+
);
746766
let query = format!("INSERT INTO t VALUES ({}, {}, {})", x, y, z);
767+
log::info!("insert: {}", query);
747768
assert_eq!(
748769
limbo_exec_rows(&db, &limbo_conn, &query),
749770
sqlite_exec_rows(&sqlite_conn, &query)

0 commit comments

Comments
 (0)