Finding Bugs in Java Native Interface Programs Goh Kondoh Tamiya Onodera Tokyo Research Laboratory IBM Research 1623-14, Shimotsuruma, Yamato-shi Kanagawa-ken, Japan +81-46-215-4584, +81-46-215-4645 {gkondo,tonodera}@jp.ibm.com ABSTRACT In this paper, we describe static analysis techniques for finding bugs in programs using the Java Native Interface (JNI). The JNI is both tedious and error-prone because there are many JNI-specific mistakes that are not caught by a native compiler. This paper is focused on four kinds of common mistakes. First, explicit statements to handle a possible exception need to be inserted after a statement calling a Java method. However, such statements tend to be forgotten. We present a typestate analysis to detect this exception-handling mistake. Second, while the native code can allocate resources in a Java VM, those resources must be manually released, unlike Java. Mistakes in resource management cause leaks and other errors. To detect Java resource errors, we used the typestate analysis also used for detecting general memory errors. Third, if a reference to a Java resource lives across multiple native method invocations, it should be converted into a global reference. However, programmers sometimes forget this rule and, for example, store a local reference in a global variable for later uses. We provide a syntax checker that detects this bad coding practice. Fourth, no JNI function should be called in a critical region. If called there, the current thread might block and cause a deadlock. Misinterpreting the end of the critical region, programmers occasionally break this rule. We present a simple typestate analysis to detect an improper JNI function call in a critical region. We have implemented our analysis techniques in a bug-finding tool called BEAM, and executed it on opensource software including JNI code. In the experiment, our analysis techniques found 86 JNI-specific bugs without any overhead and increased the total number of bug reports by 76%. Categories and Subject Descriptors D.2.4 [Software Engineering]: Software/Program Verification – correctness proofs, reliability, validation. D.3.3 [Programming Languages]: Language Constructs and Features – constraints, data types and structures, polymorphism, procedures, functions, and subroutines. General Terms Algorithms, Performance, Design, Reliability, Experimentation, Languages, Verification. Keywords Java Native Interface, static analysis, typestate analysis 1. INTRODUCTION A foreign function interface (FFI) allows code written in one language to call code written in another language. Many programming languages support their own FFIs, and Java’s version is called the Java Native Interface (JNI). However, the JNI is tedious to use and error-prone. For example, the programmer’s guide [10] devotes an entire chapter, Traps and Pitfalls, to 15 of the most common programming errors (Table 1). To express a simple expression that can be written as just a few terms in Java, JNI typically requires several lines in native code. Also, some JNI functions must be called in a specific order. As a result, code using the JNI is more likely to have bugs than code without JNI calls. These JNI mistakes are not caught by the compiler. We encountered these problems with JNI programming while we were developing a static analysis tool for Java in BEAM [3]. In an early phase of the development, we integrated a Java parser written in Java with the BEAM modules written in C and C++. During this development we encountered most of the problems described in Table 1, and that motivated us to create a JNI bug-finding tool. Table 1 spans from high-level design issues to bad coding practices at low levels. The design issues 5, 6, 7, 14 and 15 are beyond our scope because they depend on the target software and cannot be checked automatically by a static analysis tool. We worked on the other problems, especially those not covered by prior research, and prioritized them according to their severity. We selected the problems marked with symbol ‘X’ and also added the problem of calling a JNI function from a critical region, which is described later. A type inference system [6] is a useful approach for Problems 2 and 3. We implemented such a system and found it somewhat useful during the coding phases. However, it did not perform well in our experiments (for reasons explained in Section 6.2). Problem 4 can easily be detected by a syntax checker or a compiler warning (such as a –Wconversion warning). BEAM already included a checking tool for this kind of bug, but it also failed to produce some of the relevant warning messages in our experiments. Therefore, we do not further discuss these tools in this paper. Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. ISSTA’08, July 20–24, 2008, Seattle, Washington, USA. Copyright 2008 ACM 978-1-60558-050-0/08/07...$5.00. 109