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
This commit is contained in:
Roman Puchkovskiy 2020-12-07 21:16:30 +04:00 committed by Norman Maurer
parent 591b0f69bc
commit a7bc535e12
6 changed files with 171 additions and 1 deletions

View File

@ -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 {

View File

@ -396,6 +396,7 @@
<module>testsuite-shading</module>
<module>testsuite-native-image</module>
<module>testsuite-native-image-client</module>
<module>testsuite-native-image-client-runtime-init</module>
<module>transport-blockhound-tests</module>
<module>microbench</module>
<module>bom</module>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.netty</groupId>
<artifactId>netty-parent</artifactId>
<version>5.0.0.Final-SNAPSHOT</version>
</parent>
<artifactId>netty-testsuite-native-image-client-runtime-init</artifactId>
<packaging>jar</packaging>
<name>Netty/Testsuite/NativeImage/ClientRuntimeInit</name>
<properties>
<skipJapicmp>true</skipJapicmp>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>skipTests</id>
<activation>
<property>
<name>skipTests</name>
</property>
</activation>
<properties>
<skipNativeImageTestsuite>true</skipNativeImageTestsuite>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>com.oracle.substratevm</groupId>
<artifactId>native-image-maven-plugin</artifactId>
<version>${graalvm.version}</version>
<executions>
<execution>
<goals>
<goal>native-image</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<skip>${skipNativeImageTestsuite}</skip>
<imageName>${project.artifactId}</imageName>
<mainClass>io.netty.testsuite.svm.client.NativeClientWithNettyInitAtRuntime</mainClass>
<buildArgs>--report-unsupported-elements-at-runtime --allow-incomplete-classpath --no-fallback --initialize-at-run-time=io.netty.util.NetUtil</buildArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<!-- This will do a whitesmoke test: if the substitutions are missing the binary will fail to run -->
<!-- If the metadata is missing the build above will fail -->
<execution>
<id>verify-native-image</id>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>${skipNativeImageTestsuite}</skip>
<executable>${project.build.directory}/${project.artifactId}</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;