Loading core/jni/android_database_SQLiteRawStatement.cpp +32 −11 Original line number Original line Diff line number Diff line Loading @@ -72,14 +72,17 @@ static void throwInvalidParameter(JNIEnv *env, jlong stmtPtr, jint index) { // This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out // This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out // of bounds. // of bounds. It returns true if an exception was thrown. static void throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { if (col < 0 || col >= sqlite3_data_count(stmt(stmtPtr))) { if (col < 0 || col >= sqlite3_data_count(stmt(stmtPtr))) { int count = sqlite3_data_count(stmt(stmtPtr)); int count = sqlite3_data_count(stmt(stmtPtr)); std::string message = android::base::StringPrintf( std::string message = android::base::StringPrintf( "column index %d out of bounds [0,%d]", col, count - 1); "column index %d out of bounds [0,%d]", col, count - 1); char const * errmsg = sqlite3_errstr(SQLITE_RANGE); char const * errmsg = sqlite3_errstr(SQLITE_RANGE); throw_sqlite3_exception(env, SQLITE_RANGE, errmsg, message.c_str()); throw_sqlite3_exception(env, SQLITE_RANGE, errmsg, message.c_str()); return true; } else { return false; } } } } Loading Loading @@ -216,12 +219,16 @@ static void bindText(JNIEnv* env, jclass, jlong stmtPtr, jint index, jstring val static jint columnType(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnType(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_type(stmt(stmtPtr), col); return sqlite3_column_type(stmt(stmtPtr), col); } } static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return nullptr; } const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(stmt(stmtPtr), col)); const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(stmt(stmtPtr), col)); if (name == nullptr) { if (name == nullptr) { throw_sqlite3_exception(env, db(stmtPtr), "error fetching columnName()"); throw_sqlite3_exception(env, db(stmtPtr), "error fetching columnName()"); Loading @@ -232,14 +239,18 @@ static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { } } static jint columnBytes(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnBytes(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } int r = sqlite3_column_bytes16(stmt(stmtPtr), col); int r = sqlite3_column_bytes16(stmt(stmtPtr), col); throwIfError(env, stmtPtr); throwIfError(env, stmtPtr); return r; return r; } } static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return nullptr; } const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { if (blob == nullptr) { if (throwIfError(env, stmtPtr)) { if (throwIfError(env, stmtPtr)) { Loading @@ -262,7 +273,9 @@ static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, jbyteArray buffer, jint offset, jint length, jint srcOffset) { jbyteArray buffer, jint offset, jint length, jint srcOffset) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { if (blob == nullptr) { throwIfError(env, stmtPtr); throwIfError(env, stmtPtr); Loading @@ -281,22 +294,30 @@ static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, } } static jdouble columnDouble(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jdouble columnDouble(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_double(stmt(stmtPtr), col); return sqlite3_column_double(stmt(stmtPtr), col); } } static jint columnInt(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnInt(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_int(stmt(stmtPtr), col); return sqlite3_column_int(stmt(stmtPtr), col); } } static jlong columnLong(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jlong columnLong(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_int64(stmt(stmtPtr), col); return sqlite3_column_int64(stmt(stmtPtr), col); } } static jstring columnText(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jstring columnText(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return nullptr; } const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(stmt(stmtPtr), col)); const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(stmt(stmtPtr), col)); if (text == nullptr) { if (text == nullptr) { throwIfError(env, stmtPtr); throwIfError(env, stmtPtr); Loading core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +27 −0 Original line number Original line Diff line number Diff line Loading @@ -999,4 +999,31 @@ public class SQLiteRawStatementTest { mDatabase.endTransaction(); mDatabase.endTransaction(); } } } } /** * This test verifies that the JNI exception thrown because of a bad column is actually thrown * and does not crash the VM. */ @Test public void testJniExceptions() { // Create the t1 table. mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (i int, j int);"); mDatabase.setTransactionSuccessful(); } finally { mDatabase.endTransaction(); } mDatabase.beginTransactionReadOnly(); try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1")) { s.step(); s.getColumnText(5); // out-of-range column fail("JNI exception not thrown"); } catch (SQLiteBindOrColumnIndexOutOfRangeException e) { // Passing case. } finally { mDatabase.endTransaction(); } } } } Loading
core/jni/android_database_SQLiteRawStatement.cpp +32 −11 Original line number Original line Diff line number Diff line Loading @@ -72,14 +72,17 @@ static void throwInvalidParameter(JNIEnv *env, jlong stmtPtr, jint index) { // This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out // This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out // of bounds. // of bounds. It returns true if an exception was thrown. static void throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { if (col < 0 || col >= sqlite3_data_count(stmt(stmtPtr))) { if (col < 0 || col >= sqlite3_data_count(stmt(stmtPtr))) { int count = sqlite3_data_count(stmt(stmtPtr)); int count = sqlite3_data_count(stmt(stmtPtr)); std::string message = android::base::StringPrintf( std::string message = android::base::StringPrintf( "column index %d out of bounds [0,%d]", col, count - 1); "column index %d out of bounds [0,%d]", col, count - 1); char const * errmsg = sqlite3_errstr(SQLITE_RANGE); char const * errmsg = sqlite3_errstr(SQLITE_RANGE); throw_sqlite3_exception(env, SQLITE_RANGE, errmsg, message.c_str()); throw_sqlite3_exception(env, SQLITE_RANGE, errmsg, message.c_str()); return true; } else { return false; } } } } Loading Loading @@ -216,12 +219,16 @@ static void bindText(JNIEnv* env, jclass, jlong stmtPtr, jint index, jstring val static jint columnType(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnType(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_type(stmt(stmtPtr), col); return sqlite3_column_type(stmt(stmtPtr), col); } } static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return nullptr; } const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(stmt(stmtPtr), col)); const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(stmt(stmtPtr), col)); if (name == nullptr) { if (name == nullptr) { throw_sqlite3_exception(env, db(stmtPtr), "error fetching columnName()"); throw_sqlite3_exception(env, db(stmtPtr), "error fetching columnName()"); Loading @@ -232,14 +239,18 @@ static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { } } static jint columnBytes(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnBytes(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } int r = sqlite3_column_bytes16(stmt(stmtPtr), col); int r = sqlite3_column_bytes16(stmt(stmtPtr), col); throwIfError(env, stmtPtr); throwIfError(env, stmtPtr); return r; return r; } } static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return nullptr; } const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { if (blob == nullptr) { if (throwIfError(env, stmtPtr)) { if (throwIfError(env, stmtPtr)) { Loading @@ -262,7 +273,9 @@ static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, jbyteArray buffer, jint offset, jint length, jint srcOffset) { jbyteArray buffer, jint offset, jint length, jint srcOffset) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { if (blob == nullptr) { throwIfError(env, stmtPtr); throwIfError(env, stmtPtr); Loading @@ -281,22 +294,30 @@ static int columnBuffer(JNIEnv* env, jclass, jlong stmtPtr, jint col, } } static jdouble columnDouble(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jdouble columnDouble(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_double(stmt(stmtPtr), col); return sqlite3_column_double(stmt(stmtPtr), col); } } static jint columnInt(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jint columnInt(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_int(stmt(stmtPtr), col); return sqlite3_column_int(stmt(stmtPtr), col); } } static jlong columnLong(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jlong columnLong(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return 0; } return sqlite3_column_int64(stmt(stmtPtr), col); return sqlite3_column_int64(stmt(stmtPtr), col); } } static jstring columnText(JNIEnv* env, jclass, jlong stmtPtr, jint col) { static jstring columnText(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); if (throwIfInvalidColumn(env, stmtPtr, col)) { return nullptr; } const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(stmt(stmtPtr), col)); const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(stmt(stmtPtr), col)); if (text == nullptr) { if (text == nullptr) { throwIfError(env, stmtPtr); throwIfError(env, stmtPtr); Loading
core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +27 −0 Original line number Original line Diff line number Diff line Loading @@ -999,4 +999,31 @@ public class SQLiteRawStatementTest { mDatabase.endTransaction(); mDatabase.endTransaction(); } } } } /** * This test verifies that the JNI exception thrown because of a bad column is actually thrown * and does not crash the VM. */ @Test public void testJniExceptions() { // Create the t1 table. mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (i int, j int);"); mDatabase.setTransactionSuccessful(); } finally { mDatabase.endTransaction(); } mDatabase.beginTransactionReadOnly(); try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1")) { s.step(); s.getColumnText(5); // out-of-range column fail("JNI exception not thrown"); } catch (SQLiteBindOrColumnIndexOutOfRangeException e) { // Passing case. } finally { mDatabase.endTransaction(); } } } }