8000 Address a crash when close is called from finalize. · dw3/android-database-sqlcipher@fda559f · GitHub
[go: up one dir, main page]

Skip to content

Commit fda559f

Browse files
author
Kris Wong
committed
Address a crash when close is called from finalize.
On Android, finalize has 10 seconds to complete. SQLiteProgram.close is being called from finalize, and it does not consider whether it has already been closed before it tries to acquire the database lock. If the database is in use elsewhere, this can easily cause finalize to timeout, causing a fatal exception. This fixes the issue by making a second call to close a no-op.
1 parent f87cee1 commit fda559f

File tree

2 files changed

+37
-18
lines changed

2 files changed

+37
-18
lines changed

src/net/sqlcipher/database/SQLiteProgram.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ public abstract class SQLiteProgram extends SQLiteClosable {
5858
@Deprecated
5959
protected long nStatement = 0;
6060

61+
/**
62+
* Indicates whether {@link #close()} has been called.
63+
*/
64+
boolean mClosed = false;
65+
6166
/* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
6267
mDatabase = db;
6368
mSql = sql.trim();
@@ -142,7 +147,7 @@ private void releaseCompiledSqlIfNotInCache() {
142147
// it is in compiled-sql cache. reset its CompiledSql#mInUse flag
143148
mCompiledSql.release();
144149
}
145-
}
150+
}
146151
}
147152

148153
/**
@@ -177,6 +182,9 @@ protected void compile(String sql, boolean forceCompilation) {
177182
* @param index The 1-based index to the parameter to bind null to
178183
*/
179184
public void bindNull(int index) {
185+
if (mClosed) {
186+
throw new IllegalStateException("program already closed");
187+
}
180188
if (!mDatabase.isOpen()) {
181189
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
182190
}
@@ -196,6 +204,9 @@ public void bindNull(int index) {
196204
* @param value The value to bind
197205
*/
198206
public void bindLong(int index, long value) {
207+
if (mClosed) {
208+ 8000
throw new IllegalStateException("program already closed");
209+
}
199210
if (!mDatabase.isOpen()) {
200211
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
201212
}
@@ -215,6 +226,9 @@ public void bindLong(int index, long value) {
215226
* @param value The value to bind
216227
*/
217228
public void bindDouble(int index, double value) {
229+
if (mClosed) {
230+
throw new IllegalStateException("program already closed");
231+
}
218232
if (!mDatabase.isOpen()) {
219233
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
220234
}
@@ -237,6 +251,9 @@ public void bindString(int index, String value) {
237251
if (value == null) {
238252
throw new IllegalArgumentException("the bind value at index " + index + " is null");
239253
}
254+
if (mClosed) {
255+
throw new IllegalStateException("program already closed");
256+
}
240257
if (!mDatabase.isOpen()) {
241258
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
242259
}
@@ -259,6 +276,9 @@ public void bindBlob(int index, byte[] value) {
259276
if (value == null) {
260277
throw new IllegalArgumentException("the bind value at index " + index + " is null");
261278
}
279+
if (mClosed) {
280+
throw new IllegalStateException("program already closed");
281+
}
262282
if (!mDatabase.isOpen()) {
263283
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
264284
}
@@ -274,6 +294,9 @@ public void bindBlob(int index, byte[] value) {
274294
* Clears all existing bindings. Unset bindings are treated as NULL.
275295
*/
276296
public void clearBindings() {
297+
if (mClosed) {
298+
throw new IllegalStateException("program already closed");
299+
}
277300
if (!mDatabase.isOpen()) {
278301
throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
279302
}
@@ -289,6 +312,9 @@ public void clearBindings() {
289312
* Release this program's resources, making it invalid.
290313
*/
291314
public void close() {
315+
if (mClosed) {
316+
return;
317+
}
292318
if (!mDatabase.isOpen()) {
293319
return;
294320
}
@@ -298,6 +324,7 @@ public void close() {
298324
} finally {
299325
mDatabase.unlock();
300326
}
327+
mClosed = true;
301328
}
302329

303330
/**

src/net/sqlcipher/database/SQLiteQuery.java

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,16 @@ public class SQLiteQuery extends SQLiteProgram {
3232

3333
/** The index of the unbound OFFSET parameter */
3434
private int mOffsetIndex;
35-
35+
3636
/** Args to bind on requery */
3737
private String[] mBindArgs;
3838

39-
private boolean mClosed = false;
40-
4139
/**
4240
* Create a persistent query object.
43-
*
41+
*
4442
* @param db The database that this query object is associated with
45-
* @param query The SQL string for this query.
46-
* @param offsetIndex The 1-based index to the OFFSET parameter,
43+
* @param query The SQL string for this query.
44+
* @param offsetIndex The 1-based index to the OFFSET parameter,
4745
*/
4846
/* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) {
4947
super(db, query);
@@ -96,7 +94,7 @@ public class SQLiteQuery extends SQLiteProgram {
9694
* Get the column count for the statement. Only valid on query based
9795
* statements. The database must be locked
9896
* when calling this method.
99-
*
97+
*
10098
* @return The number of column in the statement's result set.
10199
*/
102100
/* package */ int columnCountLocked() {
@@ -111,7 +109,7 @@ public class SQLiteQuery extends SQLiteProgram {
111109
/**
112110
* Retrieves the column name for the given column index. The database must be locked
113111
* when calling this method.
114-
*
112+
*
115113
* @param columnIndex the index of the column to get the name for
116114
* @return The requested column's name
117115
*/
@@ -123,17 +121,11 @@ public class SQLiteQuery extends SQLiteProgram {
123121
releaseReference();
124122
}
125123
}
126-
124+
127125
@Override
128126
public String toString() {
129127
return "SQLiteQuery: " + mSql;
130128
}
131-
132-
@Override
133-
public void close() {
134-
super.close();
135-
mClosed = true;
136-
}
137129

138130
/**
139131
* Called by SQLiteCursor when it is requeried.
@@ -154,7 +146,7 @@ public void close() {
154146
errMsg.append(" ");
155147
IllegalStateException leakProgram = new IllegalStateException(
156148
errMsg.toString(), e);
157-
throw leakProgram;
149+
throw leakProgram;
158150
}
159151
}
160152
}
@@ -183,7 +175,7 @@ public void bindString(int index, String value) {
183175
if (!mClosed) super.bindString(index, value);
184176
}
185177

186-
private final native int native_fill_window(CursorWindow window,
178+
private final native int native_fill_window(CursorWindow window,
187179
int startPos, int offsetParam, int maxRead, int lastPos);
188180

189181
private final native int native_column_count();

0 commit comments

Comments
 (0)
0