Package

Source Code of MemoryAllocatorTest

/*
* Copyright (c) 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

/*
* @test MemoryAllocatorTest.java
* @bug 6755943 6792554
* @summary Checks any memory overruns in archive length.
* @run main/timeout=1200 MemoryAllocatorTest
*/

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

public class MemoryAllocatorTest {

    /*
     * The smallest possible pack file with 1 empty resource
     */
    static int[] magic = {
        0xCA, 0xFE, 0xD0, 0x0D
    };
    static int[] version_info = {
        0x07, // minor
        0x96  // major
    };
    static int[] option = {
        0x10
    };
    static int[] size_hi = {
        0x00
    };
    static int[] size_lo_ulong = {
        0xFF, 0xFC, 0xFC, 0xFC, 0xFC // ULONG_MAX 0xFFFFFFFF
    };
    static int[] size_lo_correct = {
        0x17
    };
    static int[] data = {
        0x00, 0xEC, 0xDA, 0xDE, 0xF8, 0x45, 0x01, 0x02,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x01, 0x31, 0x01, 0x00
    };
    // End of pack file data

    static final String JAVA_HOME = System.getProperty("java.home");

    static final boolean debug = Boolean.getBoolean("MemoryAllocatorTest.Debug");
    static final boolean WINDOWS = System.getProperty("os.name").startsWith("Windows");
    static final boolean LINUX = System.getProperty("os.name").startsWith("Linux");
    static final boolean SIXTYFOUR_BIT = System.getProperty("sun.arch.data.model", "32").equals("64");
    static final private int NATIVE_EXPECTED_EXIT_CODE = (WINDOWS) ? -1 : 255;
    static final private int JAVA_EXPECTED_EXIT_CODE = 1;
   
    static final private String EXPECTED_ERROR_MESSAGE[] = {
        "Native allocation failed",
        "overflow detected",
        "archive header had incorrect size",
        "EOF reading band",
        "impossible archive size",
  "bad value count",
  "file too large"
    };

    static int testExitValue = 0;
   
    static byte[] bytes(int[] a) {
        byte[] b = new byte[a.length];
        for (int i = 0; i < b.length; i++) {
            b[i] = (byte) a[i];
        }
        return b;
    }
   
    static void createPackFile(boolean good, File packFile) throws IOException {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(packFile);
            fos.write(bytes(magic));
            fos.write(bytes(version_info));
            fos.write(bytes(option));
            fos.write(bytes(size_hi));
            if (good) {
                fos.write(bytes(size_lo_correct));
            } else {
                fos.write(bytes(size_lo_ulong));
            }
            fos.write(bytes(data));
        } finally {
            if (fos != null) {
                fos.close();
            }
        }
    }

    /*
     * This method modifies the LSB of the size_lo for various larger
     * wicked values between MAXINT-0x3F and MAXINT.
     */
    static int modifyPackFileLarge(File packFile) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(packFile, "rws");
        long len = packFile.length();
        FileChannel fc = raf.getChannel();
        MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, len);
        int pos = magic.length + version_info.length + option.length +
                size_hi.length;
        byte value = bb.get(pos);
        value--;
        bb.position(pos);
        bb.put(value);
        bb.force();
        fc.truncate(len);
        fc.close();
        return value & 0xFF;
    }
 
    /*
     * This method modifies the LSB of the size_lo for smaller wicked values
     */
    static int modifyPackFileSmall(File packFile, boolean increment) throws IOException {
        RandomAccessFile raf = new RandomAccessFile(packFile, "rws");
        long len = packFile.length();
        FileChannel fc = raf.getChannel();
        MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, len);
        int pos = magic.length + version_info.length + option.length +
                size_hi.length;
        byte value = bb.get(pos);
        if (increment)
            value++;
        else
            value--;
        bb.position(pos);
        bb.put(value);
        bb.force();
        fc.truncate(len);
        fc.close();
        return value & 0xFF;
    }
   
   
    static String getUnpack200Cmd() throws Exception {
        return getAjavaCmd("unpack200");
    }
   
    static String getJavaCmd() throws Exception {
        return getAjavaCmd("java");
    }
   
    static String getAjavaCmd(String cmdStr) throws Exception {
        File binDir = new File(JAVA_HOME, "bin");
        File unpack200File = WINDOWS
                ? new File(binDir, cmdStr + ".exe")
                : new File(binDir, cmdStr);

        String cmd = unpack200File.getAbsolutePath();
        if (!unpack200File.canExecute()) {
            throw new Exception("please check" +
                    cmd + " exists and is executable");
        }
        return cmd;
    }
    final static  String UNPACK_FN = "Unpack";

   
    static void createTestClass() throws IOException {
        PrintWriter pw = new PrintWriter(new FileWriter(UNPACK_FN + ".java"));
        try {
            pw.println("import java.io.File;");
            pw.println("import java.io.FileOutputStream;");
            pw.println("import java.util.jar.JarOutputStream;");
            pw.println("import java.util.jar.Pack200;");

            pw.println("public final class " + UNPACK_FN + "  {");
            pw.println("public static void main(String args[]) throws Exception {");
            pw.println("Pack200.Unpacker u = Pack200.newUnpacker();");
            pw.println("File in = new File(args[0]);");
            pw.println("File out = new File(args[1]);");
            pw.println("FileOutputStream os = new FileOutputStream(out) {");
            pw.println("public void write(int b) {");
            pw.println("}");
            pw.println("};");
            pw.println("u.unpack(in, new JarOutputStream(os));");
            pw.println("}");
            pw.println("}");
        } finally {
            if (pw != null) {
                pw.close();
            }
        }
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        final String javacCmds[] = {UNPACK_FN + ".java"};
        javac.run(null, null, null, javacCmds);
    }
   
    static TestResult runUnpack200(File packFile) throws Exception {
        if (!packFile.exists()) {
            throw new Exception("please check" + packFile + " exists");
        }
        return runUnpacker(getUnpack200Cmd(), packFile.getName(), "testout.jar");
    }

    static TestResult runJavaUnpack(File packFile) throws Exception {
        if (!packFile.exists()) {
            throw new Exception("please check" + packFile + " exists");
        }
        return runUnpacker(getJavaCmd(), "-cp", ".", UNPACK_FN, packFile.getName(), "testout.jar");
    }
       
    static TestResult runUnpacker(String... cmds) throws Exception {
  
        ArrayList<String> alist = new ArrayList<String>();
        ProcessBuilder pb =
                new ProcessBuilder(cmds);
        Map<String, String> env = pb.environment();
        pb.directory(new File("."));
        for (String x : cmds) {
            System.out.print(x + " ");
        }
        System.out.println("");
        int retval = 0;
        try {
            pb.redirectErrorStream(true);
            Process p = pb.start();
            BufferedReader rd = new BufferedReader(
                    new InputStreamReader(p.getInputStream()), 8192);
            String in = rd.readLine();
            while (in != null) {
                alist.add(in);
                System.out.println(in);
                in = rd.readLine();
            }
            retval = p.waitFor();
            p.destroy();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
        return new TestResult("", retval, alist);
    }

    /*
     * tests large size values
     */
    static void runLargeTests() throws Exception {
        File packFile = new File("big.pack");      
        // Create a good pack file and test if everything is ok
        createPackFile(true, packFile);
        TestResult tr = runUnpack200(packFile);
        tr.setDescription("unpack200: a good pack file");
        tr.checkPositive();
        tr.isOK();
        System.out.println(tr);
        if (testExitValue != 0) {
            throw new RuntimeException("Test ERROR");
        }
       
        // try the same with java unpacker
        tr = runJavaUnpack(packFile);
        tr.setDescription("unpack: a good pack file");
        tr.checkPositive();
        tr.isOK();
        System.out.println(tr);
        if (testExitValue != 0) {
            throw new RuntimeException("Test ERROR");
        }      

        int value = 0;
   
        // create a bad pack file
        createPackFile(false, packFile);
       
        // run the unpack200 unpacker
        tr = runUnpack200(packFile);
        tr.setDescription("unpack200: a wicked pack file");
        tr.contains(EXPECTED_ERROR_MESSAGE);
        tr.checkValue(NATIVE_EXPECTED_EXIT_CODE);
        // run the java unpacker now
        tr = runJavaUnpack(packFile);
        tr.setDescription("unpack: a wicked pack file");
        tr.contains(EXPECTED_ERROR_MESSAGE);
        tr.checkValue(JAVA_EXPECTED_EXIT_CODE);
     
        // Large values test
        System.out.println(tr);
        value = modifyPackFileLarge(packFile);

        // continue creating bad pack files by modifying the specimen pack file.
        while (value >= 0xc0) {
            tr.setDescription("unpack200: wicked value=0x" +
                    Integer.toHexString(value & 0xFF));
            tr = runUnpack200(packFile);
            tr.contains(EXPECTED_ERROR_MESSAGE);
            tr.checkValue(NATIVE_EXPECTED_EXIT_CODE);

            System.out.println(tr);
           
            tr.setDescription("unpack: wicked value=0x" +
                    Integer.toHexString(value & 0xFF));
            tr = runJavaUnpack(packFile);
            tr.contains(EXPECTED_ERROR_MESSAGE);
            tr.checkValue(JAVA_EXPECTED_EXIT_CODE);

            System.out.println(tr);
           
            value = modifyPackFileLarge(packFile);
        }       
    }
   
    /*
     * tests mutations near the 0x0 size area
     */
    static void runSmallTests() throws Exception {
          // small values test
         // create a good pack file to start with
        File packFile = new File("small.pack");   
        createPackFile(true, packFile);
        TestResult tr = null;
        int value = modifyPackFileSmall(packFile, false);
        while (value > 0) {
            // run the unpack200 unpacker
            tr = runUnpack200(packFile);
            tr.setDescription("unpack200: wicked value=0x" +
                    Integer.toHexString(value & 0xFF));
            tr.contains(EXPECTED_ERROR_MESSAGE);
            tr.checkValue(NATIVE_EXPECTED_EXIT_CODE);

            System.out.println(tr);
           
            // run the java unpacker now
            tr = runJavaUnpack(packFile);
            tr.setDescription("unpack: wicked value=0x" +
                    Integer.toHexString(value & 0xFF));
            tr.contains(EXPECTED_ERROR_MESSAGE);
            tr.checkValue(JAVA_EXPECTED_EXIT_CODE);
            System.out.println(tr);
           
            value = modifyPackFileSmall(packFile, false);
        }          
    }
   
    /*
     * These tests uses the unpacker on packfiles provided by external
     * contributors which cannot be recreated programmatically.
     * Note: The jar file containing the tests may not be included in all
     * opensource repositories and the test will pass if the packfiles.jar
     * is missing.
     */
    static void runBadPackTests() throws Exception {
       File packJar = new File(System.getProperty("test.src", "."), "packfiles.jar");
       if (!packJar.exists()) {
           System.out.println("Warning: packfiles.jar missing, therefore this test passes vacuously");
           return;
       }
       String[] jarCmd = { "xvf", packJar.getAbsolutePath()};
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       PrintStream jarout = new PrintStream(baos);
       sun.tools.jar.Main jarTool = new sun.tools.jar.Main(jarout, System.err, "jar-tool");
       if (!jarTool.run(jarCmd)) {
           throw new RuntimeException("Error: could not extract archive");
       }
       TestResult tr = null;
       jarout.close();
       baos.flush();
       for (String x : baos.toString().split("\n")) {
           String line[] = x.split(":");
           if (line[0].trim().startsWith("inflated")) {
               String pfile = line[1].trim();
               tr = runUnpack200(new File(pfile));
               tr.setDescription("unpack200: " + pfile);
               tr.contains(EXPECTED_ERROR_MESSAGE);
               tr.checkValue(NATIVE_EXPECTED_EXIT_CODE);
               System.out.println(tr);
              
               tr = runJavaUnpack(new File(pfile));
               tr.setDescription("unpack: " + pfile);
               tr.contains(EXPECTED_ERROR_MESSAGE);
               tr.checkValue(JAVA_EXPECTED_EXIT_CODE);
               System.out.println(tr);
           }
       }      
    }
   
    /**
     * @param args the command line arguments
     * @throws java.lang.Exception
     */
    public static void main(String[] args) throws Exception {
        /*
         * jprt systems on windows and linux seem to have abundant memory
         * therefore can take a very long time to run, and even if it does
         * the error message is not accurate for us to discern if the test
         * passes successfully.
         */
        if (SIXTYFOUR_BIT && (LINUX || WINDOWS)) {
            System.out.println("Warning: Windows/Linux 64bit tests passes vacuously");
            return;
        }

        // Create the java unpacker
        createTestClass();       
        runLargeTests();
        runSmallTests();
        runBadPackTests();
   
        if (testExitValue != 0) {
            throw new Exception("Pack200 archive length tests(" +
                    testExitValue + ") failed ");
        } else {
            System.out.println("All tests pass");
        }
    }

    /*
     * A class to encapsulate the test results and stuff, with some ease
     * of use methods to check the test results.
     */
    static class TestResult {

        StringBuilder status;
        int exitValue;
        List<String> testOutput;
        String description;
        boolean isNPVersion;
       
        /*
         * The debug version builds of unpack200 call abort(3) which might set
         * an unexpected return value, therefore this test is to determine
         * if we are using a product or non-product build and check the
         * return value appropriately.
         */
        boolean isNonProductVersion() throws Exception {
            ArrayList<String> alist = new ArrayList<String>();
            ProcessBuilder pb = new ProcessBuilder(getUnpack200Cmd(), "--version");
            Map<String, String> env = pb.environment();
            System.out.println(new File(".").getAbsolutePath());
            pb.directory(new File("."));
            int retval = 0;
            try {
                pb.redirectErrorStream(true);
                Process p = pb.start();
                BufferedReader rd = new BufferedReader(
                        new InputStreamReader(p.getInputStream()), 8192);
                String in = rd.readLine();
                while (in != null) {
                    alist.add(in);
                    System.out.println(in);
                    in = rd.readLine();
                }
                retval = p.waitFor();
                p.destroy();
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new RuntimeException(ex.getMessage());
            }
            for (String x : alist) {
                if (x.contains("non-product")) {
                    return true;
                }
            }
            return false;
        }


        public TestResult(String str, int rv, List<String> oList) throws Exception {
            status = new StringBuilder(str);
            exitValue = rv;
            testOutput = oList;
            isNPVersion = isNonProductVersion();
            if (isNPVersion) {
                System.err.println("Warning: exit values are not checked" +
                        " for non-product build");
            }
        }

        void setDescription(String description) {
            this.description = description;
        }

        void checkValue(int value) {
            if (isNPVersion) return;
            if (exitValue != value) {
                status =
                        status.append("  Error: test expected exit value " +
                        value + "got " + exitValue);
                testExitValue++;
            }
        }

        void checkNegative() {
            if (exitValue == 0) {
                status = status.append(
                        "  Error: test did not expect 0 exit value");

                testExitValue++;
            }
        }

        void checkPositive() {
            if (exitValue != 0) {
                status = status.append(
                        "  Error: test did not return 0 exit value");
                testExitValue++;
            }
        }

        boolean isOK() {
            return exitValue == 0;
        }

        boolean isZeroOutput() {
            if (!testOutput.isEmpty()) {
                status = status.append("  Error: No message from cmd please");
                testExitValue++;
                return false;
            }
            return true;
        }

        boolean isNotZeroOutput() {
            if (testOutput.isEmpty()) {
                status = status.append("  Error: Missing message");
                testExitValue++;
                return false;
            }
            return true;
        }

        public String toString() {
            if (debug) {
                for (String x : testOutput) {
                    status = status.append(x + "\n");
                }
            }
            if (description != null) {
                status.insert(0, description);
            }
            return status.append("\nexitValue = " + exitValue).toString();
        }

        boolean contains(String... strs) {
            for (String x : testOutput) {
                for (String y : strs) {
                    if (x.contains(y)) {
                        return true;
                    }
                }
            }
            status = status.append("   Error: expected strings not found");
            testExitValue++;
            return false;
        }
    }
}
TOP

Related Classes of MemoryAllocatorTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.