Merge 'Fix fuzz issue #1763 by using the log2 & log10 functions where applicable' from Luca Muscat

It is easy to chalk this fuzzer issue to erratic floating point
behaviour, but this is not the case here.
Currently, `exec_math_log` calculates log with arbitrary bases by using
the following formula: `log_a(b) ~= ln(b) / ln(a)`. This calculation is
an approximation with lots of its floating point precision lost to
dividing the results of natural logarithms.
By using the specialized versions of the log functions (`log2` &
`log10`), we can avoid this loss of precision.
SQLite also uses these specialized log functions when possible, so it
doesn't hurt to do the same thing when aiming for parity.
This PR fixes #1763

Reviewed-by: Diego Reis (@el-yawd)
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>

Closes #1786
This commit is contained in:
Pere Diaz Bou
2025-06-20 17:58:54 +02:00
2 changed files with 22 additions and 0 deletions

View File

@@ -6133,6 +6133,12 @@ impl Value {
None => 10.0,
};
if base == 2.0 {
return Value::Float(libm::log2(f));
} else if base == 10.0 {
return Value::Float(libm::log10(f));
};
if f <= 0.0 || base <= 0.0 || base == 1.0 {
return Value::Null;
}

View File

@@ -24,6 +24,22 @@ mod tests {
(rng, seed)
}
/// [See this issue for more info](https://github.com/tursodatabase/limbo/issues/1763)
#[test]
pub fn fuzz_failure_issue_1763() {
let db = TempDatabase::new_empty();
let limbo_conn = db.connect_limbo();
let sqlite_conn = rusqlite::Connection::open_in_memory().unwrap();
let offending_query = "SELECT ((ceil(pow((((2.0))), (-2.0 - -1.0) / log(0.5)))) - -2.0)";
let limbo_result = limbo_exec_rows(&db, &limbo_conn, offending_query);
let sqlite_result = sqlite_exec_rows(&sqlite_conn, offending_query);
assert_eq!(
limbo_result, sqlite_result,
"query: {}, limbo: {:?}, sqlite: {:?}",
offending_query, limbo_result, sqlite_result
);
}
#[test]
pub fn arithmetic_expression_fuzz_ex1() {
let db = TempDatabase::new_empty();