Add test and check for SQLite being in single-threaded mode

This commit is contained in:
John Gallagher
2015-12-16 23:33:56 -05:00
parent bf2a63cc8d
commit b241f98920
5 changed files with 57 additions and 0 deletions

View File

@@ -14,6 +14,10 @@ pub enum Error {
/// An error from an underlying SQLite call.
SqliteFailure(ffi::Error, Option<String>),
/// Error reported when attempting to open a connection when SQLite was configured to
/// allow single-threaded use only.
SqliteSingleThreadedMode,
/// An error case available for implementors of the `FromSql` trait.
FromSqlConversionFailure(Box<error::Error + Send + Sync>),
@@ -77,6 +81,7 @@ impl fmt::Display for Error {
match self {
&Error::SqliteFailure(ref err, None) => err.fmt(f),
&Error::SqliteFailure(_, Some(ref s)) => write!(f, "{}", s),
&Error::SqliteSingleThreadedMode => write!(f, "SQLite was compiled or configured for single-threaded use only"),
&Error::FromSqlConversionFailure(ref err) => err.fmt(f),
&Error::Utf8Error(ref err) => err.fmt(f),
&Error::NulError(ref err) => err.fmt(f),
@@ -101,6 +106,7 @@ impl error::Error for Error {
match self {
&Error::SqliteFailure(ref err, None) => err.description(),
&Error::SqliteFailure(_, Some(ref s)) => s,
&Error::SqliteSingleThreadedMode => "SQLite was compiled or configured for single-threaded use only",
&Error::FromSqlConversionFailure(ref err) => err.description(),
&Error::Utf8Error(ref err) => err.description(),
&Error::InvalidParameterName(_) => "invalid parameter name",
@@ -122,6 +128,7 @@ impl error::Error for Error {
fn cause(&self) -> Option<&error::Error> {
match self {
&Error::SqliteFailure(ref err, _) => Some(err),
&Error::SqliteSingleThreadedMode => None,
&Error::FromSqlConversionFailure(ref err) => Some(&**err),
&Error::Utf8Error(ref err) => Some(err),
&Error::NulError(ref err) => Some(err),

View File

@@ -546,6 +546,30 @@ impl InnerConnection {
flags: OpenFlags)
-> Result<InnerConnection> {
unsafe {
// Before opening the database, we need to check that SQLite hasn't been
// compiled or configured to be in single-threaded mode. If it has, we're
// exposing a very unsafe API to Rust, so refuse to open connections at all.
// Unfortunately, the check for this is quite gross. sqlite3_threadsafe() only
// returns how SQLite was _compiled_; there is no public API to check whether
// someone called sqlite3_config() to set single-threaded mode. We can cheat
// by trying to allocate a mutex, though; in single-threaded mode due to
// compilation settings, the magic value 8 is returned (see the definition of
// sqlite3_mutex_alloc at https://github.com/mackyle/sqlite/blob/master/src/mutex.h);
// in single-threaded mode due to sqlite3_config(), the magic value 8 is also
// returned (see the definition of noopMutexAlloc at
// https://github.com/mackyle/sqlite/blob/master/src/mutex_noop.c).
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
let is_singlethreaded = if mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC {
true
} else {
false
};
ffi::sqlite3_mutex_free(mutex_ptr);
if is_singlethreaded {
return Err(Error::SqliteSingleThreadedMode);
}
let mut db: *mut ffi::sqlite3 = mem::uninitialized();
let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), ptr::null());
if r != ffi::SQLITE_OK {