Skip to content
This repository was archived by the owner on Nov 15, 2022. It is now read-only.

Commit 0df4413

Browse files
committed
Update bytecode verifier info.
Rewrote last section to describe deferred verification error reporting. Added note about structured locking checks.
1 parent e4b3060 commit 0df4413

1 file changed

Lines changed: 47 additions & 31 deletions

File tree

docs/verifier.html

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ <h2>Why Verify?</h2>
3333
error cases because the verifier guarantees that they are impossible.
3434
Also, we can optimize the DEX file more aggressively if we start
3535
with a stronger set of assumptions about the bytecode.
36-
<li>"Exact" GC. The work peformed during verification has significant
37-
overlap with the work required to compute register use maps for exact
38-
GC. Improper register use, caught by the verifier, could lead to
39-
subtle problems with an "exact" GC.
36+
<li>"Precise" GC. The work peformed during verification has significant
37+
overlap with the work required to compute register use maps for
38+
type-precise GC.
4039
<li>Intra-application security. If an app wants to download bits
4140
of interpreted code over the network and execute them, it can safely
4241
do so using well-established security mechanisms.
@@ -84,6 +83,12 @@ <h2>Verifier Differences</h2>
8483
or <code>filled-new-array</code> instruction.
8584
</ul>
8685

86+
<p>
87+
The VM is permitted but not required to enforce "structured locking"
88+
constraints, which are designed to ensure that, when a method returns, all
89+
monitors locked by the method have been unlocked an equal number of times.
90+
This is not currently implemented.
91+
8792
<p>
8893
The Dalvik verifier is more restrictive than other VMs in one area:
8994
type safety on sub-32-bit integer widths. These additional restrictions
@@ -94,24 +99,31 @@ <h2>Verifier Differences</h2>
9499
<h2>Verification Failures</h2>
95100

96101
<p>
97-
When the verifier rejects a class, it always throws a VerifyError.
98-
This is different in some cases from other implementations. For example,
99-
if a class attempts to perform an illegal access on a field, the expected
100-
behavior is to receive an IllegalAccessError at runtime the first time
101-
the field is actually accessed. The Dalvik verifier will reject the
102-
entire class immediately.
102+
The verifier may reject a class immediately, or it may defer throwing
103+
an exception until the code is actually used. For example, if a class
104+
attempts to perform an illegal access on a field, the VM should throw
105+
an IllegalAccessError the first time the instruction is encountered.
106+
On the other hand, if a class contains an invalid bytecode, it should be
107+
rejected immediately with a VerifyError.
103108

104109
<p>
105-
It's difficult to throw the error on first use in Dalvik. Possible ways
106-
to implement this behavior include:
110+
Immediate VerifyErrors are accompanied by detailed, if somewhat cryptic,
111+
information in the log file. From this it's possible to determine the
112+
exact instruction that failed, and the reason for the failure.
113+
114+
<p>
115+
It's a bit tricky to implement deferred verification errors in Dalvik.
116+
A few approaches were considered:
107117

108118
<ol>
109119
<li>We could replace the invalid field access instruction with a special
110120
instruction that generates an illegal access error, and allow class
111121
verification to complete successfully. This type of verification must
112-
often be deferred to first class load, rather than be performed ahead of time
113-
during DEX optimization, which means the bytecode instructions will be
114-
mapped read-only during verification. So this won't work.
122+
be deferred to first class load, rather than be performed ahead of time
123+
during DEX optimization, because some failures will depend on the current
124+
execution environment (e.g. not all classes are available at dexopt time).
125+
At that point the bytecode instructions are mapped read-only during
126+
verification, so rewriting them isn't possible.
115127
</li>
116128

117129
<li>We can perform the access checks when the field/method/class is
@@ -120,7 +132,7 @@ <h2>Verification Failures</h2>
120132
files combine multiple classfiles together, merging the field/method/class
121133
resolution results into a single large table. Once one class successfully
122134
resolves the field, every other class in the same DEX file would be able
123-
to access the field. This is bad.
135+
to access the field. This is incorrect.
124136
</li>
125137

126138
<li>Perform the access checks on every field/method/class access.
@@ -134,25 +146,29 @@ <h2>Verification Failures</h2>
134146
</ol>
135147

136148
<p>
137-
Other implementations are possible, but they all involve allocating
138-
some amount of additional memory or spending additional cycles
139-
on non-DEX-optimized instructions. We don't want to throw an
140-
IllegalAccessError at verification time, since that would indicate that
141-
access to the class being verified was illegal.
149+
In early versions of Dalvik (as shipped with Android 1.0/1.5), the verifier
150+
simply regarded all problems as immediately fatal. This generally worked,
151+
but in some cases the VM was rejecting classes because of bits of code
152+
that were never used. The VerifyError itself was sometimes difficult to
153+
decipher, because it was thrown during verification rather than at the
154+
point where the problem was first noticed during execution.
142155
<p>
143-
One approach that might be worth pursuing: for situations like illegal
144-
accesses, the verifier makes an in-RAM private copy of the method, and
145-
alters the instructions there. The class object is altered to point at
146-
the new copy of the instructions. This requires minimal memory overhead
147-
and provides a better experience for developers.
156+
The current version uses a variation of approach #1. The dexopt
157+
command works the way it did before, leaving the code untouched and
158+
flagging fully-correct classes as "pre-verified". When the VM loads a
159+
class that didn't pass pre-verification, the verifier is invoked. If a
160+
"deferrable" problem is detected, a modifiable copy of the instructions
161+
in the problematic method is made. In that copy, the troubled instruction
162+
is replaced with an "always throw" opcode, and verification continues.
148163

149164
<p>
150-
The VerifyError is accompanied by detailed, if somewhat cryptic,
151-
information in the log file. From this it's possible to determine the
152-
exact instruction that failed, and the reason for the failure. We can
153-
also constructor the VerifyError with an IllegalAccessError passed in as
154-
the cause.
165+
In the example used earlier, an attempt to read from an inaccessible
166+
field would result in the "field get" instruction being replaced by
167+
"always throw IllegalAccessError on field X". Creating copies of method
168+
bodies requires additional heap space, but since this affects very few
169+
methods overall the memory impact should be minor.
155170

171+
<p>
156172
<address>Copyright &copy; 2008 The Android Open Source Project</address>
157173

158174
</body>

0 commit comments

Comments
 (0)