Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Exception Handling Bug Hazards on Android

Exception Handling Bug Hazards on Android

Presentation I gave at MSR 2015.

Georgios Gousios

May 17, 2015
Tweet

More Decks by Georgios Gousios

Other Decks in Technology

Transcript

  1. The Java Exception Hierarchy Throwable Error Exception Checked Exceptions IOException

      SQLException   … RuntimeException NullPointerException   IndexOutOfBoundsException   …
  2. The Java Exception Hierarchy Throwable Error Exception Checked Exceptions IOException

      SQLException   … RuntimeException NullPointerException   IndexOutOfBoundsException   … must be caught must be declared recoverable errors should be caught could be declared recoverable errors should not be caught could be declared irrecoverable errors
  3. Exception Propagation javax.servlet.ServletException:  Something  bad  happened        

     at  com.example.myproject.OpenSessionInViewFilter.doFilter          at  org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter          at  com.example.myproject.ExceptionHandlerFilter.doFilter          ...  22  more   Caused  by:  com.example.myproject.MyProjectServletException          at  com.example.myproject.MyServlet.doPost          at  javax.servlet.http.HttpServlet.service          at  javax.servlet.http.HttpServlet.service          at  org.mortbay.jetty.servlet.ServletHolder.handle          at  org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter          at  com.example.myproject.OpenSessionInViewFilter.doFilter          ...  27  more   Caused  by:  org.hibernate.exception.ConstraintViolationException:  could  not   insert:  [com.example.myproject.MyEntity]          at  org.hibernate.exception.SQLStateConverter.convert          at  org.hibernate.exception.JDBCExceptionHelper.convert          at  org.hibernate.id.insert.AbstractSelectingDelegate.performInsert          at  org.hibernate.persister.entity.AbstractEntityPersister.insert          ...  32  more   Caused  by:  java.sql.SQLException:  Violation  of  unique  constraint   MY_ENTITY_UK_1:  duplicate  value(s)  for  column(s)  MY_COLUMN  in  statement   [...]          at  org.hsqldb.jdbc.Util.throwError          at  org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate          at  com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate          at  org.hibernate.id.insert.AbstractSelectingDelegate.performInsert          ...  54  more Root cause Wrappings Thrown exception
  4. Exception Propagation javax.servlet.ServletException:  Something  bad  happened        

     at  com.example.myproject.OpenSessionInViewFilter.doFilter          at  org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter          at  com.example.myproject.ExceptionHandlerFilter.doFilter          ...  22  more   Caused  by:  com.example.myproject.MyProjectServletException          at  com.example.myproject.MyServlet.doPost          at  javax.servlet.http.HttpServlet.service          at  javax.servlet.http.HttpServlet.service          at  org.mortbay.jetty.servlet.ServletHolder.handle          at  org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter          at  com.example.myproject.OpenSessionInViewFilter.doFilter          ...  27  more   Caused  by:  org.hibernate.exception.ConstraintViolationException:  could  not   insert:  [com.example.myproject.MyEntity]          at  org.hibernate.exception.SQLStateConverter.convert          at  org.hibernate.exception.JDBCExceptionHelper.convert          at  org.hibernate.id.insert.AbstractSelectingDelegate.performInsert          at  org.hibernate.persister.entity.AbstractEntityPersister.insert          ...  32  more   Caused  by:  java.sql.SQLException:  Violation  of  unique  constraint   MY_ENTITY_UK_1:  duplicate  value(s)  for  column(s)  MY_COLUMN  in  statement   [...]          at  org.hsqldb.jdbc.Util.throwError          at  org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate          at  com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate          at  org.hibernate.id.insert.AbstractSelectingDelegate.performInsert          ...  54  more Root cause Wrappings Thrown exception signalers
  5. Data extraction 788 repositories 183 with stack traces 157 after

    manual filtering 127,456 issues 1,963 with stack traces  2,542 repositories 589 with stack traces 482 after manual filtering 31,592 issues 4,042 with stack traces Search GHTorrent and Google Code for android 6,005 issues with stack traces from 539 projects
  6. Project post-processing • Statically analysed byte code it to identify

    use of external libraries • Analysed source code for custom exception types — exception hierarchies For each of the 539 extracted projects
  7. Exception post-processing • Extracted the stack trace using heuristics •

    Checked the source code for documentation of thrown non-checked exceptions For each of the 6,005 issues with stack traces
  8. StackTrace Dataset • project • exception location • exception type

    (Error, Runtime, checked) • exception signaler (os, libcore, lib, app)
  9. Top exceptions Occurrences (%) Projects (%) Most Common Source NullPointer

    28 52 App IllegalState 5 19 OS IllegalArgument 6 22 OS RuntimeException 5 19 OS OutOfMemory 4 12 OS Most apps crash due to programmer errors
  10. Most faulty areas Occurrences (%) Program logic 52 Resource handling

    23 Security 4 Concurrency 3 Backward compatibility 4 Programming logic and resource handling account for 75% of all exceptions
  11. Types and Origins OS Libcore Lib App Total (%) Runtime

    21 1 11 29 64 Checked 3 0 2 4 11 Error 4 5 9 5 23 Throwable 0 0 0 0 0.06 Total (%) 30 7 23 40 100 Two thirds of the reported crashes are runtime exceptions.
  12. Inappropriate wrappings Runtime exception wrapping an Error void  foo()  {

        try  {       //  various  operations     }  catch  (AppSpecificException  e)  {       //  deal  with  app  exception     }  catch  (Throwable  t)  {       throw  new  RuntimeException("Error  thrown")     }   }   OutOfMemory caught Typical occurence • “Catch all” exception blocks • Also in the core library! Bad because Wraps irrecoverable errors in errors that can be recovered from leading to inconsistent state
  13. Inappropriate wrappings void  foo()  throws  IOException  {     try

     {       throw  new  IOException("Error");     }  catch  (Exception  e)  {       throw  new  RuntimeException("Error");     }   } Runtime exception wrapping a checked exception No need to throw   RunTimeException Typical occurence Methods that “swallow” exceptions to avoid changing the signature Bad because Recoverable conditions are hidden and not treated at the place they occurred Occurrences 50% of the inappropriate wrappings
  14. Inappropriate wrappings Checked exception wrapping an Error void  foo()  throws

     AppSpecificException  {     try  {       //  JNI  invocation     }  catch  (OutOfMemoryError  e)  {       throw  new  AppSpecificException("Not  enough  memory");     }   }   Typical occurence Methods wrapping Errors thrown in native code Bad because Masks of an irrecoverable condition
  15. Inappropriate wrappings Error wrapping a checked/runtime exception static  {  

      //  various  operations     throw  new  AppSpecificException("Error");   }   Typical occurence static initializers Bad because Raises the severity of bening exceptions and may lead to non-handling of problems that may have been recoverable ExceptionInInitializerError thrown
  16. Pimp my exceptions extreme edition SUMMARY: android.view.InflateException - java.lang.RuntimeException java.lang.reflect.InvocationTargetException

    - java.lang.Exception android.content.res.Resources$NotFoundException - java.lang.RuntimeException ACRA ( 2666): android.view.InflateException: Binary XML file line g20: Error inflating class android.widget.DatePicker
 ACRA ( 2666): at android.view.LayoutInflater.createView(LayoutInflater.java:518)
 ACRA ( 2666): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
 ... ACRA ( 2666): Caused by: java.lang.reflect.InvocationTargetException
 ACRA ( 2666): at java.lang.reflect.Constructor.constructNative(Native Method)
 ACRA ( 2666): at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
 ACRA ( 2666): at android.view.LayoutInflater.createView(LayoutInflater.java:505)
 ...
 ACRA ( 2666): Caused by: android.view.InflateException: Binary XML file line g32: Error inflating class android.widget.NumberPicker
 ACRA ( 2666): at android.view.LayoutInflater.createView(LayoutInflater.java:518)
 ACRA ( 2666): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
 ACRA ( 2666): at android.widget.DatePicker.<init>(DatePicker.java:94)
 ... ACRA ( 2666): Caused by: java.lang.reflect.InvocationTargetException
 ACRA ( 2666): at java.lang.reflect.Constructor.constructNative(Native Method)
 ACRA ( 2666): at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
 ACRA ( 2666): at android.view.LayoutInflater.createView(LayoutInflater.java:505)
 ... ACRA ( 2666): Caused by: android.view.InflateException: Binary XML file line g27: Error inflating class <unknown>
 ACRA ( 2666): at android.view.LayoutInflater.createView(LayoutInflater.java:518)
 ACRA ( 2666): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
 ... ACRA ( 2666): Caused by: java.lang.reflect.InvocationTargetException
 ACRA ( 2666): at java.lang.reflect.Constructor.constructNative(Native Method)
 ACRA ( 2666): at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
 ... ACRA ( 2666): Caused by: android.content.res.Resources$NotFoundException: Resource is not a ColorStateList (color or path): TypedValue{t=0x2 d=0x1010350 a=2}
 ACRA ( 2666): at android.content.res.Resources.loadColorStateList(Resources.java:1804)
 ACRA ( 2666): at android.content.res.TypedArray.getColorStateList(TypedArray.java:342)
 ACRA ( 2666): at android.widget.TextView.<init>(TextView.java:659)
 ACRA ( 2666): at android.widget.EditText.<init>(EditText.java:58)
 ACRA ( 2666): at android.widget.EditText.<init>(EditText.java:54)
 ACRA ( 2666)
  17. Exception handling best practices • Use checked exceptions to represent

    recoverable conditions • Do not catch Errors • Only throw exceptions that precisely define recoverable conditions • All (checked and unchecked) exceptions thrown in libraries should be documented
  18. Prevent uncaught exceptions • Document all exceptions that can be

    thrown with @throws • Use top-down exception handling
  19. Avoiding nulls • Java < 8: Be careful, use static

    analysis tools • Java >= 8 • Use @Nullable • Encode nullability or possibility of exceptions in types • Optional:  Either a result or null (in stdlib)   • Try: Either an exception or a result (not in stdlib)
  20. public  Integer  getResult(Int  x)  {     if  (x  <

     0)  return  null;     return  x;   }   public  Optional<Integer>  getResult(Integer  x)  {     if  (x  <  0)  return  Optional.of(null);     return  Optional.of(x);   }   Using Optional to handle nulls public  Integer  processResult(Integer  x)  {     Integer  y  =  getResult(x);     if  (y  ==  null)  {       return  null;     }     return  y  +  1;   }   public  Optional<Integer>  processResultOpt(Integer  x)  {          return  getResultOpt(x).                        flatMap(y  -­‐>  Optional.of(y  +  1));   }   Java < 8 Java >= 8
  21. What can researchers do? • Static analysis tools to help

    developers: • identify potentially thrown exceptions • avoid inappropriate wrappings • Abolish nulls and checked exceptions from new PLs