Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d65cc9c6 authored by Lee Shombert's avatar Lee Shombert
Browse files

Correct JNI exception handling

Return immediately from a JNI function if an exception is thrown.  Do
not continue with further JNI operations.

Flag: EXEMPT bugfix
Bug: 359669601
Test: atest
 * FrameworksCoreTests:android.database
 * CtsDatabaseTestCases
Change-Id: Ied90b87935f11688d6bf2a943d63ef4ccb933e6b
parent ebf8e0c8
Loading
Loading
Loading
Loading
+32 −11
Original line number Original line Diff line number Diff line
@@ -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;
    }
    }
}
}


@@ -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()");
@@ -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)) {
@@ -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);
@@ -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);
+27 −0
Original line number Original line Diff line number Diff line
@@ -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();
        }
    }
}
}