@@ -34,6 +34,21 @@ pub(crate) struct StatementHandle(NonNull<sqlite3_stmt>);
3434
3535unsafe impl Send for StatementHandle { }
3636
37+ macro_rules! expect_ret_valid {
38+ ( $fn_name: ident( $( $args: tt) * ) ) => { {
39+ let val = $fn_name( $( $args) * ) ;
40+
41+ TryFrom :: try_from( val)
42+ . unwrap_or_else( |_| panic!( "{}() returned invalid value: {val:?}" , stringify!( $fn_name) ) )
43+ } }
44+ }
45+
46+ macro_rules! check_col_idx {
47+ ( $idx: ident) => {
48+ c_int:: try_from( $idx) . unwrap_or_else( |_| panic!( "invalid column index: {}" , $idx) )
49+ } ;
50+ }
51+
3752// might use some of this later
3853#[ allow( dead_code) ]
3954impl StatementHandle {
@@ -71,22 +86,22 @@ impl StatementHandle {
7186 #[ inline]
7287 pub ( crate ) fn column_count ( & self ) -> usize {
7388 // https://sqlite.org/c3ref/column_count.html
74- unsafe { sqlite3_column_count ( self . 0 . as_ptr ( ) ) as usize }
89+ unsafe { expect_ret_valid ! ( sqlite3_column_count( self . 0 . as_ptr( ) ) ) }
7590 }
7691
7792 #[ inline]
7893 pub ( crate ) fn changes ( & self ) -> u64 {
7994 // returns the number of changes of the *last* statement; not
8095 // necessarily this statement.
8196 // https://sqlite.org/c3ref/changes.html
82- unsafe { sqlite3_changes ( self . db_handle ( ) ) as u64 }
97+ unsafe { expect_ret_valid ! ( sqlite3_changes( self . db_handle( ) ) ) }
8398 }
8499
85100 #[ inline]
86101 pub ( crate ) fn column_name ( & self , index : usize ) -> & str {
87102 // https://sqlite.org/c3ref/column_name.html
88103 unsafe {
89- let name = sqlite3_column_name ( self . 0 . as_ptr ( ) , index as c_int ) ;
104+ let name = sqlite3_column_name ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) ;
90105 debug_assert ! ( !name. is_null( ) ) ;
91106
92107 from_utf8_unchecked ( CStr :: from_ptr ( name) . to_bytes ( ) )
@@ -107,7 +122,7 @@ impl StatementHandle {
107122 #[ inline]
108123 pub ( crate ) fn column_decltype ( & self , index : usize ) -> Option < SqliteTypeInfo > {
109124 unsafe {
110- let decl = sqlite3_column_decltype ( self . 0 . as_ptr ( ) , index as c_int ) ;
125+ let decl = sqlite3_column_decltype ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) ;
111126 if decl. is_null ( ) {
112127 // If the Nth column of the result set is an expression or subquery,
113128 // then a NULL pointer is returned.
@@ -123,16 +138,18 @@ impl StatementHandle {
123138
124139 pub ( crate ) fn column_nullable ( & self , index : usize ) -> Result < Option < bool > , Error > {
125140 unsafe {
141+ let index = check_col_idx ! ( index) ;
142+
126143 // https://sqlite.org/c3ref/column_database_name.html
127144 //
128145 // ### Note
129146 // The returned string is valid until the prepared statement is destroyed using
130147 // sqlite3_finalize() or until the statement is automatically reprepared by the
131148 // first call to sqlite3_step() for a particular run or until the same information
132149 // is requested again in a different encoding.
133- let db_name = sqlite3_column_database_name ( self . 0 . as_ptr ( ) , index as c_int ) ;
134- let table_name = sqlite3_column_table_name ( self . 0 . as_ptr ( ) , index as c_int ) ;
135- let origin_name = sqlite3_column_origin_name ( self . 0 . as_ptr ( ) , index as c_int ) ;
150+ let db_name = sqlite3_column_database_name ( self . 0 . as_ptr ( ) , index) ;
151+ let table_name = sqlite3_column_table_name ( self . 0 . as_ptr ( ) , index) ;
152+ let origin_name = sqlite3_column_origin_name ( self . 0 . as_ptr ( ) , index) ;
136153
137154 if db_name. is_null ( ) || table_name. is_null ( ) || origin_name. is_null ( ) {
138155 return Ok ( None ) ;
@@ -174,7 +191,7 @@ impl StatementHandle {
174191 #[ inline]
175192 pub ( crate ) fn bind_parameter_count ( & self ) -> usize {
176193 // https://www.sqlite.org/c3ref/bind_parameter_count.html
177- unsafe { sqlite3_bind_parameter_count ( self . 0 . as_ptr ( ) ) as usize }
194+ unsafe { expect_ret_valid ! ( sqlite3_bind_parameter_count( self . 0 . as_ptr( ) ) ) }
178195 }
179196
180197 // Name Of A Host Parameter
@@ -183,7 +200,7 @@ impl StatementHandle {
183200 pub ( crate ) fn bind_parameter_name ( & self , index : usize ) -> Option < & str > {
184201 unsafe {
185202 // https://www.sqlite.org/c3ref/bind_parameter_name.html
186- let name = sqlite3_bind_parameter_name ( self . 0 . as_ptr ( ) , index as c_int ) ;
203+ let name = sqlite3_bind_parameter_name ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) ;
187204 if name. is_null ( ) {
188205 return None ;
189206 }
@@ -200,7 +217,7 @@ impl StatementHandle {
200217 unsafe {
201218 sqlite3_bind_blob64 (
202219 self . 0 . as_ptr ( ) ,
203- index as c_int ,
220+ check_col_idx ! ( index) ,
204221 v. as_ptr ( ) as * const c_void ,
205222 v. len ( ) as u64 ,
206223 SQLITE_TRANSIENT ( ) ,
@@ -210,76 +227,85 @@ impl StatementHandle {
210227
211228 #[ inline]
212229 pub ( crate ) fn bind_text ( & self , index : usize , v : & str ) -> c_int {
230+ #[ allow( clippy:: cast_possible_truncation, clippy:: cast_sign_loss) ]
231+ let encoding = SQLITE_UTF8 as u8 ;
232+
213233 unsafe {
214234 sqlite3_bind_text64 (
215235 self . 0 . as_ptr ( ) ,
216- index as c_int ,
236+ check_col_idx ! ( index) ,
217237 v. as_ptr ( ) as * const c_char ,
218238 v. len ( ) as u64 ,
219239 SQLITE_TRANSIENT ( ) ,
220- SQLITE_UTF8 as u8 ,
240+ encoding ,
221241 )
222242 }
223243 }
224244
225245 #[ inline]
226246 pub ( crate ) fn bind_int ( & self , index : usize , v : i32 ) -> c_int {
227- unsafe { sqlite3_bind_int ( self . 0 . as_ptr ( ) , index as c_int , v as c_int ) }
247+ unsafe { sqlite3_bind_int ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) , v as c_int ) }
228248 }
229249
230250 #[ inline]
231251 pub ( crate ) fn bind_int64 ( & self , index : usize , v : i64 ) -> c_int {
232- unsafe { sqlite3_bind_int64 ( self . 0 . as_ptr ( ) , index as c_int , v) }
252+ unsafe { sqlite3_bind_int64 ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) , v) }
233253 }
234254
235255 #[ inline]
236256 pub ( crate ) fn bind_double ( & self , index : usize , v : f64 ) -> c_int {
237- unsafe { sqlite3_bind_double ( self . 0 . as_ptr ( ) , index as c_int , v) }
257+ unsafe { sqlite3_bind_double ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) , v) }
238258 }
239259
240260 #[ inline]
241261 pub ( crate ) fn bind_null ( & self , index : usize ) -> c_int {
242- unsafe { sqlite3_bind_null ( self . 0 . as_ptr ( ) , index as c_int ) }
262+ unsafe { sqlite3_bind_null ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) }
243263 }
244264
245265 // result values from the query
246266 // https://www.sqlite.org/c3ref/column_blob.html
247267
248268 #[ inline]
249269 pub ( crate ) fn column_type ( & self , index : usize ) -> c_int {
250- unsafe { sqlite3_column_type ( self . 0 . as_ptr ( ) , index as c_int ) }
270+ unsafe { sqlite3_column_type ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) }
251271 }
252272
253273 #[ inline]
254274 pub ( crate ) fn column_int ( & self , index : usize ) -> i32 {
255- unsafe { sqlite3_column_int ( self . 0 . as_ptr ( ) , index as c_int ) as i32 }
275+ unsafe { sqlite3_column_int ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) as i32 }
256276 }
257277
258278 #[ inline]
259279 pub ( crate ) fn column_int64 ( & self , index : usize ) -> i64 {
260- unsafe { sqlite3_column_int64 ( self . 0 . as_ptr ( ) , index as c_int ) as i64 }
280+ unsafe { sqlite3_column_int64 ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) as i64 }
261281 }
262282
263283 #[ inline]
264284 pub ( crate ) fn column_double ( & self , index : usize ) -> f64 {
265- unsafe { sqlite3_column_double ( self . 0 . as_ptr ( ) , index as c_int ) }
285+ unsafe { sqlite3_column_double ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) }
266286 }
267287
268288 #[ inline]
269289 pub ( crate ) fn column_value ( & self , index : usize ) -> * mut sqlite3_value {
270- unsafe { sqlite3_column_value ( self . 0 . as_ptr ( ) , index as c_int ) }
290+ unsafe { sqlite3_column_value ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) }
271291 }
272292
273293 pub ( crate ) fn column_blob ( & self , index : usize ) -> & [ u8 ] {
274- let index = index as c_int ;
275- let len = unsafe { sqlite3_column_bytes ( self . 0 . as_ptr ( ) , index) } as usize ;
294+ let len = unsafe { sqlite3_column_bytes ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) } ;
295+
296+ // This likely means UB in SQLite itself or our usage of it;
297+ // signed integer overflow is UB in the C standard.
298+ let len = usize:: try_from ( len) . unwrap_or_else ( |_| {
299+ panic ! ( "sqlite3_value_bytes() returned value out of range for usize: {len}" )
300+ } ) ;
276301
277302 if len == 0 {
278303 // empty blobs are NULL so just return an empty slice
279304 return & [ ] ;
280305 }
281306
282- let ptr = unsafe { sqlite3_column_blob ( self . 0 . as_ptr ( ) , index) } as * const u8 ;
307+ let ptr =
308+ unsafe { sqlite3_column_blob ( self . 0 . as_ptr ( ) , check_col_idx ! ( index) ) } as * const u8 ;
283309 debug_assert ! ( !ptr. is_null( ) ) ;
284310
285311 unsafe { from_raw_parts ( ptr, len) }
0 commit comments