summaryrefslogtreecommitdiffstats
path: root/sql
diff options
context:
space:
mode:
authorshess <shess@chromium.org>2016-02-26 10:15:58 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-26 18:17:13 +0000
commit644fc8aed6f9b1ab783f8cd974bb8a11dc920d7c (patch)
tree21d143dc183aadcfd31f9255a7bbe3c912b9dd86 /sql
parent1c71673cac4942b535f90543c7aa56adb57bf092 (diff)
downloadchromium_src-644fc8aed6f9b1ab783f8cd974bb8a11dc920d7c.zip
chromium_src-644fc8aed6f9b1ab783f8cd974bb8a11dc920d7c.tar.gz
chromium_src-644fc8aed6f9b1ab783f8cd974bb8a11dc920d7c.tar.bz2
[sql] Fix crash in sqlite3_total_changes.
The mmap support makes direct SQLite calls against the database handle in ReleaseCacheMemoryIfNeeded() (called after transactions are closed or statements are executed outside of any explicit transaction). Recovery or raze during the error callback can close this handle during otherwise-valid sequences of calls. Check that the handle is still open before clearing the cache. BUG=589986 Review URL: https://codereview.chromium.org/1741553002 Cr-Commit-Position: refs/heads/master@{#377924}
Diffstat (limited to 'sql')
-rw-r--r--sql/connection.cc7
-rw-r--r--sql/connection_unittest.cc17
2 files changed, 22 insertions, 2 deletions
diff --git a/sql/connection.cc b/sql/connection.cc
index f94e7ab..7787adf 100644
--- a/sql/connection.cc
+++ b/sql/connection.cc
@@ -595,7 +595,12 @@ void Connection::Preload() {
// work. There could be two prepared statements, one for cache_size=1 one for
// cache_size=goal.
void Connection::ReleaseCacheMemoryIfNeeded(bool implicit_change_performed) {
- DCHECK(is_open());
+ // The database could have been closed during a transaction as part of error
+ // recovery.
+ if (!db_) {
+ DLOG_IF(FATAL, !poisoned_) << "Illegal use of connection without a db";
+ return;
+ }
// If memory-mapping is not enabled, the page cache helps performance.
if (!mmap_enabled_)
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc
index c6f80d8..d9dd9d9 100644
--- a/sql/connection_unittest.cc
+++ b/sql/connection_unittest.cc
@@ -247,7 +247,9 @@ class SQLConnectionTest : public sql::SQLTestBase {
// Handle errors by blowing away the database.
void RazeErrorCallback(int expected_error, int error, sql::Statement* stmt) {
- EXPECT_EQ(expected_error, error);
+ // Nothing here needs extended errors at this time.
+ EXPECT_EQ(expected_error, expected_error&0xff);
+ EXPECT_EQ(expected_error, error&0xff);
db().RazeAndClose();
}
};
@@ -928,6 +930,19 @@ TEST_F(SQLConnectionTest, Poison) {
// The existing statement has become invalid.
ASSERT_FALSE(valid_statement.is_valid());
ASSERT_FALSE(valid_statement.Step());
+
+ // Test that poisoning the database during a transaction works (with errors).
+ // RazeErrorCallback() poisons the database, the extra COMMIT causes
+ // CommitTransaction() to throw an error while commiting.
+ db().set_error_callback(base::Bind(&SQLConnectionTest::RazeErrorCallback,
+ base::Unretained(this),
+ SQLITE_ERROR));
+ db().Close();
+ ASSERT_TRUE(db().Open(db_path()));
+ EXPECT_TRUE(db().BeginTransaction());
+ EXPECT_TRUE(db().Execute("INSERT INTO x VALUES ('x')"));
+ EXPECT_TRUE(db().Execute("COMMIT"));
+ EXPECT_FALSE(db().CommitTransaction());
}
// Test attaching and detaching databases from the connection.