Skip to content

sqlite: safe custom collation APIs can pass invalid UTF-8 as &str #4194

@meng-xu-cs

Description

@meng-xu-cs

I have found these related issues/pull requests

#4192, #4193 are both UTF-8 related bug, but not the same one.

Description

SqliteConnectOptions::collation() and LockedSqliteHandle::create_collation() expose a safe callback signature Fn(&str, &str) -> Ordering, but the SQLite callback implementation currently converts raw SQLite bytes to &str with std::str::from_utf8_unchecked.

SQLite explicitly documents that invalid UTF may be passed into application-defined collating sequences. That means a database containing invalid UTF-8 text can reach this callback and cause SQLx to construct invalid &str values inside a safe API.

Reproduction steps

use std::str::FromStr;

use sqlx::sqlite::SqliteConnectOptions;
use sqlx::ConnectOptions;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let opts = SqliteConnectOptions::from_str("sqlite::memory:")?
        .collation("bug", |a, b| a.cmp(b));

    let mut conn = opts.connect().await?;

    sqlx::query("CREATE TABLE t (s TEXT NOT NULL)")
        .execute(&mut conn)
        .await?;

    // Stores a TEXT value containing invalid UTF-8.
    sqlx::query("INSERT INTO t (s) VALUES ('a'), (CAST(x'80' AS TEXT))")
        .execute(&mut conn)
        .await?;

    // Triggers the custom collation callback on the invalid TEXT value.
    let _rows = sqlx::query("SELECT hex(s) FROM t ORDER BY s COLLATE bug")
        .fetch_all(&mut conn)
        .await?;

    Ok(())
}

SQLx version

main branch

Enabled SQLx features

default

Database server and version

SQLite

Operating system

MacOS

Rust version

1.94.0 (4a4ef493e 2026-03-02)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions