[
https://issues.apache.org/jira/browse/GROOVY-12680?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18137477#comment-18137477
]
ASF GitHub Bot commented on GROOVY-12680:
-----------------------------------------
codeconsole opened a new pull request, #3201:
URL: https://github.com/apache/groovy/pull/3201
`ClosureMetaClass.getProperty`, `setProperty` and `getMetaProperty` delegate
to a `MetaClassImpl` of `groovy.lang.Closure` itself, which indexes Closure's
own private fields and properties. A closure's metaclass therefore exposed and
overwrote them:
```groovy
def c = { -> 1 }
c.metaClass.getProperty(c, 'bcw') // null instead of
MissingPropertyException
c.metaClass.getProperty(c, 'serialVersionUID') // 4368710879820278874
c.metaClass.getMetaProperty('thisType') // a MetaBeanProperty
c.metaClass.setProperty(c, 'thisType', String) // overwrites the private
field
```
The same path is reached by property access on a closure with the `TO_SELF`
resolve strategy (`c.thisType = String`). Overwriting `thisType` breaks a
closure's access to private fields of its enclosing class when the owner is a
subclass instance. The metaclass of any other subclass reports a superclass's
private fields as missing. Seen in 5.0.8 and 6.0.0 (and the read side in
4.0.33).
`getProperty` and `setProperty` now take the missing-property path for a
name that resolves to a private member of Closure, including the capitalised
form `MetaClassImpl` decapitalises (GROOVY-9618). `getMetaProperty`, and so
`hasProperty`, return null for such names. A sender of `Closure` keeps access,
as a declaring class does for the metaclass of a subclass. Public properties
(`delegate`, `owner`, `thisObject`, `resolveStrategy`, `directive`,
`maximumNumberOfParameters`, `parameterTypes`, `metaClass`, `class`), the
public constants, and property resolution through owner and delegate are
unchanged. Attribute access (`c.@delegate`, `c.@owner`) is left as it is, since
existing code relies on it. This complements #3196 (GROOVY-12675), which
removed the same members from `ClosureMetaClass.getProperties`; the two merge
cleanly.
## Tests
`ClosureTest.testMetaClassDoesNotExposePrivateMembersOfClosure`,
`testMetaClassCannotOverwritePrivateMembersOfClosure` and
`testToSelfDoesNotResolvePrivateMembersOfClosure` fail without the change.
`testMetaClassStillExposesPublicMembersOfClosure` and
`testOwnerAndDelegatePropertiesNamedLikePrivateMembersOfClosure` cover the
public members and owner/delegate resolution. `groovy.lang.*`,
`org.codehaus.groovy.runtime.*`, `groovy.*Closure*`, `bugs.*`,
`gls.invocation.*`, `groovy.transform.stc.*`,
`org.codehaus.groovy.classgen.asm.sc.*` and `groovy.*MetaClass*` pass. The
Checkstyle and CodeNarc gates pass.
> A closure's metaclass reads and overwrites private fields of
> groovy.lang.Closure
> --------------------------------------------------------------------------------
>
> Key: GROOVY-12680
> URL: https://issues.apache.org/jira/browse/GROOVY-12680
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.0.33, 5.0.8, 7.0.0-alpha-1, 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> {code:groovy}
> def c = { -> 1 }
> assert c.metaClass.getProperty(c, 'bcw') == null
> assert c.metaClass.getProperty(c, 'serialVersionUID') == 4368710879820278874L
> assert c.metaClass.getMetaProperty('thisType') != null
> c.metaClass.setProperty(c, 'thisType', String) // overwrites Closure's
> private field
> class C {
> private secret = 'C'
> def read() {
> Closure c = { -> secret }
> c.metaClass.setProperty(c, 'thisType', Object)
> c()
> }
> }
> class D extends C {}
> new D().read()
> {code}
> *Actual:* getProperty returns the values of the private fields bcw,
> serialVersionUID, thisType, mopPerturbed and PROPERTY_GETTERS of Closure,
> also under capitalised names such as ThisType. getMetaProperty and
> hasProperty return them. setProperty overwrites thisType and mopPerturbed.
> After thisType is overwritten, the last line fails with "No such property:
> secret for class: D". With the TO_SELF resolve strategy, plain {{c.thisType =
> String}} does the same.
> *Expected:* MissingPropertyException from getProperty and setProperty, and
> null from getMetaProperty and hasProperty, as the metaclass of any other
> subclass gives for its superclass's private fields.
> ClosureMetaClass delegates property access to a MetaClassImpl of Closure
> itself, which indexes Closure's own private members. A generated closure
> class does not inherit them. Related: GROOVY-12675 (the same members in
> getProperties).
> Verified: 5.0.8, 6.0.0 and master (including the setProperty overwrite of
> thisType); 4.0.33 read side only (bcw and serialVersionUID).
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)