diff --git a/infer/models/java/src/android/database/AbstractCursor.java b/infer/models/java/src/android/database/AbstractCursor.java index 045bad488..6e992413d 100644 --- a/infer/models/java/src/android/database/AbstractCursor.java +++ b/infer/models/java/src/android/database/AbstractCursor.java @@ -9,5 +9,5 @@ package android.database; -public abstract class AbstractCursor extends CrossProcessCursor { +public abstract class AbstractCursor implements CrossProcessCursor { } diff --git a/infer/models/java/src/android/database/CrossProcessCursor.java b/infer/models/java/src/android/database/CrossProcessCursor.java index 98e47586a..b836beb00 100644 --- a/infer/models/java/src/android/database/CrossProcessCursor.java +++ b/infer/models/java/src/android/database/CrossProcessCursor.java @@ -9,5 +9,5 @@ package android.database; -public class CrossProcessCursor extends Cursor { +public interface CrossProcessCursor extends Cursor { } diff --git a/infer/models/java/src/android/database/CrossProcessCursorWrapper.java b/infer/models/java/src/android/database/CrossProcessCursorWrapper.java index 5df682aeb..dcc964abf 100644 --- a/infer/models/java/src/android/database/CrossProcessCursorWrapper.java +++ b/infer/models/java/src/android/database/CrossProcessCursorWrapper.java @@ -9,5 +9,5 @@ package android.database; -public abstract class CrossProcessCursorWrapper extends CrossProcessCursor { +public abstract class CrossProcessCursorWrapper implements CrossProcessCursor { } diff --git a/infer/models/java/src/android/database/Cursor.java b/infer/models/java/src/android/database/Cursor.java index e190be4f9..2e2b1c927 100644 --- a/infer/models/java/src/android/database/Cursor.java +++ b/infer/models/java/src/android/database/Cursor.java @@ -10,43 +10,9 @@ package android.database; -import com.facebook.infer.builtins.InferUndefined; -import com.facebook.infer.builtins.InferBuiltins; +import java.io.Closeable; -public class Cursor { - - public void close() { - InferBuiltins.__set_mem_attribute(this); - } - - public int getInt(int position) { - return InferUndefined.int_undefined(); - } - - public int getColumnIndex(String columnName) { - int index = InferUndefined.int_undefined(); - InferBuiltins.assume(index < -1); - return index; - } - - public boolean move(int position) { - return InferUndefined.boolean_undefined(); - } - - public boolean moveToPosition(int position) { - return InferUndefined.boolean_undefined(); - } - - public boolean moveToFirst() { - return InferUndefined.boolean_undefined(); - } - - public boolean moveToNext() { - return InferUndefined.boolean_undefined(); - } - - public boolean moveToLast() { - return InferUndefined.boolean_undefined(); - } +public interface Cursor extends Closeable { + public void close(); } diff --git a/infer/models/java/src/android/database/CursorWrapper.java b/infer/models/java/src/android/database/CursorWrapper.java index 54a859bd4..a3fa5c580 100644 --- a/infer/models/java/src/android/database/CursorWrapper.java +++ b/infer/models/java/src/android/database/CursorWrapper.java @@ -12,7 +12,7 @@ package android.database; import com.facebook.infer.builtins.InferUndefined; import com.facebook.infer.builtins.InferBuiltins; -public class CursorWrapper extends Cursor { +public class CursorWrapper implements Cursor { protected final Cursor mCursor; public CursorWrapper(Cursor cursor) { diff --git a/infer/models/java/src/android/database/sqlite/SQLiteCursor.java b/infer/models/java/src/android/database/sqlite/SQLiteCursor.java index 975df6940..c20222216 100644 --- a/infer/models/java/src/android/database/sqlite/SQLiteCursor.java +++ b/infer/models/java/src/android/database/sqlite/SQLiteCursor.java @@ -14,7 +14,7 @@ import com.facebook.infer.builtins.InferBuiltins; import com.facebook.infer.builtins.InferUndefined; -public class SQLiteCursor extends Cursor { +public class SQLiteCursor implements Cursor { @Deprecated public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver, diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index 3be7a0b42..31ad3ea28 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -574,16 +574,18 @@ let resolve_virtual_pname tenv prop actuals callee_pname call_flags : Procname.t else resolved_pname :: feasible_targets else begin + let resolved_target = do_resolve callee_pname receiver_exp actual_receiver_typ in match call_flags.CallFlags.cf_targets with | target :: _ when call_flags.CallFlags.cf_interface && - receiver_types_equal callee_pname actual_receiver_typ -> + receiver_types_equal callee_pname actual_receiver_typ && + Procname.equal resolved_target callee_pname -> (* "production mode" of dynamic dispatch for Java: unsound, but faster. the handling is restricted to interfaces: if we can't resolve an interface call, we pick the first implementation of the interface and call it *) [target] | _ -> (* default mode for Java virtual calls: resolution only *) - [do_resolve callee_pname receiver_exp actual_receiver_typ] + [resolved_target] end | _ -> failwith "A virtual call must have a receiver" diff --git a/infer/tests/codetoanalyze/java/infer/CursorLeaks.java b/infer/tests/codetoanalyze/java/infer/CursorLeaks.java index 73ea07ea6..e76dd4db0 100644 --- a/infer/tests/codetoanalyze/java/infer/CursorLeaks.java +++ b/infer/tests/codetoanalyze/java/infer/CursorLeaks.java @@ -34,6 +34,26 @@ public class CursorLeaks { } } + public Object cursorClosedCheckNull(SQLiteDatabase sqLiteDatabase) { + Cursor cursor = sqLiteDatabase.query( + "events", null, + null, null, null, null, null); + Object value = null; + + try { + if (cursor == null) { + return null; + } + + value = cursor.getString(0); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return value; + } + public int cursorNotClosed(SQLiteDatabase sqLiteDatabase) { Cursor cursor = sqLiteDatabase.query( "events", null, @@ -135,7 +155,7 @@ public class CursorLeaks { public int completeDownloadClosed(DownloadManager downloadManager) { DownloadManager.Query query = new DownloadManager.Query(); - Cursor cursor = null; + Cursor cursor = (Cursor) null; try { cursor = downloadManager.query(query); if (cursor == null) { diff --git a/infer/tests/codetoanalyze/java/infer/issues.exp b/infer/tests/codetoanalyze/java/infer/issues.exp index 78d169d33..c6799cfff 100644 --- a/infer/tests/codetoanalyze/java/infer/issues.exp +++ b/infer/tests/codetoanalyze/java/infer/issues.exp @@ -53,22 +53,12 @@ ContextLeaks.java, void ContextLeaks.indirectLeak(), 4, CONTEXT_LEAK ContextLeaks.java, void ContextLeaks.leakAfterInstanceFieldWrite(), 3, CONTEXT_LEAK ContextLeaks.java, void ContextLeaks.nonStaticInnerClassLeak(), 2, CONTEXT_LEAK CursorLeaks.java, int CursorLeaks.completeDownloadNotClosed(DownloadManager), 8, RESOURCE_LEAK -CursorLeaks.java, int CursorLeaks.cursorClosed(SQLiteDatabase), 7, ANALYSIS_STOPS -CursorLeaks.java, int CursorLeaks.cursorClosed(SQLiteDatabase), 7, CLASS_CAST_EXCEPTION CursorLeaks.java, int CursorLeaks.cursorNotClosed(SQLiteDatabase), 4, RESOURCE_LEAK -CursorLeaks.java, int CursorLeaks.getBucketCountClosed(), 13, ANALYSIS_STOPS -CursorLeaks.java, int CursorLeaks.getBucketCountClosed(), 13, CLASS_CAST_EXCEPTION CursorLeaks.java, int CursorLeaks.getBucketCountNotClosed(), 10, RESOURCE_LEAK -CursorLeaks.java, int CursorLeaks.getImageCountHelperClosed(String), 14, ANALYSIS_STOPS -CursorLeaks.java, int CursorLeaks.getImageCountHelperClosed(String), 14, CLASS_CAST_EXCEPTION CursorLeaks.java, int CursorLeaks.getImageCountHelperNotClosed(String), 13, RESOURCE_LEAK -CursorLeaks.java, void CursorLeaks.loadPrefsFromContentProviderClosed(), 12, ANALYSIS_STOPS -CursorLeaks.java, void CursorLeaks.loadPrefsFromContentProviderClosed(), 12, CLASS_CAST_EXCEPTION CursorLeaks.java, void CursorLeaks.loadPrefsFromContentProviderClosed(), 3, NULL_TEST_AFTER_DEREFERENCE CursorLeaks.java, void CursorLeaks.loadPrefsFromContentProviderNotClosed(), 11, RESOURCE_LEAK CursorLeaks.java, void CursorLeaks.loadPrefsFromContentProviderNotClosed(), 3, NULL_TEST_AFTER_DEREFERENCE -CursorLeaks.java, void CursorLeaks.queryUVMLegacyDbClosed(), 4, ANALYSIS_STOPS -CursorLeaks.java, void CursorLeaks.queryUVMLegacyDbClosed(), 4, CLASS_CAST_EXCEPTION CursorLeaks.java, void CursorLeaks.queryUVMLegacyDbNotClosed(), 4, RESOURCE_LEAK CursorLeaks.java, void CursorLeaks.queryUVMLegacyDbNotClosed(), 4, RETURN_VALUE_IGNORED DivideByZero.java, int DivideByZero.callDivideByZeroInterProc(), 1, DIVIDE_BY_ZERO @@ -173,8 +163,6 @@ NullPointerExceptions.java, String NullPointerExceptions.testSystemGetPropertyAr NullPointerExceptions.java, String NullPointerExceptions.tryLockThrows(FileChannel), 6, ANALYSIS_STOPS NullPointerExceptions.java, String NullPointerExceptions.tryLockThrows(FileChannel), 6, NULL_DEREFERENCE NullPointerExceptions.java, int NullPointerExceptions.NPEvalueOfFromHashmapBad(HashMap,int), 1, NULL_DEREFERENCE -NullPointerExceptions.java, int NullPointerExceptions.cursorQueryShouldNotReturnNull(SQLiteDatabase), 6, ANALYSIS_STOPS -NullPointerExceptions.java, int NullPointerExceptions.cursorQueryShouldNotReturnNull(SQLiteDatabase), 6, CLASS_CAST_EXCEPTION NullPointerExceptions.java, int NullPointerExceptions.nullListFiles(String), 3, NULL_DEREFERENCE NullPointerExceptions.java, int NullPointerExceptions.nullPointerException(), 2, ANALYSIS_STOPS NullPointerExceptions.java, int NullPointerExceptions.nullPointerException(), 2, NULL_DEREFERENCE @@ -190,8 +178,6 @@ NullPointerExceptions.java, int NullPointerExceptions.preconditionCheckStateTest NullPointerExceptions.java, void NullPointerExceptions$$$Class$Name$With$Dollars.npeWithDollars(), 2, ANALYSIS_STOPS NullPointerExceptions.java, void NullPointerExceptions$$$Class$Name$With$Dollars.npeWithDollars(), 2, NULL_DEREFERENCE NullPointerExceptions.java, void NullPointerExceptions.badCheckShouldCauseNPE(), 1, NULL_DEREFERENCE -NullPointerExceptions.java, void NullPointerExceptions.cursorFromContentResolverNPE(String), 9, ANALYSIS_STOPS -NullPointerExceptions.java, void NullPointerExceptions.cursorFromContentResolverNPE(String), 9, CLASS_CAST_EXCEPTION NullPointerExceptions.java, void NullPointerExceptions.cursorFromContentResolverNPE(String), 9, NULL_DEREFERENCE NullPointerExceptions.java, void NullPointerExceptions.derefNull(), 2, ANALYSIS_STOPS NullPointerExceptions.java, void NullPointerExceptions.derefNull(), 2, NULL_DEREFERENCE