https://issues.apache.org/bugzilla/show_bug.cgi?id=56166

            Bug ID: 56166
           Summary: Suggestions for exception handling (avoid potential
                    bugs)
           Product: Tomcat 8
           Version: trunk
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: y...@eecg.utoronto.ca

Created attachment 31337
  --> https://issues.apache.org/bugzilla/attachment.cgi?id=31337&action=edit
Patch addressing the mentioned problems.

Reporting a few potential bugs or improvements on some exception handling code.
For what it is worth, attaching a patch to address these problems.

Category 1:
The exception caught is too general:
=========================
Case 1:
Line: 180, File: "org/apache/catalina/core/ApplicationFilterFactory.java"

178: try {
179:     isCometFilter = filterConfig.getFilter() instanceof CometFilter;
180: } catch (Exception e) {
181:     // Note: The try catch is there because getFilter has a lot of
182:     // declared exceptions. However, the filter is allocated much
183:     // earlier
184: }

This try block can throw many exceptions, including:
1. ClassCastException
2. ClassNotFoundException
3. IllegalAccessException
4. InstantiationException
5. ServletException
6. NamingException
7. InvocationTargetException

All of them will be silently swallowed by the catch block. In particular,
earlier in the same function, the same exception is handled in the following
manner:

  try {
       isCometFilter = filterConfig.getFilter() instanceof CometFilter;
  } catch (Exception e) {
       // Note: The try catch is there because getFilter has a lot of
       // declared exceptions. However, the filter is allocated much
       // earlier
       Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
       ExceptionUtils.handleThrowable(t);
  }

Fixed in the patch by handling the exception in the same way as the above.
==========================================
=========================
Case 2:
Line: 234, File: "org/apache/tomcat/util/modeler/BaseModelMBean.java"

232:  try {
233:      response.add(new Attribute(names[i],getAttribute(names[i])));
234:  } catch (Exception e) {
235:      // Not having a particular attribute in the response
236:      // is the indication of a getter problem
237:  }

The try block could throw:
1. AttributeNotFoundException
2. MBeanException
3. ReflectionException

Fixed by ignoring the AttributeNotFoundException and log the other exceptions.
==========================================
=========================
Case 3:
Line: 298, File: "org/apache/catalina/manager/StatusTransformer.java"

294:   try {
295:      Object value = mBeanServer.getAttribute(tpName, "keepAliveCount");
296:      writer.print(" Keeped alive sockets count: ");
297:      writer.print(value);
298:   } catch (Exception e) {
299:      // Ignore
300:   }

This might be problematic since the catch block is too general.

getAttribute() can throw:
1. RuntimeOperationsException
2. MBeanException
3. AttributeNotFoundException
4. InstanceNotFoundException
5. ReflectionException

All of them will be swallowed.
Fixed by only ignoring AttributeNotFoundException.
==========================================
=========================
Case 4:
Line: 215, File: "org/apache/catalina/storeconfig/StoreLoader.java"

206:    try {
207:        File home = new File(getCatalinaBase());
208:        File conf = new File(home, "conf");
209:        File reg = new File(conf, "server-registry.xml");
210:        is = new FileInputStream(reg);
211:        if (log.isInfoEnabled())
212:            log.info("Find registry server-registry.xml at file "
213:                    + reg.getCanonicalPath());
214:        registryResource = reg.toURI().toURL();
215:    } catch (Throwable t) {
216:        // Ignore
217:    }

The catch block might be too general.

The try block could throw:
1. NullPointerException by new File
2. FileNotFoundException by new FileInputStream
3. SecurityException by new FileInputStream and reg.toURL
4. IllegalArgumentException by reg.toURL().toURL
5. MalformedURLException by reg.toURL().toURL

Now with the implementation above, all of them will be ignored.

Fixed by ignoring FileNotFoundException while logging the others.
==========================================
=========================
Case 5:
Line: 307, File: "org/apache/tomcat/util/modeler/ManagedBean.java"

305:     try {
306:         clazz = Class.forName(getClassName());
307:     } catch (Exception e) {
308:     }

Should probably just ignore ClassNotFoundException.

Fixed by ignoring ClassNotFoundException.
==========================================
=========================
Case 6:
Line: 202, File: "org/apache/catalina/storeconfig/StoreLoader.java"

193: try {
194:     String configUrl = getConfigUrl();
195:     if (configUrl != null) {
196:         is = (new URL(configUrl)).openStream();
197:         if (log.isInfoEnabled())
198:             log.info("Find registry server-registry.xml from system
property at url "
199:                     + configUrl);
200:         registryResource = new URL(configUrl);
201:     }
202: } catch (Throwable t) {
203:     // Ignore
204: }

The catch block might be too general.
openStream() above could throw IOException;
new URL() could throw MalformedURLException;

Both will be ignored.

Fixed by logging MalformedURLException and ignoring IOException.
==========================================

Category 2: Exceptions that "should never happen" are now silently ignored. In
those cases, it is better to at least put an error message there, if not
shutting down the execution. Later as code evolves, or something really wrong
occurs, such exception could have occurred and would be silently swallowed.

Currently I fixed them by log these exceptions.
=========================
Case 7:
Line: 867, File: "org/apache/catalina/connector/CoyoteAdapter.java"

865:        try {
866:            Thread.sleep(1000);
867:        } catch (InterruptedException e) {
868:            // Should never happen
869:        }
==========================================
=========================
Case 8:
Line: 706, File: "org/apache/catalina/core/DefaultInstanceManager.java"

703:                    try {
704:                        result = clazz.getDeclaredField(
705:                                entry.getAccessibleObjectName());
706:                    } catch (NoSuchFieldException e) {
707:                        // Should never happen. On that basis don't log
708:                        // it.
709:                    }
==========================================
=========================
Case 9:
Line: 231, File: "org/apache/catalina/core/NamingContextListener.java"

229:    try {
230:        namingContext = new NamingContext(contextEnv, getName());
231:    } catch (NamingException e) {
232:        // Never happens
233:    }
==========================================
=========================
Case 10:
Line: 465, File: "org/apache/catalina/connector/Request.java"

463:        try {
464:            part.delete();
465:        } catch (IOException ignored) {
466:            // ApplicationPart.delete() never throws an IOEx
467:        }
==========================================
=========================
Case 11:
Line: 2333, File: "org/apache/catalina/connector/Request.java"

2331:            try {
2332:                logout();
2333:            } catch (ServletException e) {
2334:                // Should never happen (no code called by logout()
2335:                // throws a ServletException
2336:            }
==========================================
=========================
Case 12:
Line: 481, File: "org/apache/catalina/valves/rewrite/RewriteValve.java"

478:            try {
479:               
request.getConnector().getProtocolHandler().getAdapter().service
480:                (request.getCoyoteRequest(), response.getCoyoteResponse());
481:            } catch (Exception e) {
482:                // This doesn't actually happen in the Catalina adapter
implementation
483:            }
==========================================
=========================
Case 13:
Line: 844, File: "org/apache/tomcat/jdbc/pool/PoolProperties.java"

816:try {
817:    String[] fields = DataSourceFactory.ALL_PROPERTIES;
818:    for (String field: fields) {
818:    for (String field: fields) {
819:        final String[] prefix = new String[] {"get","is"};
820:        for (int j=0; j<prefix.length; j++) {
821:
822:            String name = prefix[j]
823:                    + field.substring(0, 1).toUpperCase(Locale.ENGLISH)
824:                    + field.substring(1);
825:            Method m = null;
826:            try {
827:                m = getClass().getMethod(name);
828:            }catch (NoSuchMethodException nm) {
829:                continue;
830:            }
831:            buf.append(field);
832:            buf.append("=");
833:            if (DataSourceFactory.PROP_PASSWORD.equals(field)) {
834:                buf.append("********");
835:            } else {
836:                buf.append(m.invoke(this, new Object[0]));
837:            }
838:            buf.append("; ");
839:            break;
840:        }
841:    }
842:}catch (Exception x) {
843:    //shouldn't happen
844:    log.debug("toString() call failed", x);
845:}

Fixed by changing verbosity from debug to error.
==========================================
Exceptions that probably should at least be logged:
=========================
Case 14:
  Line: 480, File: "org/apache/juli/ClassLoaderLogManager.java"

478:        try {
479:            is = new FileInputStream(defaultFile);
480:        } catch (IOException e) {
481:            // Critical problem, do something ...
482:        }

Fixed by logging it.
==========================================
=========================
Case 15:
Line: 276, File: "org/apache/catalina/authenticator/SpnegoAuthenticator.java"

274:        try {
275:            lc.logout();
276:        } catch (LoginException e) {
277:            // Ignore
278:        }

This LoginException during logout should not be ignored. Fixed by logging it.
==========================================
=========================
Case 16:
  Line: 269, File: "org/apache/catalina/authenticator/SpnegoAuthenticator.java"

267:        try {
268:            gssContext.dispose();
269:        } catch (GSSException e) {
270:            // Ignore
271:        }

Fixed by logging it.
==========================================
=========================
Case 17:
Line: 348, File: "org/apache/catalina/core/StandardServer.java"

346:        try {
347:            service.start();
348:        } catch (LifecycleException e) {
349:            // Ignore
350:        }

Similar code snippets are logged (LifecycleException thrown from start()):
Such as:
      try {
          connector.start();
      } catch (LifecycleException e) {
          log.error(sm.getString(
                  "standardService.connector.startFailed",
                  connector), e);
      }

      try {
          ex.start();
      } catch (LifecycleException x) {
          log.error("Executor.start", x);
      }

Fixed by logging it.
==========================================
=========================
Case 18:
Line: 150, File: "org/apache/catalina/core/StandardService.java"

148:    try {
149:        this.container.start();
150:    } catch (LifecycleException e) {
151:        // Ignore
152:    }

Fixed by logging it. similar to the case above.
==========================================
=========================
Case 19:
Line 141, File "org/apache/catalina/core/ApplicationFilterFactory.java"
   if (filterConfig == null) {
       // FIXME - log configuration problem
       continue;
   }

Fixed by logging it.
A similar case is at line 173 in the same file.
==========================================

-- 
You are receiving this mail because:
You are the assignee for the bug.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to