Skip to content

Commit 2106e38

Browse files
authored
Merge branch 'main' into zgu/thread_exit_cleanup
2 parents 2a5c522 + 0738808 commit 2106e38

17 files changed

Lines changed: 221 additions & 240 deletions

File tree

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ unless the change does not modify code (e.g. only modifies docs, comments).
1717

1818
**For Datadog employees**:
1919
- [ ] If this PR touches code that signs or publishes builds or packages, or handles
20-
credentials of any kind, I've requested a review from `@DataDog/security-design-and-guidance`.
20+
credentials of any kind, I've requested a security review (run the `dd:platform-security-review`
21+
skill, or file a request via the [PSEC review form](https://datadoghq.atlassian.net/jira/software/c/projects/PSEC/forms/form/direct/7861446195161534/37715)).
22+
`bewaire` also runs automatically on every PR.
2123
- [ ] This PR doesn't touch any of that.
2224
- [ ] JIRA: [JIRA-XXXX]
2325

.github/chainguard/async-profiler-build.ci.sts.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ subject_pattern: "project_path:DataDog/java-profiler:ref_type:branch:ref:.*"
66
permissions:
77
contents: write
88
issues: write
9-
pull_requests: read
9+
# write (not read) is required to post comments on pull requests via the
10+
# issues/comments endpoint — GitLab CI back-reports benchmark & reliability
11+
# results to the PR (see .gitlab/scripts/upsert-github-pr-comment.sh).
12+
pull_requests: write

.github/workflows/test_workflow.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ jobs:
191191
name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64
192192
path: /tmp/signal-safety-violation.txt
193193
if-no-files-found: ignore
194+
- name: Upload ASan logs
195+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
196+
if: failure() && matrix.config == 'asan'
197+
with:
198+
name: asan-logs-glibc-${{ matrix.java_version }}-amd64
199+
path: /tmp/asan.log.*
200+
if-no-files-found: ignore
194201

195202
test-linux-musl-amd64:
196203
needs: [cache-jdks, filter-musl-configs]
@@ -317,6 +324,13 @@ jobs:
317324
name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64
318325
path: /tmp/signal-safety-violation.txt
319326
if-no-files-found: ignore
327+
- name: Upload ASan logs
328+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
329+
if: failure() && matrix.config == 'asan'
330+
with:
331+
name: asan-logs-musl-${{ matrix.java_version }}-amd64
332+
path: /tmp/asan.log.*
333+
if-no-files-found: ignore
320334

321335
test-linux-glibc-aarch64:
322336
needs: cache-jdks
@@ -495,6 +509,13 @@ jobs:
495509
name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64
496510
path: /tmp/signal-safety-violation.txt
497511
if-no-files-found: ignore
512+
- name: Upload ASan logs
513+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
514+
if: failure() && matrix.config == 'asan'
515+
with:
516+
name: asan-logs-glibc-${{ matrix.java_version }}-aarch64
517+
path: /tmp/asan.log.*
518+
if-no-files-found: ignore
498519

499520
test-linux-musl-aarch64:
500521
needs: [cache-jdks, filter-musl-configs]
@@ -599,3 +620,10 @@ jobs:
599620
name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64
600621
path: /tmp/signal-safety-violation.txt
601622
if-no-files-found: ignore
623+
- name: Upload ASan logs
624+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
625+
if: failure() && matrix.config == 'asan'
626+
with:
627+
name: asan-logs-musl-${{ matrix.java_version }}-aarch64
628+
path: /tmp/asan.log.*
629+
if-no-files-found: ignore

build-logic/conventions/src/main/kotlin/com/datadoghq/native/config/ConfigurationPresets.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,22 @@ object ConfigurationPresets {
211211
if (libasan != null) {
212212
config.testEnvironment.apply {
213213
put("LD_PRELOAD", libasan)
214-
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")
214+
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")
215215
put("UBSAN_OPTIONS", "halt_on_error=0:abort_on_error=0:print_stacktrace=1:suppressions=$rootDir/gradle/sanitizers/ubsan.supp")
216216
put("LSAN_OPTIONS", "detect_leaks=0")
217217
}
218+
// JDK 25's G1GC reserves heap virtual address space starting just below 2 GB
219+
// (0x7fff7000), which is exactly where ASan needs to mmap its shadow bytes
220+
// [0x7fff7000-0x10007fff7fff]. Force the heap to a very low base address so
221+
// the entire JVM footprint (heap + class space + code cache) stays well below
222+
// the shadow range and the two regions no longer conflict.
223+
if (PlatformUtils.testJvmMajorVersion() >= 25) {
224+
config.testJvmArgs.addAll(listOf(
225+
"-XX:HeapBaseMinAddress=0x4000000",
226+
"-Xmx512m",
227+
"-XX:CompressedClassSpaceSize=256m"
228+
))
229+
}
218230
}
219231
}
220232
Platform.MACOS -> {

build-logic/conventions/src/main/kotlin/com/datadoghq/native/model/BuildConfiguration.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ abstract class BuildConfiguration @Inject constructor(
1515
abstract val compilerArgs: ListProperty<String>
1616
abstract val linkerArgs: ListProperty<String>
1717
abstract val testEnvironment: MapProperty<String, String>
18+
abstract val testJvmArgs: ListProperty<String>
1819
abstract val active: Property<Boolean>
1920

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

2830
fun isActiveFor(targetPlatform: Platform, targetArch: Architecture): Boolean {

build-logic/conventions/src/main/kotlin/com/datadoghq/native/util/PlatformUtils.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,24 @@ object PlatformUtils {
367367
false
368368
}
369369
}
370+
371+
/**
372+
* Returns the major version of the test JVM (e.g. 8, 11, 17, 21, 25).
373+
* Returns 0 if the version cannot be determined.
374+
*/
375+
fun testJvmMajorVersion(): Int {
376+
val javaHome = testJavaHome()
377+
return try {
378+
val process = ProcessBuilder("$javaHome/bin/java", "-version")
379+
.redirectErrorStream(true)
380+
.start()
381+
val output = process.inputStream.bufferedReader().readText()
382+
process.waitFor(10, TimeUnit.SECONDS)
383+
// version line: java version "1.8.0_xxx" or java version "21.0.x" etc.
384+
val match = Regex("""version "(?:1\.)?(\d+)""").find(output)
385+
match?.groupValues?.get(1)?.toIntOrNull() ?: 0
386+
} catch (_: Exception) {
387+
0
388+
}
389+
}
370390
}

build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class ProfilerTestPlugin : Plugin<Project> {
111111
val testClasspath: FileCollection,
112112
val standardJvmArgs: List<String>,
113113
val extraJvmArgs: List<String>,
114+
val configJvmArgs: List<String>,
114115
val systemProperties: Map<String, String>,
115116
val environmentVariables: Map<String, String>
116117
)
@@ -164,6 +165,7 @@ class ProfilerTestPlugin : Plugin<Project> {
164165
testClasspath = testClasspath,
165166
standardJvmArgs = extension.standardJvmArgs.get(),
166167
extraJvmArgs = extension.extraJvmArgs.get(),
168+
configJvmArgs = config.testJvmArgs.get(),
167169
systemProperties = systemProps,
168170
environmentVariables = envVars
169171
)
@@ -247,6 +249,7 @@ class ProfilerTestPlugin : Plugin<Project> {
247249
}
248250

249251
allArgs.addAll(testConfig.extraJvmArgs)
252+
allArgs.addAll(testConfig.configJvmArgs)
250253
testTask.jvmArgs(allArgs)
251254
}
252255

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

307311
// System properties
308312
testConfig.systemProperties.forEach { (key, value) ->

ddprof-lib/src/main/cpp/buffers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class Buffer {
8080
_data[_offset++] = v;
8181
}
8282

83+
__attribute__((no_sanitize("undefined")))
8384
__attribute__((no_sanitize("bounds")))
8485
void put16(short v) {
8586
assert(_offset + 2 < limit());

ddprof-lib/src/main/cpp/callTraceStorage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class CallTraceStorage {
3434
// Reserved trace ID for dropped samples due to contention
3535
// Real trace IDs are generated as (instance_id << 32) | slot, where instance_id starts from 1
3636
// Any ID with 0 in upper 32 bits is guaranteed to not clash with real trace IDs
37-
static const u64 DROPPED_TRACE_ID = 1ULL;
37+
static constexpr u64 DROPPED_TRACE_ID = 1ULL;
3838

3939
// Static dropped trace object that appears in JFR constant pool
4040
static CallTrace* getDroppedTrace();

ddprof-lib/src/main/cpp/context_api.cpp

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,10 @@
1818
#include "context.h"
1919
#include "guards.h"
2020
#include "otel_context.h"
21-
#include "otel_process_ctx.h"
2221
#include "profiler.h"
2322
#include "thread.h"
2423
#include <cstring>
2524

26-
// Reserved attribute index for local root span ID in OTEL attrs_data.
27-
// Only used within this translation unit; not part of the public ContextApi header.
28-
static const uint8_t LOCAL_ROOT_SPAN_ATTR_INDEX = 0;
29-
3025
/**
3126
* Initialize context TLS for the current thread on first use.
3227
* Must be called with signals blocked to prevent musl TLS deadlock:
@@ -71,55 +66,3 @@ Context ContextApi::snapshot() {
7166
size_t numAttrs = Profiler::instance()->numContextAttributes();
7267
return thrd->snapshotContext(numAttrs);
7368
}
74-
75-
void ContextApi::registerAttributeKeys(const char** keys, int count) {
76-
// Clip to DD_TAGS_CAPACITY: that is the actual sidecar slot limit and the
77-
// maximum keyIndex accepted by ThreadContext.setContextAttribute.
78-
int n = count < (int)DD_TAGS_CAPACITY ? count : (int)DD_TAGS_CAPACITY;
79-
80-
// Build NULL-terminated key array for the process context config.
81-
// Index LOCAL_ROOT_SPAN_ATTR_INDEX (0) is reserved for local_root_span_id; user keys start at index 1.
82-
// otel_process_ctx_publish copies all strings, so no strdup is needed.
83-
const char* key_ptrs[DD_TAGS_CAPACITY + 2]; // +1 reserved, +1 null
84-
key_ptrs[LOCAL_ROOT_SPAN_ATTR_INDEX] = "datadog.local_root_span_id";
85-
for (int i = 0; i < n; i++) {
86-
key_ptrs[i + 1] = keys[i];
87-
}
88-
key_ptrs[n + 1] = nullptr;
89-
90-
otel_thread_ctx_config_data config = {
91-
.schema_version = "tlsdesc_v1_dev",
92-
.attribute_key_map = key_ptrs,
93-
};
94-
95-
#ifndef OTEL_PROCESS_CTX_NO_READ
96-
otel_process_ctx_read_result read_result = otel_process_ctx_read();
97-
if (read_result.success) {
98-
otel_process_ctx_data data = {
99-
.deployment_environment_name = read_result.data.deployment_environment_name,
100-
.service_instance_id = read_result.data.service_instance_id,
101-
.service_name = read_result.data.service_name,
102-
.service_version = read_result.data.service_version,
103-
.telemetry_sdk_language = read_result.data.telemetry_sdk_language,
104-
.telemetry_sdk_version = read_result.data.telemetry_sdk_version,
105-
.telemetry_sdk_name = read_result.data.telemetry_sdk_name,
106-
.resource_attributes = read_result.data.resource_attributes,
107-
.extra_attributes = read_result.data.extra_attributes,
108-
.thread_ctx_config = &config,
109-
};
110-
111-
otel_process_ctx_publish(&data);
112-
otel_process_ctx_read_drop(&read_result);
113-
}
114-
#endif
115-
}
116-
117-
void ContextApi::registerAttributeKeys(const std::vector<std::string>& keys) {
118-
// Clip to DD_TAGS_CAPACITY before materializing C string pointers.
119-
size_t n = keys.size() < DD_TAGS_CAPACITY ? keys.size() : DD_TAGS_CAPACITY;
120-
const char* key_ptrs[DD_TAGS_CAPACITY];
121-
for (size_t i = 0; i < n; i++) {
122-
key_ptrs[i] = keys[i].c_str();
123-
}
124-
registerAttributeKeys(key_ptrs, (int)n);
125-
}

0 commit comments

Comments
 (0)