From 4a82626658f77e1ee3982698d163ecf6acc413af Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Mon, 14 Sep 2009 20:55:08 +0100 Subject: [PATCH 1/2] 6842838: 64-bit failure in handling invalid manifest in launcher Don't compare with hard-coded 32-bit -1 when checking zip fields. Reviewed-by: ksrini --- jdk/src/share/bin/parse_manifest.c | 2 +- .../tools/launcher/6842838/CreateBadJar.java | 168 ++++++++++++++++++ .../tools/launcher/6842838/Test6842838.sh | 75 ++++++++ 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 jdk/test/tools/launcher/6842838/CreateBadJar.java create mode 100644 jdk/test/tools/launcher/6842838/Test6842838.sh diff --git a/jdk/src/share/bin/parse_manifest.c b/jdk/src/share/bin/parse_manifest.c index 6dcca091a4b..a59540213c2 100644 --- a/jdk/src/share/bin/parse_manifest.c +++ b/jdk/src/share/bin/parse_manifest.c @@ -59,7 +59,7 @@ inflate_file(int fd, zentry *entry, int *size_out) char *out; z_stream zs; - if (entry->csize == 0xffffffff || entry->isize == 0xffffffff) + if (entry->csize == (size_t) -1 || entry->isize == (size_t) -1 ) return (NULL); if (lseek(fd, entry->offset, SEEK_SET) < (off_t)0) return (NULL); diff --git a/jdk/test/tools/launcher/6842838/CreateBadJar.java b/jdk/test/tools/launcher/6842838/CreateBadJar.java new file mode 100644 index 00000000000..dfdc9163de2 --- /dev/null +++ b/jdk/test/tools/launcher/6842838/CreateBadJar.java @@ -0,0 +1,168 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * Borrowing significantly from Martin Buchholz's CorruptedZipFiles.java + * + * Needed a way of testing the checks for corrupt zip/jar entry in + * inflate_file from file j2se/src/share/bin/parse_manifest.c + * and running them with the 64-bit launcher. e.g. + * sparcv9/bin/java -jar badjar.jar + * + * Run from a script driver Test6842838.sh as we want to specifically run + * bin/sparcv9/java, the 64-bit launcher. + * + * So this program will create a zip file and damage it in the way + * required to tickle this bug. + * + * It will cause a buffer overrun: but that will not always crash. + * Use libumem preloaded by the script driver in order to + * abort quickly when the overrun happens. That makes the test + * Solaris-specific. + */ + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import static java.lang.System.*; +import static java.util.zip.ZipFile.*; + +public class CreateBadJar { + +public static void main(String [] arguments) { + + if (arguments.length != 2) { + throw new RuntimeException("Arguments: jarfilename entryname"); + } + String outFile = arguments[0]; + String entryName = arguments[1]; + + try { + // If the named file doesn't exist, create it. + // If it does, we are expecting it to contain the named entry, for + // alteration. + if (!new File(outFile).exists()) { + System.out.println("Creating file " + outFile); + + // Create the requested zip/jar file. + ZipOutputStream zos = null; + zos = new ZipOutputStream( + new FileOutputStream(outFile)); + + ZipEntry e = new ZipEntry(entryName); + zos.putNextEntry(e); + for (int j=0; j<50000; j++) { + zos.write((int)'a'); + } + zos.closeEntry(); + zos.close(); + zos = null; + } + + // Read it. + int len = (int)(new File(outFile).length()); + byte[] good = new byte[len]; + FileInputStream fis = new FileInputStream(outFile); + fis.read(good); + fis.close(); + fis = null; + + int endpos = len - ENDHDR; + int cenpos = u16(good, endpos+ENDOFF); + if (u32(good, cenpos) != CENSIG) throw new RuntimeException("Where's CENSIG?"); + + byte[] bad; + bad = good.clone(); + + // Corrupt it... + int pos = findInCEN(bad, cenpos, entryName); + + // What bad stuff are we doing to it? + // Store a 32-bit -1 in uncomp size. + bad[pos+0x18]=(byte)0xff; + bad[pos+0x19]=(byte)0xff; + bad[pos+0x1a]=(byte)0xff; + bad[pos+0x1b]=(byte)0xff; + + // Bad work complete, delete the original. + new File(outFile).delete(); + + // Write it. + FileOutputStream fos = new FileOutputStream(outFile); + fos.write(bad); + fos.close(); + fos = null; + + } catch (Exception e) { + e.printStackTrace(); + } + +} + + /* + * Scan Central Directory File Headers looking for the named entry. + */ + + static int findInCEN(byte[] bytes, int cenpos, String entryName) { + int pos = cenpos; + int nextPos = 0; + String filename = null; + do { + if (nextPos != 0) { + pos = nextPos; + } + System.out.println("entry at pos = " + pos); + if (u32(bytes, pos) != CENSIG) throw new RuntimeException ("entry not found in CEN or premature end..."); + + int csize = u32(bytes, pos+0x14); // +0x14 1 dword csize + int uncompsize = u32(bytes, pos+0x18); // +0x18 1 dword uncomp size + int filenameLength = u16(bytes, pos+0x1c); // +0x1c 1 word length of filename + int extraLength = u16(bytes, pos+0x1e); // +0x1e 1 world length of extra field + int commentLength = u16(bytes, pos+0x20); // +0x20 1 world length of file comment + filename = new String(bytes, pos+0x2e, filenameLength); // +0x2e chars of filename + int offset = u32(bytes, pos+0x2a); // +0x2a chars of filename + + System.out.println("filename = " + filename + "\ncsize = " + csize + + " uncomp.size = " + uncompsize +" file offset = " + offset); + nextPos = pos + 0x2e + filenameLength + extraLength + commentLength; + + } while (!filename.equals(entryName)); + + System.out.println("entry found at pos = " + pos); + return pos; + } + + static int u8(byte[] data, int offset) { + return data[offset]&0xff; + } + + static int u16(byte[] data, int offset) { + return u8(data,offset) + (u8(data,offset+1)<<8); + } + + static int u32(byte[] data, int offset) { + return u16(data,offset) + (u16(data,offset+2)<<16); + } + +} + diff --git a/jdk/test/tools/launcher/6842838/Test6842838.sh b/jdk/test/tools/launcher/6842838/Test6842838.sh new file mode 100644 index 00000000000..5209ab4e10f --- /dev/null +++ b/jdk/test/tools/launcher/6842838/Test6842838.sh @@ -0,0 +1,75 @@ +#!/bin/sh -x + +# +# @test @(#)Test6842838.sh +# @bug 6842838 +# @summary Test 6842838 64-bit launcher failure due to corrupt jar +# @run shell Test6842838.sh +# + +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +if [ "${TESTSRC}" = "" ] +then TESTSRC=. +fi + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + echo "TESTJAVA not set, selecting " ${TESTJAVA} + echo "If this is incorrect, try setting the variable manually." +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS ) + NULL=/dev/null + PS=":" + FS="/" + JAVA_EXE=${TESTJAVA}${FS}bin${FS}sparcv9${FS}java + ;; + * ) + echo "Only testing on sparcv9 (use libumem to reliably catch buffer overrun)" + exit 0; + ;; +esac + +BADFILE=newbadjar.jar + +${JAVA_EXE} -version +rm -f ${BADFILE} +${TESTJAVA}/bin/javac CreateBadJar.java +${JAVA_EXE} CreateBadJar ${BADFILE} "META-INF/MANIFEST.MF" +LD_PRELOAD=/lib/64/libumem.so ${JAVA_EXE} -jar ${BADFILE} > test.out 2>&1 + +grep "Invalid or corrupt jarfile" test.out +exit $? From a89a6c4aeb6194aaeaf7dd19d9d8ff08fd66ea32 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Mon, 14 Sep 2009 13:37:26 -0700 Subject: [PATCH 2/2] 6878481: Add performance counters in the JDK Added new performance counters in the JDK to track performance metrics Reviewed-by: alanb, dholmes, iris, forax, andrew --- jdk/make/java/java/FILES_java.gmk | 4 +- .../share/classes/java/lang/ClassLoader.java | 7 + .../classes/java/net/URLClassLoader.java | 3 + .../share/classes/java/util/zip/ZipFile.java | 3 + .../share/classes/sun/misc/PerfCounter.java | 191 ++++++++++++++++++ .../sun/java2d/d3d/D3DGraphicsDevice.java | 3 + 6 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 jdk/src/share/classes/sun/misc/PerfCounter.java diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index e8a2223f67a..2ad599cbe23 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -454,6 +454,8 @@ JAVA_JAVA_java = \ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ sun/misc/JavaIOFileDescriptorAccess.java \ - sun/misc/JavaNioAccess.java + sun/misc/JavaNioAccess.java \ + sun/misc/Perf.java \ + sun/misc/PerfCounter.java FILES_java = $(JAVA_JAVA_java) diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index dc69abc0636..9fec9b570a0 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -380,6 +380,7 @@ public abstract class ClassLoader { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { + long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); @@ -394,7 +395,13 @@ public abstract class ClassLoader { if (c == null) { // If still not found, then invoke findClass in order // to find the class. + long t1 = System.nanoTime(); c = findClass(name); + + // this is the defining class loader; record the stats + sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); + sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); + sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { diff --git a/jdk/src/share/classes/java/net/URLClassLoader.java b/jdk/src/share/classes/java/net/URLClassLoader.java index 22be20b7ecd..c4f775db71a 100644 --- a/jdk/src/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/share/classes/java/net/URLClassLoader.java @@ -340,6 +340,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * used. */ private Class defineClass(String name, Resource res) throws IOException { + long t0 = System.nanoTime(); int i = name.lastIndexOf('.'); URL url = res.getCodeSourceURL(); if (i != -1) { @@ -370,12 +371,14 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { // Use (direct) ByteBuffer: CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); + sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); return defineClass(name, bb, cs); } else { byte[] b = res.getBytes(); // must read certificates AFTER reading bytes. CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); + sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); return defineClass(name, b, 0, b.length, cs); } } diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java index 76c270c1b10..583d7dcfe1a 100644 --- a/jdk/src/share/classes/java/util/zip/ZipFile.java +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java @@ -195,7 +195,10 @@ class ZipFile implements ZipConstants, Closeable { if (charset == null) throw new NullPointerException("charset is null"); this.zc = ZipCoder.get(charset); + long t0 = System.nanoTime(); jzfile = open(name, mode, file.lastModified()); + sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); + sun.misc.PerfCounter.getZipFileCount().increment(); this.name = name; this.total = getTotal(jzfile); } diff --git a/jdk/src/share/classes/sun/misc/PerfCounter.java b/jdk/src/share/classes/sun/misc/PerfCounter.java new file mode 100644 index 00000000000..8c47234407a --- /dev/null +++ b/jdk/src/share/classes/sun/misc/PerfCounter.java @@ -0,0 +1,191 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.misc; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.LongBuffer; +import java.security.AccessController; + +/** + * Performance counter support for internal JRE classes. + * This class defines a fixed list of counters for the platform + * to use as an interim solution until RFE# 6209222 is implemented. + * The perf counters will be created in the jvmstat perf buffer + * that the HotSpot VM creates. The default size is 32K and thus + * the number of counters is bounded. You can alter the size + * with -XX:PerfDataMemorySize= option. If there is + * insufficient memory in the jvmstat perf buffer, the C heap memory + * will be used and thus the application will continue to run if + * the counters added exceeds the buffer size but the counters + * will be missing. + * + * See HotSpot jvmstat implementation for certain circumstances + * that the jvmstat perf buffer is not supported. + * + */ +public class PerfCounter { + private static final Perf perf = + AccessController.doPrivileged(new Perf.GetPerfAction()); + + // Must match values defined in hotspot/src/share/vm/runtime/perfdata.hpp + private final static int V_Constant = 1; + private final static int V_Monotonic = 2; + private final static int V_Variable = 3; + private final static int U_None = 1; + + private final String name; + private final LongBuffer lb; + + private PerfCounter(String name, int type) { + this.name = name; + ByteBuffer bb = perf.createLong(name, U_None, type, 0L); + bb.order(ByteOrder.nativeOrder()); + this.lb = bb.asLongBuffer(); + } + + static PerfCounter newPerfCounter(String name) { + return new PerfCounter(name, V_Variable); + } + + static PerfCounter newConstantPerfCounter(String name) { + PerfCounter c = new PerfCounter(name, V_Constant); + return c; + } + + /** + * Returns the current value of the perf counter. + */ + public synchronized long get() { + return lb.get(0); + } + + /** + * Sets the value of the perf counter to the given newValue. + */ + public synchronized void set(long newValue) { + lb.put(0, newValue); + } + + /** + * Adds the given value to the perf counter. + */ + public synchronized void add(long value) { + long res = get() + value; + lb.put(0, res); + } + + /** + * Increments the perf counter with 1. + */ + public void increment() { + add(1); + } + + /** + * Adds the given interval to the perf counter. + */ + public void addTime(long interval) { + add(interval); + } + + /** + * Adds the elapsed time from the given start time (ns) to the perf counter. + */ + public void addElapsedTimeFrom(long startTime) { + add(System.nanoTime() - startTime); + } + + @Override + public String toString() { + return name + " = " + get(); + } + + static class CoreCounters { + static final PerfCounter pdt = newPerfCounter("sun.classloader.parentDelegationTime"); + static final PerfCounter lc = newPerfCounter("sun.classloader.findClasses"); + static final PerfCounter lct = newPerfCounter("sun.classloader.findClassTime"); + static final PerfCounter rcbt = newPerfCounter("sun.urlClassLoader.readClassBytesTime"); + static final PerfCounter zfc = newPerfCounter("sun.zip.zipFiles"); + static final PerfCounter zfot = newPerfCounter("sun.zip.zipFile.openTime"); + } + + static class WindowsClientCounters { + static final PerfCounter d3dAvailable = newConstantPerfCounter("sun.java2d.d3d.available"); + } + + /** + * Number of findClass calls + */ + public static PerfCounter getFindClasses() { + return CoreCounters.lc; + } + + /** + * Time (ns) spent in finding classes that includes + * lookup and read class bytes and defineClass + */ + public static PerfCounter getFindClassTime() { + return CoreCounters.lct; + } + + /** + * Time (ns) spent in finding classes + */ + public static PerfCounter getReadClassBytesTime() { + return CoreCounters.rcbt; + } + + /** + * Time (ns) spent in the parent delegation to + * the parent of the defining class loader + */ + public static PerfCounter getParentDelegationTime() { + return CoreCounters.pdt; + } + + /** + * Number of zip files opened. + */ + public static PerfCounter getZipFileCount() { + return CoreCounters.zfc; + } + + /** + * Time (ns) spent in opening the zip files that + * includes building the entries hash table + */ + public static PerfCounter getZipFileOpenTime() { + return CoreCounters.zfot; + } + + /** + * D3D graphic pipeline available + */ + public static PerfCounter getD3DAvailable() { + return WindowsClientCounters.d3dAvailable; + } +} diff --git a/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java b/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java index a4334b42f12..788a4d0ff21 100644 --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java @@ -67,6 +67,9 @@ public class D3DGraphicsDevice extends Win32GraphicsDevice { if (d3dAvailable) { // we don't use pixel formats for the d3d pipeline pfDisabled = true; + sun.misc.PerfCounter.getD3DAvailable().set(1); + } else { + sun.misc.PerfCounter.getD3DAvailable().set(0); } }