JDK-6984762 : Invalid close of file descriptor '-1' in findZoneinfoFile
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 6u21
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2010-09-14
  • Updated: 2014-10-15
  • Resolved: 2011-10-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8
6u30Fixed 7u76Fixed 8 b10Fixed
Description
FULL PRODUCT VERSION :
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)

Note: this also occurs in 6u21 but it is not the version we are recommending at this point.


ADDITIONAL OS VERSION INFORMATION :
Linux <hostname obscured> 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 EST 2008 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
When a java.util.Date is converted to a String the TimeZone is needed. During the retrieval of the timezone information the native method repeatedly tries to close the file descriptor number -1 which causes an error with EBADF.

We are running with the JRE embedded and sandboxed within a database server with full control of all system calls (such as close()).

Looking at the source for findZoneinfoFile() in TimeZone_md.c we see the fd initialized to -1 at the top of the method. Further down we recursively mill through the directory entries at each level in the big while loop. When we finish with a level we cleanup, including a file close:
    if (fd != 0) {
	(void) close(fd);
    }

Note that the close checks for fd != 0 so we incorrectly attempt to close a bad file descriptor (for timezones we are not using no file is opened). The fd should either be initialized to 0 or the close check should exclude -1 as well.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Outside of the Sybase ASE server the equivalent java call is simply:

public static void doit()
{
        java.util.Date d = new java.util.Date()
        System.out.println( d );
}

We go into the native method TimeZone.getSystemTimeZoneID at this point
main[1] where
  [1] java.util.TimeZone.setDefaultZone (TimeZone.java:559)
  [2] java.util.TimeZone.getDefaultRef (TimeZone.java:550)
  [3] java.util.Date.normalize (Date.java:1,193)
  [4] java.util.Date.toString (Date.java:1,027)
  [5] java.lang.String.valueOf (String.java:2,838)
  [6] java.io.PrintStream.println (PrintStream.java:788)
  [7] Foo.doit (Foo.java:4)
  [8] Foo.main (Foo.java:9)

Everything is happening under the covers when doing the timezone lookup
(gdb) where
#0  0x0000000001c8d406 in pci_coma (timeout=0) at /marslinux3_imet_eng/asebharani_wtenhave_vu/calm/svr/sql/generic/pci/bridge/bridge.c:1553
#1  0x00002aaaaee2c25a in pca_close (func=0x316be0d950 <close>, fd=-1) at /marslinux3_imet_eng/asebharani_wtenhave_vu/calm/svr/sql/generic/pci/plugins/jvm/hostapi.c:972
#2  0x0000000001cdeb5c in close (fd=-1) at /marslinux3_imet_eng/asebharani_wtenhave_vu/calm/svr/sql/generic/pci/bridge/pciruntime.c:1808
#3  0x00002aaab02e9ebd in findZoneinfoFile () from /marslinux3_imet_eng/asebharani_wtenhave_vu/sybase.64.SMP/shared/JRE-6_0_20_64BIT/lib/amd64/libjava.so
#4  0x00002aaab02e9ed9 in findZoneinfoFile () from /marslinux3_imet_eng/asebharani_wtenhave_vu/sybase.64.SMP/shared/JRE-6_0_20_64BIT/lib/amd64/libjava.so
#5  0x00002aaab02ea1ba in getPlatformTimeZoneID () from /marslinux3_imet_eng/asebharani_wtenhave_vu/sybase.64.SMP/shared/JRE-6_0_20_64BIT/lib/amd64/libjava.so
#6  0x00002aaab02e9f77 in findJavaTZ_md () from /marslinux3_imet_eng/asebharani_wtenhave_vu/sybase.64.SMP/shared/JRE-6_0_20_64BIT/lib/amd64/libjava.so
#7  0x00002aaab02e9b69 in Java_java_util_TimeZone_getSystemTimeZoneID () from /marslinux3_imet_eng/asebharani_wtenhave_vu/sybase.64.SMP/shared/JRE-6_0_20_64BIT/lib/amd64/libjava.so

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
close(fd) should return 0 (success)
ACTUAL -
close(fd) returns -1 with EBADF for a reason

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Foo
        public static void doit() {
                java.util.Date d = new java.util.Date();
                System.out.println(d);
        }

        public static void main(String[] a)
        {
                doit();
        }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Most users will not see this. We have worked around internally but at the cost of masking other potential errors with incorrect file i/o.

Comments
EVALUATION Set fd to -1 after fd gets closed.
2011-09-27