Skip to content

Commit dd7d654

Browse files
committed
Test with Unsafe disabled
1 parent 28cd73b commit dd7d654

File tree

8 files changed

+376
-0
lines changed

8 files changed

+376
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
From f371066409daaf55739eb60e1ef0d9f42b21ac2a Mon Sep 17 00:00:00 2001
2+
From: Trask Stalnaker <[email protected]>
3+
Date: Sat, 20 Sep 2025 15:36:51 -0700
4+
Subject: [PATCH] Remove JCTools
5+
6+
---
7+
.../java/com/linecorp/armeria/common/ExceptionSampler.java | 5 ++---
8+
.../linecorp/armeria/common/stream/DefaultStreamMessage.java | 4 ++--
9+
core/src/main/java/com/linecorp/armeria/server/Server.java | 4 ++--
10+
3 files changed, 6 insertions(+), 7 deletions(-)
11+
12+
diff --git a/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java b/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java
13+
index 87afd2074..b5c1c2470 100644
14+
--- a/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java
15+
+++ b/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java
16+
@@ -18,10 +18,9 @@ package com.linecorp.armeria.common;
17+
import static java.util.Objects.requireNonNull;
18+
19+
import java.util.Map;
20+
+import java.util.concurrent.ConcurrentHashMap;
21+
import java.util.function.Function;
22+
23+
-import org.jctools.maps.NonBlockingHashMap;
24+
-
25+
import com.google.common.base.MoreObjects;
26+
27+
import com.linecorp.armeria.common.util.Sampler;
28+
@@ -29,7 +28,7 @@ import com.linecorp.armeria.common.util.Sampler;
29+
final class ExceptionSampler implements Sampler<Class<? extends Throwable>> {
30+
31+
private final Map<Class<? extends Throwable>, Sampler<Class<? extends Throwable>>> samplers =
32+
- new NonBlockingHashMap<>();
33+
+ new ConcurrentHashMap<>();
34+
private final Function<? super Class<? extends Throwable>,
35+
? extends Sampler<Class<? extends Throwable>>> samplerFactory;
36+
private final String spec;
37+
diff --git a/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java b/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java
38+
index e9328f03e..12173e999 100644
39+
--- a/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java
40+
+++ b/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java
41+
@@ -22,9 +22,9 @@ import static java.util.Objects.requireNonNull;
42+
43+
import java.util.Queue;
44+
import java.util.concurrent.CompletableFuture;
45+
+import java.util.concurrent.ConcurrentLinkedQueue;
46+
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
47+
48+
-import org.jctools.queues.MpscChunkedArrayQueue;
49+
import org.reactivestreams.Subscriber;
50+
import org.slf4j.Logger;
51+
import org.slf4j.LoggerFactory;
52+
@@ -109,7 +109,7 @@ public class DefaultStreamMessage<T> extends AbstractStreamWriter<T> {
53+
*/
54+
@Deprecated
55+
public DefaultStreamMessage() {
56+
- queue = new MpscChunkedArrayQueue<>(INITIAL_CAPACITY, 1 << 30);
57+
+ queue = new ConcurrentLinkedQueue<>();
58+
}
59+
60+
@Override
61+
diff --git a/core/src/main/java/com/linecorp/armeria/server/Server.java b/core/src/main/java/com/linecorp/armeria/server/Server.java
62+
index 6b8b0b557..0c3eed942 100644
63+
--- a/core/src/main/java/com/linecorp/armeria/server/Server.java
64+
+++ b/core/src/main/java/com/linecorp/armeria/server/Server.java
65+
@@ -37,6 +37,7 @@ import java.util.Set;
66+
import java.util.concurrent.CompletableFuture;
67+
import java.util.concurrent.CompletionException;
68+
import java.util.concurrent.CompletionStage;
69+
+import java.util.concurrent.ConcurrentHashMap;
70+
import java.util.concurrent.ExecutionException;
71+
import java.util.concurrent.Executor;
72+
import java.util.concurrent.ExecutorService;
73+
@@ -51,7 +52,6 @@ import java.util.stream.Collectors;
74+
75+
import javax.net.ssl.SSLSession;
76+
77+
-import org.jctools.maps.NonBlockingHashSet;
78+
import org.slf4j.Logger;
79+
import org.slf4j.LoggerFactory;
80+
81+
@@ -119,7 +119,7 @@ public final class Server implements ListenableAsyncCloseable {
82+
83+
private final UpdatableServerConfig config;
84+
private final StartStopSupport<Void, Void, Void, ServerListener> startStop;
85+
- private final Set<ServerChannel> serverChannels = new NonBlockingHashSet<>();
86+
+ private final Set<ServerChannel> serverChannels = ConcurrentHashMap.newKeySet();
87+
private final ReentrantLock lock = new ReentrantShortLock();
88+
@GuardedBy("lock")
89+
private final Map<InetSocketAddress, ServerPort> activePorts = new LinkedHashMap<>();
90+
--
91+
2.51.0.windows.1
92+
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
From d6276724f7f432af4693e9d786ecfcaddb73e505 Mon Sep 17 00:00:00 2001
2+
From: Trask Stalnaker <[email protected]>
3+
Date: Sat, 20 Sep 2025 21:48:43 -0700
4+
Subject: [PATCH] Update Caffeine
5+
6+
---
7+
.../src/main/java/com/linecorp/armeria/common/Flags.java | 2 +-
8+
.../armeria/internal/common/util/CertificateUtil.java | 9 ++++++---
9+
.../linecorp/armeria/server/file/FileServiceConfig.java | 2 +-
10+
dependencies.toml | 5 ++---
11+
gradle.properties | 4 ++--
12+
5 files changed, 12 insertions(+), 10 deletions(-)
13+
14+
diff --git a/core/src/main/java/com/linecorp/armeria/common/Flags.java b/core/src/main/java/com/linecorp/armeria/common/Flags.java
15+
index 57671a686..e1dd6eb3b 100644
16+
--- a/core/src/main/java/com/linecorp/armeria/common/Flags.java
17+
+++ b/core/src/main/java/com/linecorp/armeria/common/Flags.java
18+
@@ -1722,7 +1722,7 @@ public final class Flags {
19+
if ("off".equals(value)) {
20+
return allowOff;
21+
}
22+
- CaffeineSpec.parse(value);
23+
+ var unused = CaffeineSpec.parse(value);
24+
return true;
25+
} catch (Exception e) {
26+
return false;
27+
diff --git a/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java b/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java
28+
index a343428a3..48698e3ea 100644
29+
--- a/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java
30+
+++ b/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java
31+
@@ -57,6 +57,8 @@ public final class CertificateUtil {
32+
33+
private static final Logger logger = LoggerFactory.getLogger(CertificateUtil.class);
34+
35+
+ private static final String NO_HOSTNAME_FOUND = "<NO_HOSTNAME_FOUND>";
36+
+
37+
private static final LoadingCache<X509Certificate, String> hostnameCache =
38+
Caffeine.newBuilder()
39+
.weakKeys()
40+
@@ -73,11 +75,11 @@ public final class CertificateUtil {
41+
42+
logger.warn("No common name or subject alternative name found " +
43+
"in certificate: {}", cert);
44+
- return null;
45+
+ return NO_HOSTNAME_FOUND;
46+
} catch (Exception e) {
47+
logger.warn("Failed to get the common name or subject alternative name name " +
48+
"from a certificate: {}", cert, e);
49+
- return null;
50+
+ return NO_HOSTNAME_FOUND;
51+
}
52+
});
53+
54+
@@ -136,7 +138,8 @@ public final class CertificateUtil {
55+
if (!(certificate instanceof X509Certificate)) {
56+
return null;
57+
}
58+
- return hostnameCache.get((X509Certificate) certificate);
59+
+ final String hostname = hostnameCache.get((X509Certificate) certificate);
60+
+ return NO_HOSTNAME_FOUND.equals(hostname) ? null : hostname;
61+
}
62+
63+
public static List<X509Certificate> toX509Certificates(File file) throws CertificateException {
64+
diff --git a/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java b/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java
65+
index 8766acd95..b6b8a1b62 100644
66+
--- a/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java
67+
+++ b/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java
68+
@@ -72,7 +72,7 @@ public final class FileServiceConfig {
69+
return null;
70+
}
71+
try {
72+
- CaffeineSpec.parse(entryCacheSpec);
73+
+ var unused = CaffeineSpec.parse(entryCacheSpec);
74+
} catch (Exception e) {
75+
throw new IllegalArgumentException("invalid cache spec: " + entryCacheSpec, e);
76+
}
77+
diff --git a/dependencies.toml b/dependencies.toml
78+
index 22c366f47..bfd54bcce 100644
79+
--- a/dependencies.toml
80+
+++ b/dependencies.toml
81+
@@ -15,8 +15,7 @@ brave6 = "6.3.0"
82+
brotli4j = "1.18.0"
83+
# Don"t upgrade bucket4j to 7.6.1 or 8.x that requires Java 11. The module name also has been changed to "com.bucket4j"
84+
bucket4j = "7.6.0"
85+
-# Don"t upgrade Caffeine to 3.x that requires Java 11.
86+
-caffeine = "2.9.3"
87+
+caffeine = "3.2.2"
88+
cglib = "3.3.0"
89+
checkerframework = "2.5.6"
90+
checkstyle = "10.3.2"
91+
@@ -325,7 +324,7 @@ javadocs = "https://javadoc.io/doc/com.github.vladimir-bukhtoyarov/bucket4j-core
92+
module = "com.github.ben-manes.caffeine:caffeine"
93+
version.ref = "caffeine"
94+
exclusions = "com.google.errorprone:error_prone_annotations"
95+
-javadocs = "https://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/2.9.3/"
96+
+javadocs = "https://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/3.2.2/"
97+
relocations = { from = "com.github.benmanes.caffeine", to = "com.linecorp.armeria.internal.shaded.caffeine" }
98+
99+
[libraries.cglib]
100+
diff --git a/gradle.properties b/gradle.properties
101+
index de5b05013..5ab06b436 100644
102+
--- a/gradle.properties
103+
+++ b/gradle.properties
104+
@@ -12,8 +12,8 @@ licenseUrl=https://www.apache.org/license/LICENSE-2.0.txt
105+
scmUrl=https://github.com/line/armeria
106+
scmConnection=scm:git:https://github.com/line/armeria.git
107+
scmDeveloperConnection=scm:git:ssh://[email protected]/line/armeria.git
108+
-javaSourceCompatibility=1.8
109+
-javaTargetCompatibility=1.8
110+
+javaSourceCompatibility=11
111+
+javaTargetCompatibility=11
112+
publishUrlForRelease=https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/
113+
publishUrlForSnapshot=https://central.sonatype.com/repository/maven-snapshots/
114+
publishUsernameProperty=ossrhUsername
115+
--
116+
2.51.0.windows.1
117+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
set -e
3+
4+
VERSION="1.33.3"
5+
CURR_DIR="$(pwd)"
6+
7+
cd "$(mktemp -d)"
8+
9+
# Clone Armeria repository
10+
git clone --depth 1 --branch "armeria-${VERSION}" https://github.com/line/armeria.git
11+
12+
cd armeria
13+
14+
# Apply patch to remove Unsafe usage
15+
git apply "${CURR_DIR}/.github/unsafe/armeria-remove-JCTools.patch"
16+
git apply "${CURR_DIR}/.github/unsafe/armeria-update-Caffeine.patch"
17+
18+
# Build the core module (shaded JAR includes all dependencies)
19+
./gradlew :core:shadedJar -x javadoc -x :docs-client:nodeSetup -x :docs-client:npmSetup -x :docs-client:npmInstall -x :docs-client:eslint -x :docs-client:lint -x :docs-client:buildWeb -x :docs-client:copyWeb
20+
21+
# Download the original POM file
22+
curl -sL -o "armeria-${VERSION}.pom" "https://repo1.maven.org/maven2/com/linecorp/armeria/armeria/${VERSION}/armeria-${VERSION}.pom"
23+
24+
# Install core JAR to Maven local repository with POM
25+
mvn install:install-file -q \
26+
-Dfile="core/build/libs/armeria-untrimmed-${VERSION}.jar" \
27+
-DpomFile="armeria-${VERSION}.pom"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
set -e
3+
4+
VERSION="4.32.1"
5+
6+
cd "$(mktemp -d)"
7+
8+
# Download original artifact and extract
9+
curl -sL -o "protobuf-java-${VERSION}.jar" "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/${VERSION}/protobuf-java-${VERSION}.jar"
10+
11+
# Extract JAR
12+
mkdir classes
13+
cd classes
14+
jar -xf "../protobuf-java-${VERSION}.jar"
15+
cd ..
16+
17+
# Clone protobuf repository
18+
git clone --depth 1 --branch "v32.1" https://github.com/protocolbuffers/protobuf.git
19+
20+
# Apply patch to remove Unsafe usage
21+
sed -i 's/private static final sun\.misc\.Unsafe UNSAFE = getUnsafe();/private static final sun.misc.Unsafe UNSAFE = null;/' protobuf/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
22+
23+
# Compile modified classes
24+
javac -cp protobuf-java-${VERSION}.jar -d classes protobuf/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
25+
26+
# Create new JAR with modified classes
27+
jar -cf "protobuf-java-${VERSION}.jar" -C classes .
28+
29+
# Download the original POM file
30+
curl -sL -o "protobuf-java-${VERSION}.pom" "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/${VERSION}/protobuf-java-${VERSION}.pom"
31+
32+
# Install to Maven local repository with POM
33+
mvn install:install-file -q \
34+
-Dfile="protobuf-java-${VERSION}.jar" \
35+
-DpomFile="protobuf-java-${VERSION}.pom"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Move mavenLocal() before mavenCentral() in the repositories block
5+
sed -i '/repositories {/,/}/ {
6+
/mavenCentral()/d
7+
/mavenLocal()/d
8+
/repositories {/a\ mavenLocal()
9+
/repositories {/a\ mavenCentral()
10+
}' "settings.gradle.kts"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Add Java 11 compile target and disruptor version update to opencensus-shim build file
5+
cat >> opencensus-shim/build.gradle.kts << 'EOF'
6+
7+
tasks.withType<JavaCompile>().configureEach {
8+
options.release.set(11)
9+
}
10+
11+
configurations.all {
12+
resolutionStrategy.force("com.lmax:disruptor:4.0.0")
13+
}
14+
EOF
15+
16+
# Add targeted disruptor fix to exporters/otlp/all for JdkHttpSender tests
17+
if ! grep -q "resolutionStrategy.force.*disruptor.*4.0.0" exporters/otlp/all/build.gradle.kts; then
18+
# Replace the existing afterEvaluate block with the complete version
19+
sed -i '/afterEvaluate {/,/^}$/c\
20+
afterEvaluate {\
21+
tasks.named<JavaCompile>("compileTestJdkHttpSenderJava") {\
22+
options.release.set(11)\
23+
}\
24+
\
25+
// Force disruptor 4.0.0 for JdkHttpSender tests to prevent conflicts with mockserver\
26+
configurations.named("testJdkHttpSenderRuntimeClasspath") {\
27+
resolutionStrategy.force("com.lmax:disruptor:4.0.0")\
28+
}\
29+
}' exporters/otlp/all/build.gradle.kts
30+
fi

.github/workflows/unsafe.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Unsafe disabled test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- release/*
8+
pull_request:
9+
workflow_dispatch:
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
13+
cancel-in-progress: true
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
unsafe-disabled-test:
20+
name: Unsafe disabled test
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
24+
25+
- id: setup-java-test
26+
name: Set up Java 24 for tests
27+
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
28+
with:
29+
distribution: temurin
30+
java-version: 24
31+
32+
- id: setup-java
33+
name: Set up Java for build
34+
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
35+
with:
36+
distribution: temurin
37+
java-version: 17
38+
39+
- name: Set up gradle
40+
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
41+
42+
- name: Build custom protobuf-java that doesn't require Unsafe
43+
run: ./.github/unsafe/build-custom-protobuf.sh
44+
45+
- name: Build custom armeria that doesn't require Unsafe
46+
run: ./.github/unsafe/build-custom-armeria.sh
47+
48+
- name: Prioritize Maven local repository to pick up custom builds
49+
run: ./.github/unsafe/prioritize-maven-local.sh
50+
51+
- name: Update to LMAX Disruptor version that doesn't require Unsafe
52+
run: ./.github/unsafe/update-lmax-disruptor.sh
53+
54+
- name: Build and test
55+
run: >
56+
./gradlew build
57+
-PtestJavaVersion=24
58+
-PunsafeDisabled=true
59+
"-Porg.gradle.java.installations.paths=${{ steps.setup-java-test.outputs.path }}"
60+
"-Porg.gradle.java.installations.auto-download=false"

buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ dependencyCheck {
7070
}
7171

7272
val testJavaVersion = gradle.startParameter.projectProperties.get("testJavaVersion")?.let(JavaVersion::toVersion)
73+
val unsafeDisabled = gradle.startParameter.projectProperties.get("unsafeDisabled")?.toBoolean() ?: false
7374

7475
tasks {
7576
withType<JavaCompile>().configureEach {
@@ -114,6 +115,10 @@ tasks {
114115
)
115116
}
116117

118+
if (unsafeDisabled) {
119+
jvmArgs("--sun-misc-unsafe-memory-access=deny")
120+
}
121+
117122
val defaultMaxRetries = if (System.getenv().containsKey("CI")) 2 else 0
118123
val maxTestRetries = gradle.startParameter.projectProperties["maxTestRetries"]?.toInt() ?: defaultMaxRetries
119124

0 commit comments

Comments
 (0)