Immutable defrecord fields can be changed via set!

Description

The docstring for deftype says that the (set! field value) syntax is available in method bodies for mutable deftype fields. Trying to set an immutable type or record field with (set! a newa) will fail at compile time:

However, you can also use the instance field set! syntax in this location (set! (.a this) newa) - this is passes the compiler and (susprisingly!) works at runtime even though the field is final:

Cause:

The set! instance assignment does not check whether the field can be written and just emits the bytecode. The Java verifier for Java 8 bytecode does not prevent a write to a final field from happening (the policy on this has changed multiple times over the lifetime of Java). In JVM 9+, the bytecode verifier does perform final assignment check on class files version 9+ (Clojure class files are currently Java 8 level).

Alternatives:

  1. Do nothing, and wait for this to get caught at runtime in the future when we are using a later Java verifier, ie: don’t do that. This would probably fail at runtime with an IllegalAccessError if I understand correctly.

  2. At compile time, in InstanceFieldExpr and StaticFieldExpr, check whether the field is ‘final’ and throw a compiler exception. The class may be unknown, in which case this is a reflective call and it must fail at runtime instead.

  3. At compile time, do something specific in InstanceFieldExpr for type/record immutable fields (IRecord/IType). Don’t think we have access to the type field metadata just based on the class so the best we can do here is probably same as #2, checking final field.

Approach:

Check field accessibility for assignment and fail if attempting to emit a field assignment to a final field at compile time. A reflective field assignment will fail at runtime.

Patch: 0001-CLJ-2126-don-t-assign-final-fields.patch

Environment

None

Attachments

1

Activity

Show:

Alex MillerDecember 5, 2023 at 7:07 PM

moving out of 1.12, will reconsider in future

Erik AssumMarch 21, 2022 at 4:02 PM

Erik AssumMarch 20, 2022 at 10:27 AM

While trying to add tests to this (and failing at that) I discovered that applying this patch makes mvn install fail because a test in test/clojure/test_clojure/compilation.clj and This test fails because the cases shown ( and ) both do what this patch is preventing us from doing.

So, I believe that applying this patch will stop us from being able to publish an artifact to mvn

Erik AssumMarch 16, 2022 at 3:22 PM

Add test?

Details

Assignee

Reporter

Labels

Approval

Vetted

Patch

Code

Priority

Affects versions

Created March 14, 2017 at 8:05 PM
Updated April 16, 2024 at 7:14 PM