You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by lk...@apache.org on 2022/03/21 19:27:07 UTC

[netbeans] branch master updated: Handle classfiles with too new versions.

This is an automated email from the ASF dual-hosted git repository.

lkishalmi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new c204921  Handle classfiles with too new versions.
c204921 is described below

commit c20492168f16094844107376a8f2e475d970269b
Author: Jan Lahoda <jl...@netbeans.org>
AuthorDate: Sat Feb 12 08:28:39 2022 +0100

    Handle classfiles with too new versions.
---
 .../lib/nbjavac/services/NBClassReader.java        |  73 +++++++++-
 .../lib/nbjavac/services/NBClassReaderTest.java    | 150 +++++++++++++++++++++
 2 files changed, 221 insertions(+), 2 deletions(-)

diff --git a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java
index 062412f..5a26320 100644
--- a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java
+++ b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBClassReader.java
@@ -18,23 +18,40 @@
  */
 package org.netbeans.lib.nbjavac.services;
 
+import com.sun.tools.javac.code.ClassFinder.BadClassFile;
 import java.util.Set;
 import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.jvm.ClassFile;
 import com.sun.tools.javac.jvm.ClassFile.Version;
 import com.sun.tools.javac.jvm.ClassReader;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.tools.ForwardingJavaFileObject;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
 
 /**
  *
  * @author lahvac
  */
 public class NBClassReader extends ClassReader {
-    
+
     public static void preRegister(Context context) {
         context.put(classReaderKey, new Context.Factory<ClassReader>() {
             public ClassReader make(Context c) {
@@ -45,12 +62,14 @@ public class NBClassReader extends ClassReader {
 
     private final Names names;
     private final NBNames nbNames;
+    private final Log log;
 
     public NBClassReader(Context context) {
         super(context);
 
         names = Names.instance(context);
         nbNames = NBNames.instance(context);
+        log = Log.instance(context);
 
         NBAttributeReader[] readers = {
             new NBAttributeReader(nbNames._org_netbeans_EnclosingMethod, Version.V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
@@ -65,7 +84,57 @@ public class NBClassReader extends ClassReader {
         for (NBAttributeReader r: readers)
             attributeReaders.put(r.getName(), r);
     }
-    
+
+    @Override
+    public void readClassFile(ClassSymbol c) {
+        try {
+            super.readClassFile(c);
+        } catch (BadClassFile cf) {
+            if ("compiler.misc.bad.class.file.header".equals(cf.getDiagnostic().getCode())) {
+                JavaFileObject origFile = c.classfile;
+                try (InputStream in = origFile.openInputStream()) {
+                    byte[] data = readFile(in);
+                    int major = (Byte.toUnsignedInt(data[6]) << 8) + Byte.toUnsignedInt(data[7]);
+                    int maxMajor = ClassFile.Version.MAX().major;
+                    if (maxMajor < major) {
+                        if (log.currentSourceFile() != null) {
+                            log.warning(0, Warnings.BigMajorVersion(origFile, major, maxMajor));
+                        }
+                        data[6] = (byte) (maxMajor >> 8);
+                        data[7] = (byte) (maxMajor & 0xFF);
+                        byte[] dataFin = data;
+                        c.classfile = new ForwardingJavaFileObject(origFile) {
+                            @Override
+                            public InputStream openInputStream() throws IOException {
+                                return new ByteArrayInputStream(dataFin);
+                            }
+                        };
+                        super.readClassFile(c);
+                        return ;
+                    }
+                } catch (IOException ex) {
+                    Logger.getLogger(NBClassReader.class.getName()).log(Level.SEVERE, null, ex);
+                } finally {
+                    c.classfile = origFile;
+                }
+            }
+            throw cf;
+        }
+    }
+
+    static byte[] readFile(final InputStream in) throws IOException {
+        byte[] data = new byte[Math.max(in.available(), 256)];
+        int off = 0;
+        int read;
+        while ((read = in.read(data, off, data.length - off)) != (-1)) {
+            off += read;
+            if (data.length == off) {
+                data = Arrays.copyOf(data, 2 * (data.length + in.available()));
+            }
+        }
+        return Arrays.copyOf(data, off);
+    }
+
     private abstract class NBAttributeReader extends AttributeReader {
 
         private NBAttributeReader(Name name, Version version, Set<AttributeKind> kinds) {
diff --git a/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassReaderTest.java b/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassReaderTest.java
new file mode 100644
index 0000000..a642e36
--- /dev/null
+++ b/java/lib.nbjavac/test/unit/src/org/netbeans/lib/nbjavac/services/NBClassReaderTest.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.lib.nbjavac.services;
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.util.Context;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import org.junit.Assert;
+import org.netbeans.junit.NbTestCase;
+
+import static org.netbeans.lib.nbjavac.services.Utilities.DEV_NULL;
+
+/**
+ *
+ * @author lahvac
+ */
+public class NBClassReaderTest extends NbTestCase {
+
+    public NBClassReaderTest(String testName) {
+        super(testName);
+    }
+
+    public void testTooNewClassFile() throws Exception {
+        compile("package test; public class Test { }");
+        File testClass = new File(new File(workingDir, "test"), "Test.class");
+        try (RandomAccessFile raf = new RandomAccessFile(testClass, "rw")) {
+            raf.seek(6);
+
+            raf.write(0xFF);
+            raf.write(0xFF);
+        }
+        testCompile("package test; class Test2 { Test t; }",
+                    "/Test.java:1:compiler.warn.big.major.version");
+    }
+
+    public void testReadBytes() throws Exception {
+        byte[] data = new byte[1024];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = (byte) i;
+        }
+        for (int i = 0; i <= data.length; i++) {
+            int available = i;
+            ByteArrayInputStream dataIS = new ByteArrayInputStream(data);
+            InputStream testIS = new InputStream() {
+                @Override
+                public int read() throws IOException {
+                    return dataIS.read();
+                }
+                @Override
+                public int available() throws IOException {
+                    return available;
+                }
+            };
+            byte[] actual = NBClassReader.readFile(testIS);
+            Assert.assertArrayEquals(data, actual);
+        }
+    }
+    //<editor-fold defaultstate="collapsed" desc=" Test Infrastructure ">
+    private static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+
+    private File workingDir;
+
+    @Override
+    protected void setUp() throws Exception {
+        workingDir = getWorkDir();
+    }
+
+    private void compile(String code) throws Exception {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+
+        StandardJavaFileManager std = tool.getStandardFileManager(null, null, null);
+
+        std.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(workingDir));
+
+        Context context = new Context();
+        NBLog.preRegister(context, DEV_NULL);
+        final JavacTaskImpl ct = (JavacTaskImpl) ((JavacTool)tool).getTask(null, std, null, Arrays.asList("-source", "8", "-target", "8"), null, Arrays.asList(new MyFileObject(code)), context);
+
+        ct.call();
+    }
+
+    private void testCompile(String code, String... expectedErrors) throws IOException {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+
+        StandardJavaFileManager std = tool.getStandardFileManager(null, null, null);
+
+        std.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(workingDir));
+
+        Context context = new Context();
+        NBLog.preRegister(context, DEV_NULL);
+        DiagnosticCollector<JavaFileObject> diags = new DiagnosticCollector<>();
+        JavacTaskImpl ct = (JavacTaskImpl)((JavacTool)tool).getTask(null, std, diags, Arrays.asList("-source", "1.8", "-target", "1.8", "-Xlint:-options", "-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code)), context);
+
+        NBClassReader.preRegister(ct.getContext());
+
+        ct.analyze();
+
+        List<String> actualErrors = diags.getDiagnostics().stream().map(d -> (d.getSource() != null ? d.getSource().getName() + ":" : "") + d.getLineNumber() + ":" + d.getCode()).collect(Collectors.toList());
+
+        assertEquals(Arrays.asList(expectedErrors), actualErrors);
+    }
+    //</editor-fold>
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists