Closed
Description
It seems there is some invalid memory access in the sqlite backend which sometimes happen when a future that is executing some query is aborted before it has chance to run to completion. Here is a minimal reproductible case:
#[tokio::test(flavor = "multi_thread")]
async fn sqlx_memory_corruption() {
use sqlx::{sqlite::SqliteConnectOptions, ConnectOptions};
use std::{str::FromStr, time::Duration};
use tokio::time;
let mut conn = SqliteConnectOptions::from_str(":memory:")
.unwrap()
.connect()
.await
.unwrap();
sqlx::query("CREATE TABLE stuff (name INTEGER, value INTEGER)")
.execute(&mut conn)
.await
.unwrap();
let task = tokio::spawn(async move {
for i in 0..1000 {
sqlx::query("INSERT INTO stuff (name, value) VALUES (?, ?)")
.bind(i)
.bind(0)
.execute(&mut conn)
.await
.unwrap();
}
});
time::sleep(Duration::from_millis(1)).await;
task.abort();
}
(it might need to be run a couple of times before the bug is observed).
My hypothesis is that when the future is aborted, some sqlx objects might be dropped in unexpected order. e.g. a connection might be dropped before a statement handle, etc... which causes the underlying sqlite3 resources to be cleaned up in wrong order, causing an use-after-free or similar. I haven't verified this though.
Metadata
Metadata
Assignees
Labels
No labels