Skip to content
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
28 changes: 28 additions & 0 deletions .github/workflows/test_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ jobs:
name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64
path: /tmp/signal-safety-violation.txt
if-no-files-found: ignore
- name: Upload ASan logs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && matrix.config == 'asan'
with:
name: asan-logs-glibc-${{ matrix.java_version }}-amd64
path: /tmp/asan.log.*
if-no-files-found: ignore

test-linux-musl-amd64:
needs: [cache-jdks, filter-musl-configs]
Expand Down Expand Up @@ -317,6 +324,13 @@ jobs:
name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64
path: /tmp/signal-safety-violation.txt
if-no-files-found: ignore
- name: Upload ASan logs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && matrix.config == 'asan'
with:
name: asan-logs-musl-${{ matrix.java_version }}-amd64
path: /tmp/asan.log.*
if-no-files-found: ignore

test-linux-glibc-aarch64:
needs: cache-jdks
Expand Down Expand Up @@ -495,6 +509,13 @@ jobs:
name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64
path: /tmp/signal-safety-violation.txt
if-no-files-found: ignore
- name: Upload ASan logs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && matrix.config == 'asan'
with:
name: asan-logs-glibc-${{ matrix.java_version }}-aarch64
path: /tmp/asan.log.*
if-no-files-found: ignore

test-linux-musl-aarch64:
needs: [cache-jdks, filter-musl-configs]
Expand Down Expand Up @@ -599,3 +620,10 @@ jobs:
name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64
path: /tmp/signal-safety-violation.txt
if-no-files-found: ignore
- name: Upload ASan logs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && matrix.config == 'asan'
with:
name: asan-logs-musl-${{ matrix.java_version }}-aarch64
path: /tmp/asan.log.*
if-no-files-found: ignore
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,22 @@ object ConfigurationPresets {
if (libasan != null) {
config.testEnvironment.apply {
put("LD_PRELOAD", libasan)
put("ASAN_OPTIONS", "allocator_may_return_null=1:unwind_abort_on_malloc=1:use_sigaltstack=0:detect_stack_use_after_return=0:handle_segv=0:halt_on_error=0:abort_on_error=0:print_stacktrace=1:symbolize=1:suppressions=$rootDir/gradle/sanitizers/asan.supp")
put("ASAN_OPTIONS", "allocator_may_return_null=1:unwind_abort_on_malloc=1:use_sigaltstack=0:detect_stack_use_after_return=0:handle_segv=0:halt_on_error=0:abort_on_error=0:print_stacktrace=1:symbolize=1:log_path=/tmp/asan.log:suppressions=$rootDir/gradle/sanitizers/asan.supp")
put("UBSAN_OPTIONS", "halt_on_error=0:abort_on_error=0:print_stacktrace=1:suppressions=$rootDir/gradle/sanitizers/ubsan.supp")
put("LSAN_OPTIONS", "detect_leaks=0")
}
// JDK 25's G1GC reserves heap virtual address space starting just below 2 GB
// (0x7fff7000), which is exactly where ASan needs to mmap its shadow bytes
// [0x7fff7000-0x10007fff7fff]. Force the heap to a very low base address so
// the entire JVM footprint (heap + class space + code cache) stays well below
// the shadow range and the two regions no longer conflict.
if (PlatformUtils.testJvmMajorVersion() >= 25) {
config.testJvmArgs.addAll(listOf(
"-XX:HeapBaseMinAddress=0x4000000",
"-Xmx512m",
"-XX:CompressedClassSpaceSize=256m"
))
}
}
}
Platform.MACOS -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ abstract class BuildConfiguration @Inject constructor(
abstract val compilerArgs: ListProperty<String>
abstract val linkerArgs: ListProperty<String>
abstract val testEnvironment: MapProperty<String, String>
abstract val testJvmArgs: ListProperty<String>
abstract val active: Property<Boolean>

override fun getName(): String = configName
Expand All @@ -23,6 +24,7 @@ abstract class BuildConfiguration @Inject constructor(
// Default to active unless overridden
active.convention(true)
testEnvironment.convention(emptyMap())
testJvmArgs.convention(emptyList())
}

fun isActiveFor(targetPlatform: Platform, targetArch: Architecture): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,24 @@ object PlatformUtils {
false
}
}

/**
* Returns the major version of the test JVM (e.g. 8, 11, 17, 21, 25).
* Returns 0 if the version cannot be determined.
*/
fun testJvmMajorVersion(): Int {
val javaHome = testJavaHome()
return try {
val process = ProcessBuilder("$javaHome/bin/java", "-version")
.redirectErrorStream(true)
.start()
val output = process.inputStream.bufferedReader().readText()
process.waitFor(10, TimeUnit.SECONDS)
// version line: java version "1.8.0_xxx" or java version "21.0.x" etc.
val match = Regex("""version "(?:1\.)?(\d+)""").find(output)
match?.groupValues?.get(1)?.toIntOrNull() ?: 0
Comment on lines +378 to +385
} catch (_: Exception) {
0
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class ProfilerTestPlugin : Plugin<Project> {
val testClasspath: FileCollection,
val standardJvmArgs: List<String>,
val extraJvmArgs: List<String>,
val configJvmArgs: List<String>,
val systemProperties: Map<String, String>,
val environmentVariables: Map<String, String>
)
Expand Down Expand Up @@ -164,6 +165,7 @@ class ProfilerTestPlugin : Plugin<Project> {
testClasspath = testClasspath,
standardJvmArgs = extension.standardJvmArgs.get(),
extraJvmArgs = extension.extraJvmArgs.get(),
configJvmArgs = config.testJvmArgs.get(),
systemProperties = systemProps,
environmentVariables = envVars
)
Expand Down Expand Up @@ -247,6 +249,7 @@ class ProfilerTestPlugin : Plugin<Project> {
}

allArgs.addAll(testConfig.extraJvmArgs)
allArgs.addAll(testConfig.configJvmArgs)
testTask.jvmArgs(allArgs)
}

Expand Down Expand Up @@ -303,6 +306,7 @@ class ProfilerTestPlugin : Plugin<Project> {
allArgs.add("-Djava.library.path=${extension.nativeLibDir.get().asFile.absolutePath}")
}
allArgs.addAll(testConfig.extraJvmArgs)
allArgs.addAll(testConfig.configJvmArgs)

// System properties
testConfig.systemProperties.forEach { (key, value) ->
Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/buffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class Buffer {
_data[_offset++] = v;
}

__attribute__((no_sanitize("undefined")))
__attribute__((no_sanitize("bounds")))
void put16(short v) {
assert(_offset + 2 < limit());
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/callTraceStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CallTraceStorage {
// Reserved trace ID for dropped samples due to contention
// Real trace IDs are generated as (instance_id << 32) | slot, where instance_id starts from 1
// Any ID with 0 in upper 32 bits is guaranteed to not clash with real trace IDs
static const u64 DROPPED_TRACE_ID = 1ULL;
static constexpr u64 DROPPED_TRACE_ID = 1ULL;

// Static dropped trace object that appears in JFR constant pool
static CallTrace* getDroppedTrace();
Expand Down
Loading