Skip to content

Commit 349ebbc

Browse files
jbachorikclaude
andcommitted
Fix attrs_data overflow, stale sidecar encodings, and JfrMetadata reinit
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent e8ef201 commit 349ebbc

6 files changed

Lines changed: 38 additions & 11 deletions

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ bool JfrMetadata::_initialized = false;
2626

2727
JfrMetadata::JfrMetadata() : Element("root") {}
2828

29+
void JfrMetadata::reset() {
30+
_root._children.clear();
31+
_root._attributes.clear();
32+
_strings.clear();
33+
_string_map.clear();
34+
// Re-register "root" at ID 0 so _root._name (const 0) stays valid
35+
getId("root");
36+
_initialized = false;
37+
}
38+
2939
void JfrMetadata::initialize(
3040
const std::vector<std::string> &contextAttributes) {
3141
if (_initialized) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class JfrMetadata : Element {
259259
JfrMetadata();
260260

261261
static void initialize(const std::vector<std::string> &contextAttributes);
262+
static void reset();
262263

263264
static Element *root() { return &_root; }
264265

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,7 @@ Error Profiler::start(Arguments &args, bool reset) {
14481448
// Always enable library trap to catch wasmtime loading and patch its broken sigaction
14491449
switchLibraryTrap(true);
14501450

1451+
JfrMetadata::reset();
14511452
JfrMetadata::initialize(args._context_attributes);
14521453
_num_context_attributes = args._context_attributes.size();
14531454
error = _jfr.start(args, reset);

ddprof-lib/src/main/java/com/datadoghq/profiler/ThreadContext.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ public ThreadContext(ByteBuffer recordBuffer, ByteBuffer tlsPtrBuffer, ByteBuffe
100100
throw new UnsupportedOperationException(
101101
"ByteBuffer context path requires little-endian platform");
102102
}
103+
// Zero sidecar + record to prevent stale encodings from a previous profiler session.
104+
// The native ProfiledThread survives across sessions, so the sidecar may hold
105+
// old tag encodings and the record may hold old attrs_data.
106+
for (int i = 0; i < MAX_CUSTOM_SLOTS; i++) {
107+
this.sidecarBuffer.putInt(i * 4, 0);
108+
}
109+
this.sidecarBuffer.putLong(this.lrsSidecarOffset, 0);
110+
this.recordBuffer.put(this.validOffset, (byte) 0);
111+
this.recordBuffer.putShort(this.attrsDataSizeOffset, (short) 0);
112+
this.tlsPtrBuffer.putLong(0, 0);
103113
}
104114

105115
/**
@@ -219,9 +229,9 @@ private boolean setContextAttributeDirect(int keyIndex, String value) {
219229
// otepKeyIndex is offset by 1: index 0 is reserved for LRS
220230
int otepKeyIndex = keyIndex + 1;
221231
detach();
222-
replaceOtepAttribute(otepKeyIndex, utf8);
232+
boolean written = replaceOtepAttribute(otepKeyIndex, utf8);
223233
attach();
224-
return true;
234+
return written;
225235
}
226236

227237
/**
@@ -305,7 +315,7 @@ private void attach() {
305315
* Replace or insert an attribute in attrs_data. Record must be detached.
306316
* Writes the pre-encoded UTF-8 bytes into the record.
307317
*/
308-
private void replaceOtepAttribute(int otepKeyIndex, byte[] utf8) {
318+
private boolean replaceOtepAttribute(int otepKeyIndex, byte[] utf8) {
309319
int currentSize = compactOtepAttribute(otepKeyIndex);
310320
int valueLen = Math.min(utf8.length, 255);
311321
int entrySize = 2 + valueLen;
@@ -317,8 +327,11 @@ private void replaceOtepAttribute(int otepKeyIndex, byte[] utf8) {
317327
recordBuffer.put(base + 2 + i, utf8[i]);
318328
}
319329
currentSize += entrySize;
330+
recordBuffer.putShort(attrsDataSizeOffset, (short) currentSize);
331+
return true;
320332
}
321333
recordBuffer.putShort(attrsDataSizeOffset, (short) currentSize);
334+
return false;
322335
}
323336

324337
/** Remove an attribute from attrs_data by compacting. Record must be detached. */

ddprof-test/src/test/java/com/datadoghq/profiler/AbstractProfilerTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ protected void runTests(Runnable... runnables) throws InterruptedException {
323323
public final void stopProfiler() {
324324
if (!stopped) {
325325
profiler.stop();
326+
profiler.resetThreadContext();
326327
stopped = true;
327328
checkConfig();
328329
}

ddprof-test/src/test/java/com/datadoghq/profiler/context/OtelContextStorageModeTest.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public static void setup() throws IOException {
5050
public void cleanup() {
5151
if (profilerStarted) {
5252
profiler.stop();
53+
profiler.resetThreadContext();
5354
profilerStarted = false;
5455
}
5556
}
@@ -62,7 +63,7 @@ public void cleanup() {
6263
public void testOtelStorageModeContext() throws Exception {
6364
Path jfrFile = Files.createTempFile("otel-ctx-otel", ".jfr");
6465

65-
profiler.execute(String.format("start,cpu=1ms,jfr,file=%s", jfrFile.toAbsolutePath()));
66+
profiler.execute(String.format("start,cpu=1ms,attributes=tag1;tag2;tag3,jfr,file=%s", jfrFile.toAbsolutePath()));
6667
profilerStarted = true;
6768

6869
long localRootSpanId = 0x1111222233334444L;
@@ -83,7 +84,7 @@ public void testOtelStorageModeContext() throws Exception {
8384
public void testOtelModeStartsOnAnyPlatform() throws Exception {
8485
Path jfrFile = Files.createTempFile("otel-ctx-any", ".jfr");
8586

86-
profiler.execute(String.format("start,cpu=1ms,jfr,file=%s", jfrFile.toAbsolutePath()));
87+
profiler.execute(String.format("start,cpu=1ms,attributes=tag1;tag2;tag3,jfr,file=%s", jfrFile.toAbsolutePath()));
8788
profilerStarted = true;
8889

8990
// Context operations should not crash
@@ -97,7 +98,7 @@ public void testOtelModeStartsOnAnyPlatform() throws Exception {
9798
public void testOtelModeClearContext() throws Exception {
9899
Path jfrFile = Files.createTempFile("otel-ctx-clear", ".jfr");
99100

100-
profiler.execute(String.format("start,cpu=1ms,jfr,file=%s", jfrFile.toAbsolutePath()));
101+
profiler.execute(String.format("start,cpu=1ms,attributes=tag1;tag2;tag3,jfr,file=%s", jfrFile.toAbsolutePath()));
101102
profilerStarted = true;
102103

103104
profiler.setContext(0xCAFEBABEL, 0xDEADBEEFL, 0L, 0x12345678L);
@@ -116,7 +117,7 @@ public void testOtelModeClearContext() throws Exception {
116117
public void testOtelModeCustomAttributes() throws Exception {
117118
Path jfrFile = Files.createTempFile("otel-ctx-attrs", ".jfr");
118119

119-
profiler.execute(String.format("start,cpu=1ms,contextattribute=http.route;db.system,jfr,file=%s", jfrFile.toAbsolutePath()));
120+
profiler.execute(String.format("start,cpu=1ms,attributes=http.route;db.system,jfr,file=%s", jfrFile.toAbsolutePath()));
120121
profilerStarted = true;
121122

122123
// Register attribute keys
@@ -145,7 +146,7 @@ public void testOtelModeCustomAttributes() throws Exception {
145146
public void testSetContextAttribute() throws Exception {
146147
Path jfrFile = Files.createTempFile("otel-ctx-attr", ".jfr");
147148

148-
profiler.execute(String.format("start,cpu=1ms,contextattribute=http.route,jfr,file=%s", jfrFile.toAbsolutePath()));
149+
profiler.execute(String.format("start,cpu=1ms,attributes=http.route,jfr,file=%s", jfrFile.toAbsolutePath()));
149150
profilerStarted = true;
150151

151152
profiler.setContext(0x456L, 0x123L, 0L, 0x789L);
@@ -162,7 +163,7 @@ public void testSetContextAttribute() throws Exception {
162163
public void testOtelModeAttributeOverflow() throws Exception {
163164
Path jfrFile = Files.createTempFile("otel-ctx-overflow", ".jfr");
164165

165-
profiler.execute(String.format("start,cpu=1ms,contextattribute=k0;k1;k2;k3;k4,jfr,file=%s", jfrFile.toAbsolutePath()));
166+
profiler.execute(String.format("start,cpu=1ms,attributes=k0;k1;k2;k3;k4,jfr,file=%s", jfrFile.toAbsolutePath()));
166167
profilerStarted = true;
167168

168169
OTelContext.getInstance().registerAttributeKeys("k0", "k1", "k2", "k3", "k4");
@@ -171,8 +172,8 @@ public void testOtelModeAttributeOverflow() throws Exception {
171172

172173
ThreadContext ctx = profiler.getThreadContext();
173174

174-
// Fill up attrs_data with long values (255 bytes each = 257 bytes per entry)
175-
// 612 / 257 = 2 full entries, third should fail
175+
// LRS "2" occupies 3 bytes (key=1, len=1, value=1) in attrs_data.
176+
// Each 255-char attr = 257 bytes per entry. Two fit; third overflows.
176177
StringBuilder sb = new StringBuilder(255);
177178
for (int i = 0; i < 255; i++) sb.append('x');
178179
String longValue = sb.toString();

0 commit comments

Comments
 (0)