Skip to content

Commit 97e9f99

Browse files
committed
fix(profiler): cover all JFR-writing signal handlers in drain
jbachorik review (profiler.cpp:1578): the inflight drain previously only covered CTimer/CTimerJvmti, so the TOCTOU/UAF this PR closes for those handlers remains open for the other CPU and wall fallback engines. Add InflightGuard at signal-handler entry (after the foreign-signal filter passes, before any JFR-writing code) for: - PerfEvents::signalHandler (CPU fallback, same risk shape as CTimer) - ITimer::signalHandler (CPU fallback when timer_create absent) - ITimerJvmti::signalHandler (CPU + jvmtistacks fallback) - WallClockASGCT::sharedSignalHandler (default wall handler) - WallClockJvmti::sharedSignalHandler (wall + jvmtistacks handler) For the wall handlers the guard is placed in sharedSignalHandler — the engine-specific inner signalHandler is dispatched from the shared scope, so a single guard in the dispatcher covers every JFR-touching code path in both wall variants. Risk profile (highest to lowest probability of hitting the race in practice): CTimer / PerfEvents (per-thread streams, ~10ms interval, N concurrent in-flight handlers) > Wall (signals from the wall pthread, ~reservoir_size concurrent) > ITimer / ITimerJvmti (process-wide setitimer, single in-flight at a time). All five plug into the same SignalInflight counter so Profiler::stop() drains them uniformly.
1 parent 1e75102 commit 97e9f99

3 files changed

Lines changed: 14 additions & 0 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "jvmThread.h"
2121
#include "os.h"
2222
#include "profiler.h"
23+
#include "signalInflight.h"
2324
#include "stackWalker.h"
2425
#include "thread.h"
2526
#include "threadState.inline.h"
@@ -38,6 +39,7 @@ void ITimer::signalHandler(int signo, siginfo_t *siginfo, void *ucontext) {
3839
// is therefore vulnerable to the foreign-SIGPROF deadlock scenario this
3940
// feature addresses. Use CTimer (the default) when signal-origin
4041
// validation is required.
42+
InflightGuard inflight;
4143
if (!_enabled)
4244
return;
4345

@@ -104,6 +106,7 @@ long ITimerJvmti::_interval = 0;
104106

105107
void ITimerJvmti::signalHandler(int signo, siginfo_t *siginfo, void *ucontext) {
106108
SIGNAL_HANDLER_GUARD();
109+
InflightGuard inflight;
107110
CriticalSection cs;
108111
if (!cs.entered()) {
109112
return;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "os.h"
3030
#include "perfEvents.h"
3131
#include "profiler.h"
32+
#include "signalInflight.h"
3233
#include "spinLock.h"
3334
#include "stackFrame.h"
3435
#include "stackWalker.h"
@@ -735,6 +736,7 @@ void PerfEvents::signalHandler(int signo, siginfo_t *siginfo, void *ucontext) {
735736
// Looks like an external signal; don't treat as a profiling event
736737
return;
737738
}
739+
InflightGuard inflight;
738740
// Atomically try to enter critical section - prevents all reentrancy races
739741
CriticalSection cs;
740742
if (!cs.entered()) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "log.h"
1717
#include "profiler.h"
1818
#include "signalCookie.h"
19+
#include "signalInflight.h"
1920
#include "thread.h"
2021
#include "threadState.inline.h"
2122
#include "guards.h"
@@ -66,6 +67,10 @@ void WallClockASGCT::sharedSignalHandler(int signo, siginfo_t *siginfo,
6667
}
6768
Counters::increment(WALLCLOCK_SIGNAL_OWN);
6869

70+
// Past the foreign-signal filter: any work below this point can write JFR.
71+
// Participate in SignalInflight::drain() so Profiler::stop() does not tear
72+
// down JFR while this handler is still inside recordSample().
73+
InflightGuard inflight;
6974
WallClockASGCT *engine = reinterpret_cast<WallClockASGCT *>(Profiler::instance()->wallEngine());
7075
if (signo == SIGVTALRM) {
7176
engine->signalHandler(signo, siginfo, ucontext, engine->_interval);
@@ -246,6 +251,10 @@ void WallClockJvmti::sharedSignalHandler(int signo, siginfo_t *siginfo,
246251
}
247252
Counters::increment(WALLCLOCK_SIGNAL_OWN);
248253

254+
// Past the foreign-signal filter: any work below this point can write JFR.
255+
// Participate in SignalInflight::drain() so Profiler::stop() does not tear
256+
// down JFR while this handler is still inside recordSampleDelegated().
257+
InflightGuard inflight;
249258
WallClockJvmti *engine =
250259
reinterpret_cast<WallClockJvmti *>(Profiler::instance()->wallEngine());
251260
if (signo == SIGVTALRM) {

0 commit comments

Comments
 (0)