jbonofre commented on code in PR #2870:
URL: https://github.com/apache/karaf/pull/2870#discussion_r3975477753


##########
services/interceptor/impl/src/main/java/org/apache/karaf/service/interceptor/impl/runtime/proxy/AsmProxyFactory.java:
##########
@@ -114,19 +113,22 @@ private boolean hasSameSignature(Method a, Method b) {
 
     private void createConstructor(final ClassWriter cw, final String 
proxyClassFileName, final Class<?> classToProxy,
                                    final String classFileName) {
-        Constructor superDefaultCt;
-        String parentClassFileName = classFileName;
-        String descriptor = "()V";
-
-        try {
-            if (classToProxy.isInterface()) {
-                parentClassFileName = Type.getInternalName(Object.class);
-                superDefaultCt = Object.class.getConstructor(null);
-                descriptor = Type.getConstructorDescriptor(superDefaultCt);
+        // the proxy extends the proxied class, or Object when proxying an 
interface; either way
+        // the super constructor it invokes is the no-arg one
+        final String parentClassFileName;
+        if (classToProxy.isInterface()) {
+            parentClassFileName = Type.getInternalName(Object.class);
+        } else {
+            parentClassFileName = classFileName;
+            try {
+                classToProxy.getDeclaredConstructor();

Review Comment:
   `getDeclaredConstructor()` also matches a private or package-private no-arg 
constructor, but the `INVOKESPECIAL` we generate below can't call either one. 
So far those classes the check passes and we still fail late, which is exactly 
what this guard is meant to prevent.
   
   Package-private doesn't help here either: the proxy is define by a fresh 
`ProxyFactory.ProxyClassLoader`, so it ends up in a different runtime package 
than the proxied class even though the package name matches.
   
   `protected` does work (super-constructor access from a direct subclass is 
legal across packages), so the condition we actually want is "public or 
protected", not "declared". Concrete case that regresses today: a service impl 
registered via `bundleContext.registerService(...)` with a package-private 
no-arg constructor (a pretty normal idiom) gets an 
`IllegalStateException`/`IllegalAccessError` instead of the clear 
`IllegalArgumentException`.
   
   The simplest fix is `getConstructor()`, which is public-only and also avoids 
needing `accessDeclaredMembers` under a security manager:
   
   ```java
   classToProxy.getConstructor();
   ```
   
   If you want to keep `protected` proxyable, keep `getDeclaredConstructor()` 
and reject on the modifiers:
   
   
   ```java
   final Constructor<?> superCt = classToProxy.getDeclaredConstructor();
   final int modifiers = superCt.getModifiers();
   if (!Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers)) {
     throw new IllegalArgumentException("Cannot proxy " + 
classToProxy.getName() + ", its no-arg constructor is not accessible from the 
generated proxy");
   }
   ```
   
   Maybe worth a test alongside `proxyWithoutNoArgConstructor` covering a class 
whose only no-arg constructor is package-private.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to