Defer reporting of certain verifier failures.
The verifier currently reports all failures immediately. Certain failures,
such as the failure to resolve a method, or the determination that access
to a field is not allowed, are supposed to deferred until the first time
that executing code does something that could cause the resolution.
With this change, several kinds of verification failures are deferred.
This is done by making a writable copy of the bytecode and replacing the
failing instruction with an "always throw" opcode.
Gory details:
- Added throw-verification-error instruction. Implemented in "portable"
and ARM interpreters. x86 uses portable form through stub.
- Added a function that creates a copy of a DexCode area and makes the
bytecodes writable.
- Added code that replaces a single instruction with an "always throw".
- Replaced runtime check for abstract/interface in new-instance with a
check at verification time.
- Added a test to exercise the deferred error mechanism.
- Minor cleanups (replaced tab, bad valgrind command, ...).
diff --git a/libdex/DexFile.c b/libdex/DexFile.c
index a8b5345..99b38c9 100644
--- a/libdex/DexFile.c
+++ b/libdex/DexFile.c
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Access the contents of a .dex file.
*/
#include "DexFile.h"
#include "DexProto.h"
+#include "DexCatch.h"
#include "Leb128.h"
#include "sha1.h"
#include "ZipArchive.h"
@@ -887,6 +889,43 @@
/*
+ * Compute the size, in bytes, of a DexCode.
+ */
+size_t dexGetDexCodeSize(const DexCode* pCode)
+{
+ /*
+ * The catch handler data is the last entry. It has a variable number
+ * of variable-size pieces, so we need to create an iterator.
+ */
+ u4 handlersSize;
+ u4 offset;
+ u4 ui;
+
+ if (pCode->triesSize != 0) {
+ handlersSize = dexGetHandlersSize(pCode);
+ offset = dexGetFirstHandlerOffset(pCode);
+ } else {
+ handlersSize = 0;
+ offset = 0;
+ }
+
+ for (ui = 0; ui < handlersSize; ui++) {
+ DexCatchIterator iterator;
+ dexCatchIteratorInit(&iterator, pCode, offset);
+ offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
+ }
+
+ const u1* handlerData = dexGetCatchHandlerData(pCode);
+
+ //LOGD("+++ pCode=%p handlerData=%p last offset=%d\n",
+ // pCode, handlerData, offset);
+
+ /* return the size of the catch handler + everything before it */
+ return (handlerData - (u1*) pCode) + offset;
+}
+
+
+/*
* ===========================================================================
* Debug info
* ===========================================================================
@@ -1185,3 +1224,4 @@
free(methodDescriptor);
}
}
+
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index 4d8d151..4b5fe7c 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -735,6 +735,9 @@
return dexStringById(pDexFile, pClassDef->sourceFileIdx);
}
+/* get the size, in bytes, of a DexCode */
+size_t dexGetDexCodeSize(const DexCode* pCode);
+
/* Get the list of "tries" for the given DexCode. */
DEX_INLINE const DexTry* dexGetTries(const DexCode* pCode) {
const u2* insnsEnd = &pCode->insns[pCode->insnsSize];
@@ -753,6 +756,7 @@
return (const u1*) &pTries[pCode->triesSize];
}
+/* get a pointer to the start of the debugging data */
DEX_INLINE const u1* dexGetDebugInfoStream(const DexFile* pDexFile,
const DexCode* pCode)
{
diff --git a/libdex/InstrUtils.c b/libdex/InstrUtils.c
index f9ce4de..33c7e7d 100644
--- a/libdex/InstrUtils.c
+++ b/libdex/InstrUtils.c
@@ -604,7 +604,7 @@
flags = kInstrCanSwitch | kInstrCanContinue;
break;
- /* optimizer-generated instructions */
+ /* verifier/optimizer-generated instructions */
case OP_THROW_VERIFICATION_ERROR:
flags = kInstrCanThrow;
break;