1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 22:22:11 +02:00

Bug 572250: [Java 16] fix illegal reflection in scannerInfoCache

Java 16 restricts some reflection. The serializing of scannerInfoCache
with gson does some reflection on Pattern which isn't allowed.
Fortunately the reflection is not needed, we just have to prevent
gson from calling setAccessible by providing our own serialization
for the IExtendedScannerInfo

Change-Id: I0db5cec9cfec1ac4caabd2e67f1d6a336e361023
This commit is contained in:
Jonah Graham 2021-04-07 09:41:42 -04:00
parent 55c2df3b03
commit 19a37f18b4
10 changed files with 341 additions and 74 deletions

View file

@ -1,5 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.cdt.core.tests" version="2">
<resource path="parser/org/eclipse/cdt/core/parser/tests/scannerinfo/ExtendedScannerInfoSerializerDeserializerTest.java" type="org.eclipse.cdt.core.parser.tests.scannerinfo.ExtendedScannerInfoSerializerDeserializerTest">
<filter comment="This is ok - there is just no way of marking @noreference as having friends." id="640712815">
<message_arguments>
<message_argument value="ExtendedScannerInfo"/>
<message_argument value="ExtendedScannerInfoSerializerDeserializerTest"/>
<message_argument value="getIncludeExportPatterns()"/>
</message_arguments>
</filter>
</resource>
<resource path="suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase5.java" type="org.eclipse.cdt.core.testplugin.util.BaseTestCase5$ModelJoiner">
<filter comment="This is ok - there is just no way of marking @noreference as having friends." id="640712815">
<message_arguments>

View file

@ -22,6 +22,7 @@ Export-Package: org.eclipse.cdt.core.cdescriptor.tests,
org.eclipse.cdt.core.parser.tests.rewrite.changegenerator,
org.eclipse.cdt.core.parser.tests.rewrite.comenthandler,
org.eclipse.cdt.core.parser.tests.scanner,
org.eclipse.cdt.core.parser.tests.scannerinfo,
org.eclipse.cdt.core.resources.tests,
org.eclipse.cdt.core.settings.model,
org.eclipse.cdt.core.suite,
@ -42,7 +43,8 @@ Require-Bundle: org.eclipse.core.resources,
org.eclipse.jface.text,
org.eclipse.core.filesystem,
org.eclipse.ltk.core.refactoring;bundle-version="3.4.0",
org.hamcrest
org.hamcrest,
com.google.gson;bundle-version="[2.8.6,3.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Bundle-RequiredExecutionEnvironment: JavaSE-11

View file

@ -0,0 +1,111 @@
/*******************************************************************************
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.scannerinfo;
import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.Map;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
import org.eclipse.cdt.internal.core.scannerinfo.ExtendedScannerInfoSerializer;
import org.eclipse.cdt.internal.core.scannerinfo.IExtendedScannerInfoDeserializer;
import org.junit.jupiter.api.Test;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class ExtendedScannerInfoSerializerDeserializerTest {
private static class Container {
IExtendedScannerInfo info;
}
private Gson createGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(IExtendedScannerInfo.class, new IExtendedScannerInfoDeserializer());
gsonBuilder.registerTypeAdapter(ExtendedScannerInfo.class, new ExtendedScannerInfoSerializer());
Gson gson = gsonBuilder.create();
return gson;
}
@Test
public void test() {
String input = "" //
+ "{" //
+ "\"info\": {\n" //
+ " \"includeExportPatterns\": {\n" //
+ " \"includeExportPattern\": {\n" //
+ " \"pattern\": \"pattern1\"\n" //
+ " },\n" //
+ " \"includeBeginExportPattern\": {\n" //
+ " \"pattern\": \"pattern2\"\n" //
+ " },\n" //
+ " \"includeEndExportPattern\": {\n" //
+ " \"pattern\": \"pattern3\"\n" //
+ " }\n" //
+ " },\n" //
+ " \"definedSymbols\": {\n" //
+ " \"__STDC__\": \"1\",\n" //
+ " \"__INT64_MAX__\": \"0x7fffffffffffffffL\"\n" //
+ " },\n" //
+ " \"includePaths\": [\n" //
+ " \"/usr/local/include\",\n" //
+ " \"/usr/include\"\n" //
+ " ]\n" //
+ "}" //
+ "}";
Gson createGson = createGson();
Container fromJson = createGson.fromJson(input, Container.class);
ExtendedScannerInfo info = (ExtendedScannerInfo) fromJson.info;
assertEquals(Map.of("__STDC__", "1", "__INT64_MAX__", "0x7fffffffffffffffL"), info.getDefinedSymbols());
assertArrayEquals(new String[] { "/usr/local/include", "/usr/include" }, info.getIncludePaths());
assertEquals("pattern1", info.getIncludeExportPatterns().getIncludeExportPattern().pattern());
assertEquals("pattern2", info.getIncludeExportPatterns().getIncludeBeginExportsPattern().pattern());
assertEquals("pattern3", info.getIncludeExportPatterns().getIncludeEndExportsPattern().pattern());
// default values for the rest
assertArrayEquals(new String[0], info.getIncludeFiles());
assertArrayEquals(new String[0], info.getLocalIncludePath());
assertArrayEquals(new String[0], info.getMacroFiles());
assertNotNull(info.getParserSettings());
Container container = new Container();
container.info = info;
String json = createGson.toJson(container);
assertEquals(input.replaceAll("\\s", ""), json);
}
@Test
public void testDefaults() {
String input = "{\"info\":{}}";
Gson createGson = createGson();
Container fromJson = createGson.fromJson(input, Container.class);
ExtendedScannerInfo info = (ExtendedScannerInfo) fromJson.info;
// default values
assertEquals(Map.of(), info.getDefinedSymbols());
assertArrayEquals(new String[0], info.getIncludePaths());
assertNull(info.getIncludeExportPatterns());
assertArrayEquals(new String[0], info.getIncludeFiles());
assertArrayEquals(new String[0], info.getLocalIncludePath());
assertArrayEquals(new String[0], info.getMacroFiles());
assertNotNull(info.getParserSettings());
}
}

View file

@ -98,6 +98,7 @@ Export-Package: org.eclipse.cdt.core,
org.eclipse.cdt.internal.core.pdom.indexer;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.pdom.tag;x-internal:=true,
org.eclipse.cdt.internal.core.resources;x-friends:="org.eclipse.cdt.ui,org.eclipse.cdt.make.core,org.eclipse.cdt.codan.ui.cxx",
org.eclipse.cdt.internal.core.scannerinfo;x-friends:="org.eclipse.cdt.core.tests",
org.eclipse.cdt.internal.core.settings.model;x-internal:=true,
org.eclipse.cdt.internal.core.util;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.errorparsers;x-friends:="org.eclipse.cdt.codan.checkers.ui",
@ -132,7 +133,7 @@ Require-Bundle: org.eclipse.cdt.core.native;bundle-version="[6.0.0,7.0.0)";visib
org.eclipse.ltk.core.refactoring;bundle-version="[3.10.200,4.0.0)",
org.eclipse.osgi.services;bundle-version="[3.8.0,4.0.0)",
org.eclipse.text;bundle-version="[3.9.0,4.0.0)",
com.google.gson,
com.google.gson;bundle-version="[2.8.6,3.0.0)",
org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-11

View file

@ -19,7 +19,6 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Type;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
@ -28,12 +27,11 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
@ -61,12 +59,12 @@ import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.parser.IScannerInfoChangeListener;
import org.eclipse.cdt.core.parser.IncludeExportPatterns;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.internal.core.build.Messages;
import org.eclipse.cdt.internal.core.model.BinaryRunner;
import org.eclipse.cdt.internal.core.model.CModelManager;
import org.eclipse.cdt.internal.core.parser.ParserSettings2;
import org.eclipse.cdt.internal.core.scannerinfo.ExtendedScannerInfoSerializer;
import org.eclipse.cdt.internal.core.scannerinfo.IExtendedScannerInfoDeserializer;
import org.eclipse.cdt.utils.CommandLineUtil;
import org.eclipse.cdt.utils.spawner.EnvironmentReader;
import org.eclipse.core.filesystem.URIUtil;
@ -92,12 +90,6 @@ import org.osgi.service.prefs.Preferences;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
/**
* Root class for CDT build configurations. Provides access to the build
@ -639,63 +631,6 @@ public abstract class CBuildConfiguration extends PlatformObject implements ICBu
.append(getProject().getName()).append(name + ".json").toFile(); //$NON-NLS-1$
}
private static class IExtendedScannerInfoCreator implements JsonDeserializer<IExtendedScannerInfo> {
@Override
public IExtendedScannerInfo deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2)
throws JsonParseException {
JsonObject infoObj = element.getAsJsonObject();
Map<String, String> definedSymbols = null;
if (infoObj.has("definedSymbols")) { //$NON-NLS-1$
JsonObject definedSymbolsObj = infoObj.get("definedSymbols").getAsJsonObject(); //$NON-NLS-1$
definedSymbols = new HashMap<>();
for (Entry<String, JsonElement> entry : definedSymbolsObj.entrySet()) {
definedSymbols.put(entry.getKey(), entry.getValue().getAsString());
}
}
String[] includePaths = null;
if (infoObj.has("includePaths")) { //$NON-NLS-1$
JsonArray includePathsArray = infoObj.get("includePaths").getAsJsonArray(); //$NON-NLS-1$
List<String> includePathsList = new ArrayList<>(includePathsArray.size());
for (Iterator<JsonElement> i = includePathsArray.iterator(); i.hasNext();) {
includePathsList.add(i.next().getAsString());
}
includePaths = includePathsList.toArray(new String[includePathsList.size()]);
}
IncludeExportPatterns includeExportPatterns = null;
if (infoObj.has("includeExportPatterns")) { //$NON-NLS-1$
JsonObject includeExportPatternsObj = infoObj.get("includeExportPatterns").getAsJsonObject(); //$NON-NLS-1$
String exportPattern = null;
if (includeExportPatternsObj.has("includeExportPattern")) { //$NON-NLS-1$
exportPattern = includeExportPatternsObj.get("includeExportPattern") //$NON-NLS-1$
.getAsJsonObject().get("pattern").getAsString(); //$NON-NLS-1$
}
String beginExportsPattern = null;
if (includeExportPatternsObj.has("includeBeginExportPattern")) { //$NON-NLS-1$
beginExportsPattern = includeExportPatternsObj.get("includeBeginExportPattern") //$NON-NLS-1$
.getAsJsonObject().get("pattern").getAsString(); //$NON-NLS-1$
}
String endExportsPattern = null;
if (includeExportPatternsObj.has("includeEndExportPattern")) { //$NON-NLS-1$
endExportsPattern = includeExportPatternsObj.get("includeEndExportPattern") //$NON-NLS-1$
.getAsJsonObject().get("pattern").getAsString(); //$NON-NLS-1$
}
includeExportPatterns = new IncludeExportPatterns(exportPattern, beginExportsPattern,
endExportsPattern);
}
ExtendedScannerInfo info = new ExtendedScannerInfo(definedSymbols, includePaths);
info.setIncludeExportPatterns(includeExportPatterns);
info.setParserSettings(new ParserSettings2());
return info;
}
}
/**
* @since 6.1
*/
@ -705,9 +640,7 @@ public abstract class CBuildConfiguration extends PlatformObject implements ICBu
File cacheFile = getScannerInfoCacheFile();
if (cacheFile.exists()) {
try (FileReader reader = new FileReader(cacheFile)) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(IExtendedScannerInfo.class, new IExtendedScannerInfoCreator());
Gson gson = gsonBuilder.create();
Gson gson = createGson();
scannerInfoCache = gson.fromJson(reader, ScannerInfoCache.class);
} catch (IOException e) {
CCorePlugin.log(e);
@ -721,6 +654,14 @@ public abstract class CBuildConfiguration extends PlatformObject implements ICBu
}
}
private Gson createGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(IExtendedScannerInfo.class, new IExtendedScannerInfoDeserializer());
gsonBuilder.registerTypeAdapter(ExtendedScannerInfo.class, new ExtendedScannerInfoSerializer());
Gson gson = gsonBuilder.create();
return gson;
}
/**
* @since 6.1
*/
@ -736,7 +677,7 @@ public abstract class CBuildConfiguration extends PlatformObject implements ICBu
}
try (FileWriter writer = new FileWriter(getScannerInfoCacheFile())) {
Gson gson = new Gson();
Gson gson = createGson();
synchronized (scannerInfoLock) {
gson.toJson(scannerInfoCache, writer);
}

View file

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.internal.core.scannerinfo;
import java.lang.reflect.Type;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IncludeExportPatterns;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* Serializer for {@link ExtendedScannerInfo}
*
* @see ShadowExtendedScannerInfo
* @see ShadowIncludeExportPatterns
* @see ShadowPattern
*/
public class ExtendedScannerInfoSerializer implements JsonSerializer<ExtendedScannerInfo> {
@Override
public JsonElement serialize(ExtendedScannerInfo info, Type typeOfInfo, JsonSerializationContext context) {
ShadowExtendedScannerInfo shadowInfo = new ShadowExtendedScannerInfo();
IncludeExportPatterns includeExportPatterns = info.getIncludeExportPatterns();
if (includeExportPatterns != null) {
shadowInfo.includeExportPatterns = new ShadowIncludeExportPatterns();
if (includeExportPatterns.getIncludeExportPattern() != null) {
shadowInfo.includeExportPatterns.includeExportPattern = new ShadowPattern(
includeExportPatterns.getIncludeExportPattern().pattern());
}
if (includeExportPatterns.getIncludeBeginExportsPattern() != null) {
shadowInfo.includeExportPatterns.includeBeginExportPattern = new ShadowPattern(
includeExportPatterns.getIncludeBeginExportsPattern().pattern());
}
if (includeExportPatterns.getIncludeEndExportsPattern() != null) {
shadowInfo.includeExportPatterns.includeEndExportPattern = new ShadowPattern(
includeExportPatterns.getIncludeEndExportsPattern().pattern());
}
}
shadowInfo.definedSymbols = info.getDefinedSymbols();
shadowInfo.includePaths = info.getIncludePaths();
return context.serialize(shadowInfo);
}
}

View file

@ -0,0 +1,62 @@
/*******************************************************************************
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.internal.core.scannerinfo;
import java.lang.reflect.Type;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IncludeExportPatterns;
import org.eclipse.cdt.internal.core.parser.ParserSettings2;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
/**
* Deserializer for {@link IExtendedScannerInfo} that deserializes into {@link ExtendedScannerInfo} as the concrete type.
*
* @see ShadowExtendedScannerInfo
* @see ShadowIncludeExportPatterns
* @see ShadowPattern
*/
public class IExtendedScannerInfoDeserializer implements JsonDeserializer<IExtendedScannerInfo> {
@Override
public IExtendedScannerInfo deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
ShadowExtendedScannerInfo shadowInfo = (ShadowExtendedScannerInfo) context.deserialize(element,
ShadowExtendedScannerInfo.class);
ExtendedScannerInfo info = new ExtendedScannerInfo(shadowInfo.definedSymbols, shadowInfo.includePaths);
if (shadowInfo.includeExportPatterns != null) {
String includeExportPattern = null;
String includeBeginExportPattern = null;
String includeEndExportPattern = null;
if (shadowInfo.includeExportPatterns.includeExportPattern != null) {
includeExportPattern = shadowInfo.includeExportPatterns.includeExportPattern.pattern;
}
if (shadowInfo.includeExportPatterns.includeBeginExportPattern != null) {
includeBeginExportPattern = shadowInfo.includeExportPatterns.includeBeginExportPattern.pattern;
}
if (shadowInfo.includeExportPatterns.includeEndExportPattern != null) {
includeEndExportPattern = shadowInfo.includeExportPatterns.includeEndExportPattern.pattern;
}
IncludeExportPatterns patterns = new IncludeExportPatterns(includeExportPattern, includeBeginExportPattern,
includeEndExportPattern);
info.setIncludeExportPatterns(patterns);
}
info.setParserSettings(new ParserSettings2());
return info;
}
}

View file

@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.internal.core.scannerinfo;
import java.util.Map;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
/**
* Shadow version of the classes we are trying to serialize that contain only the info we need.
*
* @see ExtendedScannerInfo
* @see IExtendedScannerInfoDeserializer
* @see ExtendedScannerInfoSerializer
*/
public class ShadowExtendedScannerInfo {
ShadowIncludeExportPatterns includeExportPatterns;
Map<String, String> definedSymbols;
String[] includePaths;
}

View file

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.internal.core.scannerinfo;
import org.eclipse.cdt.core.parser.IncludeExportPatterns;
/**
* Shadow version of the classes we are trying to serialize that contain only the info we need.
*
* @see IncludeExportPatterns
* @see IExtendedScannerInfoDeserializer
* @see ExtendedScannerInfoSerializer
*/
public class ShadowIncludeExportPatterns {
ShadowPattern includeExportPattern;
ShadowPattern includeBeginExportPattern;
ShadowPattern includeEndExportPattern;
}

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2021 Kichwa Coders Canada Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.internal.core.scannerinfo;
import java.util.regex.Pattern;
/**
* Shadow version of the classes we are trying to serialize that contain only the info we need.
*
* To match original implementation of the serialize/deserialize which used {@link Pattern} directly
* we replicate the structure. This is why we don't just use String instead of ShadowPattern
*
* @see Pattern
* @see IExtendedScannerInfoDeserializer
* @see ExtendedScannerInfoSerializer
*/
public class ShadowPattern {
public ShadowPattern(String pattern) {
this.pattern = pattern;
}
String pattern;
}