From 25f24ca4de34d55d81f1087864d01d9a4a7bd032 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Fri, 12 Dec 2025 14:38:53 +0100 Subject: [PATCH 1/2] LDEV-5862 fix Bad access to protected data in invokevirtual https://luceeserver.atlassian.net/browse/LDEV-5862 --- .../dynamic/meta/dynamic/ClazzDynamic.java | 20 ++++++++- test/tickets/LDEV5862.cfc | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 test/tickets/LDEV5862.cfc diff --git a/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java b/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java index bb9c4cbe22..6b507726cf 100644 --- a/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java +++ b/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java @@ -493,7 +493,15 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str Type tmpType = tmpClass != null ? Type.getType(tmpClass) : null; Type rtnType = rtnClass != null ? Type.getType(rtnClass) : null; - if (Clazz.compareAccess(fmParent, fmCurrent) >= 0) fmCurrent.setDeclaringProviderClassWithSameAccess(tmpClass, tmpType, rtnClass, rtnType); + // LDEV-5862: For declaringProviderClassWithSameAccess, use the parent's WithSameAccess version + // to avoid propagating a class where the method has different (e.g., protected) access + if (Clazz.compareAccess(fmParent, fmCurrent) >= 0) { + Class sameAccessClass = fmParent.getDeclaringProviderClassWithSameAccess(true); + Class sameAccessRtnClass = (fmParent instanceof Method) ? fmParent.getDeclaringProviderRtnClassWithSameAccess(true) : null; + Type sameAccessType = sameAccessClass != null ? Type.getType(sameAccessClass) : null; + Type sameAccessRtnType = sameAccessRtnClass != null ? Type.getType(sameAccessRtnClass) : null; + fmCurrent.setDeclaringProviderClassWithSameAccess(sameAccessClass, sameAccessType, sameAccessRtnClass, sameAccessRtnType); + } fmCurrent.setDeclaringProviderClass(tmpClass, tmpType, rtnClass, rtnType); /* * if (name.equals("nextElement")) { print.e(fm.getDeclaringProviderClassName()); @@ -640,7 +648,15 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str Type tmpType = tmpClass != null ? Type.getType(tmpClass) : null; Type rtnType = rtnClass != null ? Type.getType(rtnClass) : null; - if (Clazz.compareAccess(fmParent, fmCurrent) >= 0) fmCurrent.setDeclaringProviderClassWithSameAccess(tmpClass, tmpType, rtnClass, rtnType); + // LDEV-5862: For declaringProviderClassWithSameAccess, use the parent's WithSameAccess version + // to avoid propagating a class where the method has different (e.g., protected) access + if (Clazz.compareAccess(fmParent, fmCurrent) >= 0) { + Class sameAccessClass = fmParent.getDeclaringProviderClassWithSameAccess(true); + Class sameAccessRtnClass = (fmParent instanceof Method) ? fmParent.getDeclaringProviderRtnClassWithSameAccess(true) : null; + Type sameAccessType = sameAccessClass != null ? Type.getType(sameAccessClass) : null; + Type sameAccessRtnType = sameAccessRtnClass != null ? Type.getType(sameAccessRtnClass) : null; + fmCurrent.setDeclaringProviderClassWithSameAccess(sameAccessClass, sameAccessType, sameAccessRtnClass, sameAccessRtnType); + } fmCurrent.setDeclaringProviderClass(tmpClass, tmpType, rtnClass, rtnType); /* diff --git a/test/tickets/LDEV5862.cfc b/test/tickets/LDEV5862.cfc new file mode 100644 index 0000000000..1697d7d0ad --- /dev/null +++ b/test/tickets/LDEV5862.cfc @@ -0,0 +1,42 @@ +component extends="org.lucee.cfml.test.LuceeTestCase" { + + function run( testResults, testBox ) { + describe( title='LDEV-5862 Bad access to protected data in invokevirtual', body=function() { + + it( title='clone() on HashMap', body=function() { + var map = createObject( "java", "java.util.HashMap" ).init(); + map.put( "key", "value" ); + var cloned = map.clone(); + expect( cloned.get( "key" ) ).toBe( "value" ); + }); + + it( title='clone() on LinkedHashMap', body=function() { + var map = createObject( "java", "java.util.LinkedHashMap" ).init(); + map.put( "key", "value" ); + var cloned = map.clone(); + expect( cloned.get( "key" ) ).toBe( "value" ); + }); + + it( title='clone() on ArrayList', body=function() { + var list = createObject( "java", "java.util.ArrayList" ).init(); + list.add( "item" ); + var cloned = list.clone(); + expect( cloned.get( 0 ) ).toBe( "item" ); + }); + + it( title='clone() on SimpleDateFormat', body=function() { + var sdf = createObject( "java", "java.text.SimpleDateFormat" ).init( "yyyy-MM-dd" ); + var cloned = sdf.clone(); + expect( cloned.toPattern() ).toBe( "yyyy-MM-dd" ); + }); + + it( title='clone() on Date', body=function() { + var d = createObject( "java", "java.util.Date" ).init(); + var cloned = d.clone(); + expect( cloned.getTime() ).toBe( d.getTime() ); + }); + + }); + } + +} From 49780537193a35ea9faeaaa2f0690b971fb830aa Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Fri, 12 Dec 2025 15:07:09 +0100 Subject: [PATCH 2/2] LDEV-5862 fix typo --- .../lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java b/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java index 6b507726cf..848a92764d 100644 --- a/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java +++ b/core/src/main/java/lucee/transformer/dynamic/meta/dynamic/ClazzDynamic.java @@ -235,7 +235,7 @@ public Method getMethod(String methodName, Class[] arguments, boolean nameCaseSe outer: for (FunctionMember fm: methods) { if (/* fm.isPublic() && */ (nameCaseSensitive ? methodName.equals(fm.getName()) : methodName.equalsIgnoreCase(fm.getName()))) { Type[] args = ((FunctionMemberDynamic) fm).getArgumentTypes(); - if (types.length == types.length) { + if (types.length == args.length) { for (int i = 0; i < args.length; i++) { if (!types[i].equals(args[i])) continue outer; }