Details
-
Bug
-
Resolution: Fixed
-
P2
-
5.0
-
b51
-
generic
-
generic
Description
From: <###@###.###>
Background:
JSR133 requires that all fields of classes that are specified to be
immutable must be declared as "final". This solves a long-standing
issue in the memory semantics of Java that was not addressed in the
original JLS. The presense of "final" in such cases is more than a
decoration. It causes the compiler and hardware to not reorder
critical instructions in a way that could cause one thread to "catch"
an immutable object in the course of construction, and thus see its
pre-construction (0/null) value instead of its actual final
value. This is not just a theoretical possibility; without the use of
"final", this can and does occur regularly on multiprocessors. A
further discussion with examples of how this may induce security holes
may be found at
http://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#finalWrong
As part of JSR133, the expert group surveyed all classes in java.lang
and java.util, to find those that required field declarations be
marked as "final" to meet their specs. This was then done as bug
4998264.
While this is all fine, the JSR133 group did not address (or
anticipate the consequences of) a known interaction between "final"
and code that does "manual" deserialization, such as the XML
serialization in appServer: It is impossible to reflectively assign a
value to a final field. Thus, appServer broke. This might be
indicative of other similar code out there also being broken.
While it might be deal with this by undoing some of the "finals" in
4998264, this would be a crummy alternative in two senses: (1) It
merely delays the day of reckoning for dealing with the underlying
problem (2) People writing multithreaded code will be relying on
immutability guarantees that are not actually supported, so will
encounter extremely difficult to locate bugs.
Proposal:
Allow reflective set-field operations on any final field f,
ONLY if f.setAccessible(true) succeeds.
Advantages:
1. appServer will actually work. (Not just sort-of work, as true even
when using 1.4.x). Any other similar code out there that bothers
to do explicit setAccessible calls before setting fields will
similarly work.
2. In some limited circumstances, this technique can be used in
a serializable class's custom readObject method to initialize
final fields upon deserialization directly (rather than through
defaultReadObject). Note that because of the permission
requirement, this only applies to highly trusted code; it is not
a general solution.
3. No API change. It only requires addition of one new sentence in
the javadocs to describe the case when setting final is allowed.
4. By requiring the setAccessible check EVEN if the field is
public, there is essentially no possibility of accidental misuse.
5. If you have permission to suppress all access checks, then you can,
among other things change the security manager, so there is
no additional security risk here.
6. Bill Pugh and I can/will adjust the JSR133 spec to add the appropriate
wording about resulting multithreaded semantics.
7. There is almost no impact on plans to further optimize final fields
in the future inside hotspot.
8. And mainly: I think this is the simplest solution that actually works.
Disadvantages:
1. While the changes are straightforward, there are more lines of
them than anyone wants to see at this point.
2. If people use this in inappropriate contexts (i.e., in situations
not related to object reconstruction or deserialization)
their programs will make no sense.
Attachments
Issue Links
- duplicates
-
JDK-5041458 Add "final" modifiers to fields of immutable wrapper classes
- Closed
- relates to
-
JDK-8233873 final field values should be trusted as constant
- Open
-
JDK-5040310 Remove "final" modifier from fields in immutable classes so AppServer can run
- Resolved
-
JDK-4998264 Recommended changes to immutable classes for conformance to jsr133 (mem model)
- Resolved
-
JDK-5081108 reflective access to final longs loses uppper 32 bits on some x86 machines
- Closed
-
JDK-5103437 (reflect) Can set a final instance variable via reflection if setAccessible(true
- Closed
-
JDK-6379948 Need mechanism for implementing serializable classes with final fields
- Open