Skip to content

fix(sqlite): don't dereference a NULL declared type in column_nullable - #4374

Open
msdrigg wants to merge 1 commit into
transact-rs:mainfrom
msdrigg:fix/sqlite-untyped-column-segfault
Open

fix(sqlite): don't dereference a NULL declared type in column_nullable#4374
msdrigg wants to merge 1 commit into
transact-rs:mainfrom
msdrigg:fix/sqlite-untyped-column-segfault

Conversation

@msdrigg

@msdrigg msdrigg commented Aug 11, 2026

Copy link
Copy Markdown

Fixes #4373

sqlite3_table_column_metadata() leaves its declared-type out-param NULL when a column was declared with no type (CREATE TABLE foo (bar PRIMARY KEY) is legal SQLite). column_nullable() passed that pointer straight into CStr::from_ptr(), so describing such a column segfaulted. Since query!() describes a live database while expanding, the process that died was rustc.

Introduced in 69ee0df (#4088), released in 0.9.0. Before that the slot was ptr::null_mut() and never read.

The fix. Only read the pointer when it's non-null. A column with no declared type isn't declared INTEGER, so it can't be a rowid alias, and it falls through to the ordinary NOT NULL check:

let is_integer = !datatype.is_null()
    && CStr::from_ptr(datatype)
        .to_bytes()
        .eq_ignore_ascii_case("integer".as_bytes());

Ok(if primary_key != 0 && is_integer {
    None
} else {
    Some(not_null == 0)
})

This matches what column_decltype() right above already does with the pointer from sqlite3_column_decltype().

That's also the correct answer semantically, not just a crash guard: a PRIMARY KEY with no declared type has BLOB affinity, is not a rowid alias, and SQLite really does allow NULLs in it, so Some(true) is right.

After the fix, an untyped column gives the normal diagnostic instead of a crash:

error: no built-in mapping found for type NULL of column #1 ("device_id");
       a type override may be required

and a type override (device_id as "device_id!: String") compiles cleanly. That's the behaviour #1979 and #3546 describe.

sqlite3_table_column_metadata() leaves its declared-type out-param NULL for a
column declared without a type, e.g. `CREATE TABLE foo (bar PRIMARY KEY)`.
column_nullable() passed that pointer straight to CStr::from_ptr(), so
describing such a column segfaulted the process, and rustc itself, since the
query!() macros describe a live database at expansion time.

A column with no declared type is not declared INTEGER and so cannot be a rowid
alias; treat it as a normal column and fall through to the NOT NULL flag.

Regression introduced in 69ee0df (transact-rs#4088), released in 0.9.0.
@msdrigg msdrigg changed the title fixfix(sqlite): don't dereference a NULL declared type in column_nullable fix(sqlite): don't dereference a NULL declared type in column_nullable Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SQLite: query!() segfaults rustc when a column has no declared type

1 participant