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