Bug 35482

Summary: regression: apache-tomcat-5.5.26 throws NPE with 0.97
Product: classpath Reporter: Christian Thalinger <twisti>
Component: classpathAssignee: Andrew John Hughes <gnu_andrew>
Status: RESOLVED FIXED    
Severity: normal CC: bug-classpath
Priority: P3    
Version: 0.97   
Target Milestone: 0.98   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2008-03-06 16:32:29
Bug Depends on:    
Bug Blocks: 36145    
Attachments: Minimal test case
Fix

Description Christian Thalinger 2008-03-06 15:04:22 UTC
This works with 0.96.1:

Mar 6, 2008 4:02:21 PM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /home/cthalinger/cacao/cacao/src/cacao/.libs
Mar 6, 2008 4:02:22 PM org.apache.commons.modeler.Registry registerComponent
SEVERE: Error registering Catalina:type=Server
javax.management.MBeanException: Cannot instantiate ModelMBean of class org.apache.commons.modeler.BaseModelMBean
   at org.apache.commons.modeler.ManagedBean.createMBean(ManagedBean.java:385)
   at org.apache.commons.modeler.Registry.registerComponent(Registry.java:835)
   at org.apache.catalina.core.StandardServer.initialize(StandardServer.java:763)
   at org.apache.catalina.startup.Catalina.load(Catalina.java:504)
   at org.apache.catalina.startup.Catalina.load(Catalina.java:524)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:384)
   at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:267)
   at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:432)
Caused by: java.lang.NullPointerException
   at javax.management.modelmbean.ModelMBeanInfoSupport.isDescriptorValid(ModelMBeanInfoSupport.java:665)
   at javax.management.modelmbean.ModelMBeanInfoSupport.checkAndSetDescriptor(ModelMBeanInfoSupport.java:624)
   at javax.management.modelmbean.ModelMBeanInfoSupport.<init>(ModelMBeanInfoSupport.java:132)
   at javax.management.modelmbean.ModelMBeanInfoSupport.clone(ModelMBeanInfoSupport.java:137)
   at org.apache.commons.modeler.BaseModelMBean.setModelMBeanInfo(BaseModelMBean.java:806)
   at org.apache.commons.modeler.BaseModelMBean.<init>(BaseModelMBean.java:117)
   at java.lang.reflect.Constructor.constructNative(Native Method)
   at java.lang.reflect.Constructor.newInstance(Constructor.java:344)
   at java.lang.Class.newInstance(Class.java:1154)
   at org.apache.commons.modeler.ManagedBean.createMBean(ManagedBean.java:378)
   ...8 more
Comment 1 Andrew John Hughes 2008-03-06 16:32:28 UTC
I'll investigate this further.
Comment 2 Andrew John Hughes 2008-05-05 23:19:26 UTC
I've managed to duplicate this here.  Note that it needs the JDK 1.4 compatibility package to obtain this error.  Without this, it complains about a missing JMX class.  In the long term, we should aim to run without the compatibility package too.

The error seems to be related to the expected cloning behaviour.
Comment 3 Andrew John Hughes 2008-05-06 01:52:27 UTC
After hours of chasing, I've found it's nothing to do with JMX at all or our implementation.  The bug arises from Ian's change to String.toLowerCase(), which now eats characters when they begin with lowercase letters.  Thus, the lowercase variants of the descriptor keys become broken.

       int i = count;
        int x = offset - 1;
        while (--i >= 0)
          {
            char ch = value[++x];
            if (ch != Character.toLowerCase(ch))
              break;
          }
        if (i < 0)
          return this;

        // Now we perform the conversion. Fortunately, there are no
        // multi-character lowercase expansions in Unicode 3.0.0.
        //char[] newStr = (char[]) value.clone();
        char[] newStr = new char[count];
        VMSystem.arraycopy(value, offset, newStr, 0, count - (x - offset));
        do
          {
            char ch = value[x];
            // Hardcoded special case.
            newStr[x - offset] = Character.toLowerCase(ch);
            x++;
            //newStr[x++] = Character.toLowerCase(ch);
          }
        while (--i >= 0);
        // Package constructor avoids an array copy.
        return new String(newStr, 0, count, true);
        //return new String(newStr, offset, count, true);

The lowerCase algorithm above calculates a value of x which will differ depending on how many lowercase letters are at the start of the string.
The upperCase algorithm works differently, taking account of larger lowercase letters and doesn't optimise by only uppercasing non-uppercased starting letters.  Thus it doesn't seem to suffer from this bug.

A string which starts with an uppercase letter will lowercase fine, because the offset, x, will be 0 (the while loop immediately fails, incrementing x just once).  However a string like 'descriptorType' (which is the lookup that fails in this bug) becomes 'desctype' instead.

I'll attach a testcase that demonstrates this.
Comment 4 Andrew John Hughes 2008-05-06 01:53:37 UTC
Created attachment 15583 [details]
Minimal test case
Comment 5 Andrew John Hughes 2008-05-06 02:43:02 UTC
Created attachment 15584 [details]
Fix
Comment 6 Andrew John Hughes 2008-05-06 02:43:51 UTC
CVSROOT:        /sources/classpath
Module name:    classpath
Changes by:     Andrew John Hughes <gnu_andrew> 08/05/06 02:42:05

Modified files:
       .              : ChangeLog
       java/lang      : String.java

Log message:
       2008-05-06  Andrew John Hughes  <gnu_andrew@member.fsf.org>

               PR classpath/35482
               * java/lang/String.java:
               (toLowerCase()): Fix calculation of number
               of characters to copy.
               (toLowerCaseTurkish()): Likewise.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.9595&r2=1.9596
http://cvs.savannah.gnu.org/viewcvs/classpath/java/lang/String.java?cvsroot=classpath&r1=1.89&r2=1.90
Comment 7 Christian Thalinger 2008-05-06 11:23:58 UTC
Yes, the bug is fixed.  Thanks.