Skip to content

[GR-44503] Add support for a symbol encoder #11306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/reference-manual/native-image/BuildOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ To fix this, ensure that proper GAV coordinates (Group ID, Artifact ID, and Vers

For more information, see [Software Bill of Materials](../../security/native-image.md).

#### <a name="glossary-obfuscation"></a>Obfuscation
This section indicates whether obfuscation was applied and provides related statistics.
Obfuscation is applied to your application code and third-party dependencies, but not to the JDK or [Substrate VM](https://github.com/oracle/graal/tree/master/substratevm) code.
The following elements are obfuscated: module, package, and class names; method and source file names in stack traces; and field names in heap dumps.
The following elements are not obfuscated: symbols affected by registrations in reachability metadata; modules and packages that contain a class which loads a resource; annotations; lambdas; and proxies.
Use `-H:EnableObfuscation=export-mapping` to export a build artifact containing the mappings from original to obfuscated names.

#### <a name="glossary-backwards-edge-cfi"></a>Backwards-Edge Control-Flow Integrity (CFI)
Control-Flow Integrity (CFI) can be enforced with the experimental `-H:CFI=HW` option.
This feature is currently only available for code compiled by Graal for Linux AArch64 and leverages pointer authentication codes (PAC) to ensure integrity of a function's return address.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2025, 2025, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core;

/**
* Contains constants shared between the driver and the image builder.
*/
public final class SharedConstants {

/**
* The name of the environment variable containing the path to the temporary directory that is
* available during the process lifetime of the Native Image driver.
*/
public static final String DRIVER_TEMP_DIR_ENV_VARIABLE = "DRIVER_TEMP_DIR_ENV_VARIABLE";

/**
* The name of the Java environment variable used to indicate that it is a build initiated due
* to a {@link com.oracle.svm.core.util.ExitStatus#REBUILD_AFTER_ANALYSIS exit status}. The
* environment variable is not set for all other builds.
*/
public static final String REBUILD_AFTER_ANALYSIS_MARKER = "com.oracle.svm.rebuild";
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.Objects;
import java.util.Set;

import com.oracle.svm.core.encoder.SymbolEncoder;
import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.Equivalence;
import org.graalvm.nativeimage.ImageSingletons;
Expand Down Expand Up @@ -127,6 +128,7 @@ protected void recordFrame(ResolvedJavaMethod method, Infopoint infopoint, boole

public abstract static class SourceFieldsFromMethod extends Customization {
private final HostedStringDeduplication stringTable = HostedStringDeduplication.singleton();
private final SymbolEncoder encoder = SymbolEncoder.singleton();

@Override
protected void fillSourceFields(ResolvedJavaMethod method, FrameInfoQueryResult resultFrameInfo) {
Expand All @@ -144,7 +146,7 @@ protected void fillSourceFields(ResolvedJavaMethod method, FrameInfoQueryResult
*/
int sourceMethodModifiers = method.getModifiers();
String methodSignature = method.getSignature().toMethodDescriptor();
String sourceMethodName = stringTable.deduplicate(source.getMethodName(), true);
String sourceMethodName = stringTable.deduplicate(encoder.encodeMethod(source.getMethodName(), sourceClass), true);
String sourceMethodSignature = CodeInfoEncoder.shouldEncodeAllMethodMetadata() ? stringTable.deduplicate(methodSignature, true) : methodSignature;
resultFrameInfo.setSourceFields(sourceClass, sourceMethodName, sourceMethodSignature, sourceMethodModifiers);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025, 2025, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.encoder;

/**
* This encoder returns the symbol names unmodified.
*/
public final class IdentitySymbolEncoder implements SymbolEncoder {
@Override
public String encodeModule(String moduleName) {
return moduleName;
}

@Override
public String encodeClass(String className) {
return className;
}

@Override
public String encodePackage(String packageName) {
return packageName;
}

@Override
public String encodeSourceFile(String sourceFileName, Class<?> clazz) {
return sourceFileName;
}

@Override
public String encodeMethod(String methodName, Class<?> clazz) {
return methodName;
}

@Override
public String encodeField(String fieldName, Class<?> clazz) {
return fieldName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2025, 2025, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.encoder;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

import jdk.graal.compiler.api.replacements.Fold;

/**
* This interface provides hooks to encode the names of modules, packages, classes, source files,
* methods, and fields. Encoding these symbols allows an implementation to control which names are
* present in the image, as well as those included in stack traces and heap dumps.
*/
@Platforms(Platform.HOSTED_ONLY.class)
public interface SymbolEncoder {
String encodeModule(String moduleName);

String encodePackage(String packageName);

String encodeClass(String className);

String encodeSourceFile(String sourceFileName, Class<?> clazz);

String encodeMethod(String methodName, Class<?> clazz);

String encodeField(String fieldName, Class<?> clazz);

@Fold
static SymbolEncoder singleton() {
return ImageSingletons.lookup(SymbolEncoder.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2025, 2025, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.encoder;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;

/**
* Ensures that the {@link IdentitySymbolEncoder} is used.
*/
@AutomaticallyRegisteredFeature
public class SymbolEncoderFeature implements InternalFeature {
@Override
public void afterRegistration(AfterRegistrationAccess access) {
registerIdentityStringEncoder();
}

protected void registerIdentityStringEncoder() {
ImageSingletons.add(SymbolEncoder.class, new IdentitySymbolEncoder());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@

import java.lang.reflect.Modifier;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.BooleanSupplier;

import org.graalvm.collections.EconomicMap;
Expand Down Expand Up @@ -280,6 +282,16 @@ public static Class<?> forNameOrNull(String className, ClassLoader classLoader)
}
}

@Platforms(Platform.HOSTED_ONLY.class)
public Set<String> getKnownClassNames() {
EconomicMap<String, ?> map = respectClassLoader() ? knownClassNames : knownClasses;
Set<String> set = new HashSet<>(map.size());
for (String key : map.getKeys()) {
set.add(key);
}
return set;
}

public static Class<?> forName(String className, ClassLoader classLoader) throws ClassNotFoundException {
return forName(className, classLoader, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import com.oracle.svm.core.encoder.SymbolEncoder;
import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.MapCursor;
import org.graalvm.nativeimage.ImageInfo;
Expand Down Expand Up @@ -89,6 +90,7 @@ public final class Resources implements MultiLayeredImageSingleton, UnsavedSingl

private static final int INVALID_TIMESTAMP = -1;
public static final char RESOURCES_INTERNAL_PATH_SEPARATOR = '/';
private final SymbolEncoder encoder = SymbolEncoder.singleton();

/**
* @return the singleton corresponding to this layer's resources in a layered build, the unique
Expand Down Expand Up @@ -180,6 +182,11 @@ public Iterable<ConditionalRuntimeValue<ResourceStorageEntryBase>> resources() {
return resources.getValues();
}

@Platforms(Platform.HOSTED_ONLY.class)
public Iterable<ModuleResourceKey> resourceKeys() {
return resources.getKeys();
}

@Platforms(Platform.HOSTED_ONLY.class)
public int count() {
return resources.size();
Expand Down Expand Up @@ -318,7 +325,7 @@ public void registerIncludePattern(ConfigurationCondition condition, String modu
assert MissingRegistrationUtils.throwMissingRegistrationErrors();
synchronized (requestedPatterns) {
updateTimeStamp();
requestedPatterns.put(new RequestedPattern(module, handleEscapedCharacters(pattern)), RuntimeConditionSet.createHosted(condition));
requestedPatterns.put(new RequestedPattern(encoder.encodeModule(module), handleEscapedCharacters(pattern)), RuntimeConditionSet.createHosted(condition));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import com.oracle.svm.core.encoder.SymbolEncoder;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
Expand Down Expand Up @@ -88,9 +89,10 @@ public void enableServiceCatalogMapTransformer(Feature.BeforeAnalysisAccess acce
var omittedProviders = omittedServiceProviders.get(service);
providers = providers.stream()
.filter(p -> !omittedProviders.contains(p))
.collect(Collectors.toList());
.toList();
}
return providers;
SymbolEncoder encoder = SymbolEncoder.singleton();
return providers.stream().map(encoder::encodeClass).toList();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public enum ExitStatus {
DRIVER_ERROR(20),
DRIVER_TO_BUILDER_ERROR(21),
WATCHDOG_EXIT(30),
REBUILD_AFTER_ANALYSIS(40),
MISSING_METADATA(172),
UNKNOWN(255);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,21 @@
public class InterruptImageBuilding extends RuntimeException {
static final long serialVersionUID = 754312906378380L;
private final boolean hasMessage;
private final ExitStatus exitStatus;

/**
* Print an error message upon exit.
*
* @param message reason for interruption.
*/
public InterruptImageBuilding(String message) {
this(null, message);
}

public InterruptImageBuilding(ExitStatus exitStatus, String message) {
super(message);
this.hasMessage = true;
this.exitStatus = exitStatus;
}

/**
Expand All @@ -56,6 +62,7 @@ public InterruptImageBuilding(String message) {
public InterruptImageBuilding(Throwable cause) {
super(cause);
this.hasMessage = cause != null && cause.getMessage() != null;
this.exitStatus = null;
}

/**
Expand All @@ -68,4 +75,8 @@ public InterruptImageBuilding() {
public Optional<String> getReason() {
return hasMessage ? Optional.of(getMessage()) : Optional.empty();
}

public Optional<ExitStatus> getExitStatus() {
return Optional.ofNullable(exitStatus);
}
}
Loading
Loading