Skip to content

From<ValueRef> for Value panics on invalid UTF-8 text via expect() #1817

Description

@dimitarvp

(This text was generated with LLM assistance and modified by me. I feel it's accurate and a good bug report.)


From<ValueRef> for Value panics on invalid UTF-8 text instead of returning an error.

Problem

From<ValueRef<'_>> for Value panics via expect() when a ValueRef::Text contains invalid UTF-8 bytes. This makes it impossible to use row.get::<_, Value>()on databases that may contain non-UTF-8 text data due to an immediate runtime panic.

The FromSql for String path handles this well via as_str()from_utf8().map_err() but the Value conversion path does not do that and panics unconditionally.

Reproduction

Minimal repo: https://github.com/dimitarvp/rusqlite-utf8-panic

Just cargo run it.

use rusqlite::{Connection, types::Value};

fn main() {
    let conn = Connection::open_in_memory().unwrap();
    conn.execute_batch("CREATE TABLE t (val TEXT);").unwrap();
    conn.execute(
        "INSERT INTO t (val) VALUES (CAST(X'FFFE8041' AS TEXT))",
        [],
    ).unwrap();

    // Panics in From<ValueRef> for Value
    let mut stmt = conn.prepare("SELECT UPPER(val) FROM t").unwrap();
    let result = stmt.query_row([], |row| row.get::<_, Value>(0));
    println!("result: {:?}", result);
}

Output:

thread 'main' panicked at rusqlite-0.37.0/src/types/from_sql.rs:293:18:
invalid UTF-8: Utf8Error { valid_up_to: 0, error_len: Some(1) }

Tested on both 0.37.0 and 0.38.0. Both panic.

Root cause

value_ref.rs:

impl From<ValueRef<'_>> for Value {
    fn from(borrowed: ValueRef<'_>) -> Self {
        match borrowed {
            // ...
            ValueRef::Text(s) => {
                let s = std::str::from_utf8(s).expect("invalid UTF-8"); // panics
                Self::Text(s.to_string())
            }
            // ...
        }
    }
}

This uses expect() instead of returning an error. ValueRef::as_str() uses from_utf8(t).map_err(FromSqlError::other) and does not panic.

Context

SQLite does not enforce UTF-8 validity for TEXT columns. Databases created by non-Rust programs, or TEXT columns containing data processed by SQLite functions like UPPER() / LOWER() on non-UTF-8 input, can legitimately contain invalid byte sequences.

This was partially addressed in #548 (making ValueRef::Text hold &[u8]), but the From<ValueRef> for Value conversion was not updated to handle the error case.

Potential fixes

Replace expect() with code that returns Result or store the bytes as a blob fallback. For example, TryFrom<ValueRef<'_>> for Value could be introduced alongside the existing From, or the From impl could fall back to Value::Blob for invalid UTF-8 text.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions