• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20449
89%

Build:
DEFAULT BRANCH: master
Ran 08 Sep 2026 11:24AM UTC
Jobs 1
Files 689
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

08 Sep 2026 11:10AM UTC coverage: 89.228% (-0.02%) from 89.25%
#20449

push

github

web-flow
xds: Fix TSAN data race on ClientCall cancellation in ExternalProcessorClientInterceptor (#13022)

Prevent concurrent cancellations of the underlying ClientCall in
ExternalProcessorClientInterceptor:
- Wrap rawCall with SimpleForwardingClientCall using an AtomicBoolean to
ensure the underlying ClientCall.cancel() is executed at most once, even
if invoked concurrently across threads or from DelayedListener.
- In DataPlaneClientCall.cancel(), atomically transition
extProcStreamState to FAILED, catch exceptions during onError(), and
clear extProcClientCallRequestObserver.
- In sendToExtProc(), return early if the ext-proc stream is already
completed or the observer is null, and catch unexpected onNext()
exceptions to trigger internalOnError() rather than letting exceptions
escape into listener callbacks.
- Safely complete and clear extProcClientCallRequestObserver in
closeExtProcStream() and halfCloseExtProcStream().
- Route all rawCall.cancel() calls in sendMessage(),
handleImmediateResponse(), and DataPlaneListener through
cancelDownstream().

Fixes the TSAN detected race condition below. The previous fix in commit
cf92f2d2de introduced `AtomicBoolean downstreamCancelled` in
`cancelDownstream()`. However, the TSAN data race still reproduced under
postsubmit because `DelayedListener` exception path bypasses
`cancelDownstream()`: When `DelayedClientCall.start(wrappedListener,
headers)` is called, it registers an internal `DelayedListener`. If
`wrappedListener.onHeaders()` throws any exception,
`DelayedListener.deliverHeaders()` catches it and calls
`exceptionThrown()`, which invokes `delayedCall.cancel()` directly. Once
`delayedCall` has been activated `(realCall != null)`,
`DelayedClientCall.cancel()` directly calls `realCall.cancel()` on
whatever thread triggered it without any de-duplication.
```
Details
==================
WARNING: ThreadSanitizer: data race (pid=7774)
  Read of size 1 at 0x000089d8a086 by thread T113:
    #0 io.grpc.internal.ClientCa... (continued)

38776 of 43457 relevant lines covered (89.23%)

0.89 hits per line

Coverage Regressions

Lines Coverage ∆ File
39
95.78
0.23% ../xds/src/main/java/io/grpc/xds/ExternalProcessorClientInterceptor.java
5
83.02
-9.43% ../core/src/main/java/io/grpc/internal/Http2Ping.java
4
75.25
-3.96% ../servlet/src/main/java/io/grpc/servlet/AsyncServletOutputStreamWriter.java
3
95.07
-0.44% ../core/src/main/java/io/grpc/internal/RetriableStream.java
1
93.83
-0.62% ../opentelemetry/src/main/java/io/grpc/opentelemetry/OpenTelemetryMetricSink.java
1
87.6
-0.83% ../rls/src/main/java/io/grpc/rls/LinkedHashLruCache.java
Jobs
ID Job ID Ran Files Coverage
1 #20449.1 08 Sep 2026 11:24AM UTC 689
89.23
Source Files on build #20449
  • Tree
  • List 689
  • Changed 8
  • Source Changed 0
  • Coverage Changed 8
Coverage ∆ File Lines Relevant Covered Missed Hits/Line
  • Back to Repo
  • Github Actions Build #20449
  • b8f745a3 on github
  • Prev Build on master
  • Next Build on master
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc