Skip to content

Commit 4249cb4

Browse files
authored
fix: replace from_utf8_unchecked with from_utf8 in SQLite column name handling (#4221)
* fix: replace from_utf8_unchecked with from_utf8 in SQLite statement handle Replace all uses of `from_utf8_unchecked` with safe `from_utf8` in the SQLite statement handle to fix a soundness issue. SQLite allows non-UTF-8 column names via its C API, but `from_utf8_unchecked` assumes valid UTF-8 without checking. This can produce invalid `&str` values through a safe public API, which is undefined behavior in Rust. Using `from_utf8().expect()` instead converts potential UB into a defined panic with a clear message. There is no behavioral change for valid UTF-8 inputs, which covers all practical usage. Fixes #4192 * style: run rustfmt on handle.rs
1 parent b6cb1e3 commit 4249cb4

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

sqlx-sqlite/src/statement/handle.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::os::raw::{c_char, c_int};
2121
use std::ptr;
2222
use std::ptr::NonNull;
2323
use std::slice::from_raw_parts;
24-
use std::str::{from_utf8, from_utf8_unchecked};
24+
use std::str::from_utf8;
2525
use std::sync::Arc;
2626

2727
#[derive(Debug)]
@@ -77,7 +77,8 @@ impl StatementHandle {
7777
let raw = sqlite3_sql(self.0.as_ptr());
7878
debug_assert!(!raw.is_null());
7979

80-
from_utf8_unchecked(CStr::from_ptr(raw).to_bytes())
80+
from_utf8(CStr::from_ptr(raw).to_bytes())
81+
.expect("sqlite3_sql() returned non-UTF-8 string")
8182
}
8283
}
8384

@@ -107,7 +108,8 @@ impl StatementHandle {
107108
let name = sqlite3_column_name(self.0.as_ptr(), check_col_idx!(index));
108109
debug_assert!(!name.is_null());
109110

110-
from_utf8_unchecked(CStr::from_ptr(name).to_bytes())
111+
from_utf8(CStr::from_ptr(name).to_bytes())
112+
.expect("sqlite3_column_name() returned non-UTF-8 column name")
111113
}
112114
}
113115

@@ -139,7 +141,10 @@ impl StatementHandle {
139141
let db_name = sqlite3_column_database_name(self.0.as_ptr(), check_col_idx!(index));
140142

141143
if !db_name.is_null() {
142-
Some(from_utf8_unchecked(CStr::from_ptr(db_name).to_bytes()))
144+
Some(
145+
from_utf8(CStr::from_ptr(db_name).to_bytes())
146+
.expect("sqlite3_column_database_name() returned non-UTF-8 string"),
147+
)
143148
} else {
144149
None
145150
}
@@ -151,7 +156,10 @@ impl StatementHandle {
151156
let table_name = sqlite3_column_table_name(self.0.as_ptr(), check_col_idx!(index));
152157

153158
if !table_name.is_null() {
154-
Some(from_utf8_unchecked(CStr::from_ptr(table_name).to_bytes()))
159+
Some(
160+
from_utf8(CStr::from_ptr(table_name).to_bytes())
161+
.expect("sqlite3_column_table_name() returned non-UTF-8 string"),
162+
)
155163
} else {
156164
None
157165
}
@@ -163,7 +171,10 @@ impl StatementHandle {
163171
let origin_name = sqlite3_column_origin_name(self.0.as_ptr(), check_col_idx!(index));
164172

165173
if !origin_name.is_null() {
166-
Some(from_utf8_unchecked(CStr::from_ptr(origin_name).to_bytes()))
174+
Some(
175+
from_utf8(CStr::from_ptr(origin_name).to_bytes())
176+
.expect("sqlite3_column_origin_name() returned non-UTF-8 string"),
177+
)
167178
} else {
168179
None
169180
}
@@ -191,7 +202,8 @@ impl StatementHandle {
191202
return None;
192203
}
193204

194-
let decl = from_utf8_unchecked(CStr::from_ptr(decl).to_bytes());
205+
let decl = from_utf8(CStr::from_ptr(decl).to_bytes())
206+
.expect("sqlite3_column_decltype() returned non-UTF-8 string");
195207
let ty: DataType = decl.parse().ok()?;
196208

197209
Some(SqliteTypeInfo(ty))
@@ -285,7 +297,10 @@ impl StatementHandle {
285297
return None;
286298
}
287299

288-
Some(from_utf8_unchecked(CStr::from_ptr(name).to_bytes()))
300+
Some(
301+
from_utf8(CStr::from_ptr(name).to_bytes())
302+
.expect("sqlite3_bind_parameter_name() returned non-UTF-8 string"),
303+
)
289304
}
290305
}
291306

0 commit comments

Comments
 (0)