Bug 35482 - regression: apache-tomcat-5.5.26 throws NPE with 0.97
Summary: regression: apache-tomcat-5.5.26 throws NPE with 0.97
Alias: None
Product: classpath
Classification: Unclassified
Component: classpath (show other bugs)
Version: 0.97
: P3 normal
Target Milestone: 0.98
Assignee: Andrew John Hughes
Depends on:
Blocks: 36145
  Show dependency treegraph
Reported: 2008-03-06 15:04 UTC by Christian Thalinger
Modified: 2008-05-06 11:23 UTC (History)
1 user (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2008-03-06 16:32:29

Minimal test case (212 bytes, text/x-java)
2008-05-06 01:53 UTC, Andrew John Hughes
Fix (571 bytes, patch)
2008-05-06 02:43 UTC, Andrew John Hughes
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
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))
        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));
            char ch = value[x];
            // Hardcoded special case.
            newStr[x - offset] = Character.toLowerCase(ch);
            //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]
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.

Comment 7 Christian Thalinger 2008-05-06 11:23:58 UTC
Yes, the bug is fixed.  Thanks.