From a7bc535e12a5a2dbe7e95497e4d3811f28de0768 Mon Sep 17 00:00:00 2001 From: Roman Puchkovskiy Date: Mon, 7 Dec 2020 21:16:30 +0400 Subject: [PATCH] Fix native image build for the cases when io.netty.util.NetUtil is initialized at run-time (#10799) Motivation: In #10630, field substitutions were introduced for NetUtil.LOCALHOST4, NetUtil.LOCALHOST6 and NetUtil.LOCALHOST fields. They were required to allow a native image be built with most of Netty (including NetUtil) initialized at build time. The substitutions created in #10630 only define getters, so the 3 fields can only be read in a native image. But when NetUtil is initialized at run-time (this is what happens in #10797), its static initialization block is executed, and this block writes to all 3 fields. As the substitutions do not provide any setters, field stores are not valid, and such builds fail. Modifications: - Add netty-testsuite-native-image-client-runtime-init Maven module that builds a native image deferring NetUtil class initialization till run-time; this module is used to demonstrate the problem and verify the problem is gone with the fix - Add no-op setters to substitutions for NetUtil.LOCALHOST4, NetUtil.LOCALHOST6 and NetUtil.LOCALHOST Result: A native image initializing NetUtil at run-time builds successfully. Fixes #10797 --- .../io/netty/util/NetUtilSubstitutions.java | 12 +++ pom.xml | 1 + .../pom.xml | 100 ++++++++++++++++++ .../NativeClientWithNettyInitAtRuntime.java | 36 +++++++ .../testsuite/svm/client/package-info.java | 21 ++++ .../testsuite/svm/client/package-info.java | 2 +- 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 testsuite-native-image-client-runtime-init/pom.xml create mode 100644 testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/NativeClientWithNettyInitAtRuntime.java create mode 100644 testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/package-info.java diff --git a/common/src/main/java/io/netty/util/NetUtilSubstitutions.java b/common/src/main/java/io/netty/util/NetUtilSubstitutions.java index 9d9740392c..7894037e4e 100644 --- a/common/src/main/java/io/netty/util/NetUtilSubstitutions.java +++ b/common/src/main/java/io/netty/util/NetUtilSubstitutions.java @@ -45,6 +45,10 @@ final class NetUtilSubstitutions { // using https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom return NetUtilLocalhost4LazyHolder.LOCALHOST4; } + + static void set(Inet4Address ignored) { + // a no-op setter to avoid exceptions when NetUtil is initialized at run-time + } } private static final class NetUtilLocalhost4LazyHolder { @@ -56,6 +60,10 @@ final class NetUtilSubstitutions { // using https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom return NetUtilLocalhost6LazyHolder.LOCALHOST6; } + + static void set(Inet6Address ignored) { + // a no-op setter to avoid exceptions when NetUtil is initialized at run-time + } } private static final class NetUtilLocalhost6LazyHolder { @@ -67,6 +75,10 @@ final class NetUtilSubstitutions { // using https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom return NetUtilLocalhostLazyHolder.LOCALHOST; } + + static void set(InetAddress ignored) { + // a no-op setter to avoid exceptions when NetUtil is initialized at run-time + } } private static final class NetUtilLocalhostLazyHolder { diff --git a/pom.xml b/pom.xml index ac6351d37a..380379b577 100644 --- a/pom.xml +++ b/pom.xml @@ -396,6 +396,7 @@ testsuite-shading testsuite-native-image testsuite-native-image-client + testsuite-native-image-client-runtime-init transport-blockhound-tests microbench bom diff --git a/testsuite-native-image-client-runtime-init/pom.xml b/testsuite-native-image-client-runtime-init/pom.xml new file mode 100644 index 0000000000..1721c37979 --- /dev/null +++ b/testsuite-native-image-client-runtime-init/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 5.0.0.Final-SNAPSHOT + + + netty-testsuite-native-image-client-runtime-init + jar + + Netty/Testsuite/NativeImage/ClientRuntimeInit + + + true + + + + + ${project.groupId} + netty-common + ${project.version} + + + + + + skipTests + + + skipTests + + + + true + + + + + + + + com.oracle.substratevm + native-image-maven-plugin + ${graalvm.version} + + + + native-image + + package + + + + ${skipNativeImageTestsuite} + ${project.artifactId} + io.netty.testsuite.svm.client.NativeClientWithNettyInitAtRuntime + --report-unsupported-elements-at-runtime --allow-incomplete-classpath --no-fallback --initialize-at-run-time=io.netty.util.NetUtil + + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + + + + verify-native-image + verify + + exec + + + + + ${skipNativeImageTestsuite} + ${project.build.directory}/${project.artifactId} + + + + + diff --git a/testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/NativeClientWithNettyInitAtRuntime.java b/testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/NativeClientWithNettyInitAtRuntime.java new file mode 100644 index 0000000000..6c4aa22ba8 --- /dev/null +++ b/testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/NativeClientWithNettyInitAtRuntime.java @@ -0,0 +1,36 @@ +/* + * Copyright 2020 The Netty Project + * + * The Netty Project 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: + * + * https://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 io.netty.testsuite.svm.client; + +import io.netty.util.NetUtil; + +/** + * A client that triggers runtime initialization of NetUtil when + * built to a native image. + */ +public final class NativeClientWithNettyInitAtRuntime { + /** + * Main entry point (not instantiable) + */ + private NativeClientWithNettyInitAtRuntime() { + } + + public static void main(String[] args) { + System.out.println(NetUtil.LOCALHOST4); + System.out.println(NetUtil.LOCALHOST6); + System.out.println(NetUtil.LOCALHOST); + } +} diff --git a/testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/package-info.java b/testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/package-info.java new file mode 100644 index 0000000000..c5d8a74b31 --- /dev/null +++ b/testsuite-native-image-client-runtime-init/src/main/java/io/netty/testsuite/svm/client/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 The Netty Project + * + * The Netty Project 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: + * + * https://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. + */ + +/** + * A client that triggers runtime initialization of NetUtil when + * built to a native image. + */ +package io.netty.testsuite.svm.client; diff --git a/testsuite-native-image-client/src/main/java/io/netty/testsuite/svm/client/package-info.java b/testsuite-native-image-client/src/main/java/io/netty/testsuite/svm/client/package-info.java index 0426d41985..7b575e6835 100644 --- a/testsuite-native-image-client/src/main/java/io/netty/testsuite/svm/client/package-info.java +++ b/testsuite-native-image-client/src/main/java/io/netty/testsuite/svm/client/package-info.java @@ -15,6 +15,6 @@ */ /** - * A hello world server that should be compiled to native. + * A client that uses netty-dns and gets compiled to a native image. */ package io.netty.testsuite.svm.client;