A class loading sensitive approach to detection of runtime type errors in component-based Java programs

https://doi.org/10.1016/j.infsof.2014.04.005Get rights and content

Highlights

  • A novel approach to detect type errors related to custom class loaders in Java.

  • A static approach to predict runtime errors by referencing class loader information.

  • A general method based on popular points-to analysis problem setting.

Abstract

Context

The employment of class loaders in component-based Java programs may introduce runtime type errors, which may happen at any statement related to class loading, and may be wrapped into various types of exceptions raised by JVM. Traditional static analysis approaches are inefficient to detect them.

Objective

Our previous work proposed a semi-static detection work based on points-to analysis to detect such runtime type errors. In this paper, we extend previous work by referencing the information obtained from class loading to detect runtime type errors in component-based Java programs, without the need to running them.

Method

Our approach extends the typical points-to analysis by gathering the behavior information of Java class loaders and figuring out the defining class loader of the allocation sites. By doing that, we obtain the runtime types of objects a reference variable may point to, and make use of such information to facilitate runtime type error detecting.

Results

Results on four case studies show that our approach is feasible, can effectively detect runtime errors missed by traditional static checking methods, and performs acceptably in both false negative test and scalability test.

Introduction

With the increasing adoption of component-based software development (CBSD) as a mainstream approach of software engineering [23], Java programs have been the most prevalent software in Web world, such as Servlet/JSP, EJBs, OSGi1-based programs, and so on. Error detections of Java programs are invaluable for their comprehensive application, while type checking is one of such detection mechanisms. Type checking for Java can be done statically or dynamically. Type-related defects missed by Java compilers and captured by JVM’s runtime type checking are conventionally named runtime type errors [12]. Such errors are very common in Java program, such those caused by unsafe casts [18].

Runtime type errors are usually apt to occur in component-based Java programs for the following reasons. First, in component-based Java programs, component containers, like web application servers and OSGi frameworks, different custom class loaders are often allowed, and classes are defined at runtime [14]. For example, in OSGi-based programs, classes in each bundle (OSGi-compliant component) are defined by the bundle’s class loader [21]. Nevertheless, in Java web systems, classes of the web application and those of its hosting application server are also defined by different class loaders. The inconsistent of class loaders in classes loading contributes in the majority of runtime errors in Java. In this paper, we will focus on these scenarios and give our solution to detect this kind of runtime errors.

Second, it is very common that in a component-based Java program, components may contain same-named classes.2 For example, JOnAS 5.2.0, an OSGi-based Java EE application server, has 77 bundles, which are active in execution, and there are 105 distinct class names3 of which each is owned by more than one class. Same-named classes usually result from the extensive use of application frameworks and third-party libraries. The instance of a class or its subclass created in one component may propagate to other components that contain a class of the same name. Since same-named classes in different components are defined by different class loaders and thus represent different runtime types [12], the propagation may cause some reference variables to point to objects with wrong runtime types. Compilers, which focus more on static types, cannot detect this kind of. In realities, such errors are mostly found by JVM as runtime errors and handled as exceptions, such as ClassCastException and ArrayStoreException.

Eliminating same-named classes will prevent this kind of errors. A brute force solution is to delete those classes until there is only one class left for each class name. However, this approach may have undesired results. Same-named classes may have separate implementations, because they may come from different third-party libraries, and each of them may have a set of static fields, which take effect when loaded. If only one such class is permitted to be loaded, the semantics of the program may be damaged. Avoiding such errors by coding standards or best practices, for example, prohibiting the instances of same-named classes (or their subclasses) to be propagated beyond their own components, is also impractical. First, which classes will become the same-named classes are usually not known until those components are integrated together, especially when many third-party libraries are integrated at the same time. Second, components may come from various vendors and constraint these vendors comply with the same coding standard is also ineffective. Third, some third-party components are casually migrated from legacy code, such as the official OSGi-compliant log4j 1.2.16, which imports and exports [21] many Java packages and the clarity of component interface is sacrificed. Exceptions caused by runtime type errors may occur at almost every possible position of the program, rendering writing exception handling code to recover from these errors can be very hard [18].

Statically detecting runtime type errors will help programmers find out faults at early stage and enables corresponding remedies. There have been some works using static analysis to detect runtime type errors caused by unsafe casts [16], [17], [24], [30]. However, these works do not consider runtime type discrepancies caused by class loaders and thus cannot detect runtime type errors effectively.

In our previous work [33], we propose a class loading sensitive approach based on points-to analysis [9] to detect runtime type errors in component-based Java programs. We invoke class loaders provided by component containers to get their behavior and figure out the defining class loader of the allocation sites [15]. Then the runtime types of objects a reference variable may point to can be obtained. In this paper, we extend our previous work to acquire the runtime types of the reference variables from the behavior information of class loaders. Based on these runtime types, we check every program statement where JVM may raise exception [3] for runtime type error, and assess the possibility that related variables pointing to wrong-typed allocation sites. Besides, we also give the formal descriptive pseudo code to integrate our detection progress based on both points-to analysis and class loader information.

We implement our method as a prototype tool and conduct four case studies to show the feasibility and effectiveness of our method and its performance in false negative test and scalability test.

Contribution of this work is at least three-folded. First, we give a solution to detect runtime type error related to class loaders. Second, we use the de facto dynamic module system OSGi [11] as the framework to implement our open-source prototype tool. Third, we conduct a case study to validate our method and show it promising.

The remainder of this paper is organized as follows. Section 2 gives preliminaries by stating the problem of runtime type errors in component-based Java programs. Section 3 gives a short motivation and presents our approach in Section 4. Section 5 talks about the implementation of our prototype tool as an evaluation, presents results of case studies, and talks about threats to validity of the results observed, followed by Section 6, which introduces related work. Section 7 concludes the paper and gives future work.

Section snippets

Preliminaries

Before we give the problem and elaborate on our solution, we first introduce the class loading mechanism and OSGi framework as preliminaries.

Motivation

In this section, we use an example to motivate our work and show that class loader can be statically referenced as clues to detect runtime type errors.

Our detection process

Previous points-to analysis approaches solely consider static types and cannot effectively detect runtime type errors caused by the “dynamic part” of runtime types. To detect this kind of errors, we also need to consider defining class loaders in points-to analysis.

Evaluation

To validate the feasibility of our method, we implement a prototype tool called Clap,5 which is specific to OSGi-based programs now. This tool is based on Java static analysis framework Soot and OSGi framework Felix.6 We add a defining class loader field to Java class’s representation class “soot.SootClass” and Java reference type’s representation class “soot.RefType”, and change

Related work

Static analysis is used for detecting unsafe casts in Java programs [16], [17], [24], [30], and unsafe casts are a source of runtime type errors. The proposed approaches use either points-to analysis or constraint-based analysis. They only consider static types and cannot detect runtime type errors caused by class loaders.

Points-to analysis is used to statically estimate which objects a reference variable may point to during execution of the program under analysis. Spark [15] is an early but

Conclusion and future work

In this paper we propose an approach using points-to analysis and dynamically gathered behavior information of Java class loaders to statically detect runtime type errors in component-based Java programs, and implement a prototype tool for OSGi. Case studies show our method feasible, effective, and scalable.

In the future, we will first use larger and more complicated experiment to evaluate our method. Further, we plan to make Clap couples loosely with component container such as Felix, using

Acknowledgments

This work is supported by the National Key Basic Research Program of China (Grant No. 2014CB340701) and the National Natural Science Foundation of China (Grant No. 61173004, 61379045).

References (34)

  • L.O. Andersen, Program Analysis and Specialization for the C Programming Language, PhD, Computer Science Department,...
  • B. Bellamy, P. Avgustinov, O. d. Moor, D. Sereni, Efficient local type inference, in: Proceedings of the Proceedings of...
  • M. Braux, J. Noyé, Towards partially evaluating reflection in Java, in: Proceedings of the Proceedings of the 2000 ACM...
  • E. Bodden, A. Sewe, J. Sinschek, H. Oueslati, M. Mezini, Taming reflection: aiding static analysis in the presence of...
  • Class Loading and Types in Java....
  • C. Csallner, Y. Smaragdakis, Check ‘n’ crash: combining static checking and testing, in: Proceedings of the Proceedings...
  • Z.Q. Cui et al.

    Target-directed concolic testing

    Chin. J. Comput.

    (2011)
  • B. Dufour, Blended analysis for improving the quality of framework-intensive applications, in: Proceedings of the 2008...
  • B. Dufour, B.G. Ryder, G. Sevitsky, Blended analysis for performance understanding of framework-based applications, in:...
  • B. Dufour, B.G. Ryder, G. Sevitsky, A scalable technique for characterizing the usage of temporaries in...
  • K. Gama et al.

    A self-healing component sandbox for untrustworthy third party code execution

  • J. Gosling et al.

    The Java Language Specification

    (2005)
  • N.D. Jones

    An introduction to partial evaluation

    ACM Comput. Surv.

    (1996)
  • T. Lindholm et al.

    Java Virtual Machine Specification

    (1999)
  • O. Lhoták et al.

    Scaling Java points-to analysis using SPARK

  • O. Lhoták et al.

    Context-sensitive points-to analysis: is it worth it?

  • O. Lhoták

    Program Analysis using Binary Decision Diagrams

    (2006)
  • Cited by (0)

    View full text