James Daugherty created GROOVY-12149:
----------------------------------------

             Summary: Nondeterministic reflection order flows into generated 
bytecode, breaking reproducible builds
                 Key: GROOVY-12149
                 URL: https://issues.apache.org/jira/browse/GROOVY-12149
             Project: Groovy
          Issue Type: Bug
            Reporter: James Daugherty


Follow-up to GROOVY-12146, which fixed nondeterministic ordering of annotation 
members copied from precompiled classes. The same root cause — 
Class.getDeclaredMethods()/getDeclaredFields()/getDeclaredConstructors() 
returning members in an unspecified order that varies between HotSpot runs — 
also affects Java8#configureClassNode, which populates ClassNodes for 
precompiled classes via reflection. The enumeration order is preserved through 
to bytecode generation (e.g. via the LinkedHashMap returned by 
ClassNode#getDeclaredMethodsMap), so two compilations of identical sources on 
the same JDK can still produce byte-different class files.

Two manifestations were observed while verifying the reproducibility of the 
Apache Grails 8.0.0-M3 release artifacts (same sources, same JDK, containerized 
double-build):

1. MOP bridge methods: for classes extending a precompiled Groovy class, 
MopWriter#getSuperMethods iterates the superclass's declared-methods map, so 
the synthetic super$N$… methods are emitted in a different order per build.
2. Woven trait methods: methods copied from a precompiled trait (e.g. GORM's 
DirtyCheckable#trackChanges/syncChangedProperties) are woven into implementing 
classes in enumeration order, reordering the emitted methods and the constant 
pool.

In both cases the bytecode is semantically identical — decompiled sources match 
exactly — only member emission order (and the constant-pool layout that follows 
from it) differs.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to