JDK-8368124 : Show useful thread names in ASAN reports
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 26
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • Submitted: 2025-09-19
  • Updated: 2025-09-27
  • Resolved: 2025-09-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26 masterFixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
ASAN only shows some internal thread designation on reports, e.g.:

```
WRITE of size 8 at 0x7b749d2d9190 thread T49
```

which is useless. We should add this capability to Linux. 

JDK-7102541 added support for thread names in gdb, which uses `_pthread_setname_np`, but these names do not show up in ASAN.

Investigation:

We call pthread_setname_np assuming that it causes libpthread to call prctl(PR_SET_NAME,...), which would set the thread name in the kernel task structure. We further assume that name would percolate through to all interested parties, like gdb and ASAN.

But it reproducibly does not work for ASAN, tested on Fedora with glibc 2.42 and on Debian 12 stable. I also often see JVM ASAN reports from unknown Linux versions that never show a Thread name.

glibc does everything correctly:

https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=nptl/pthread_setname.c;hb=42aba9189557280ad367c35908cbdfe26f5aeeb1

Specifically, in the Linux version of pthread_setname_np, it calls eventually:

```
int
__pthread_setname_np (pthread_t th, const char *name)
{
...
  if (pd == THREAD_SELF)
    return __prctl (PR_SET_NAME, name) ? errno : 0;
...
```

ASAN, in GCC, intercepts prctl(SET_NAME): it does the real prctl first, then calls COMMON_INTERCEPTOR_SET_THREAD_NAME:

https://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc;hb=HEAD

```
INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
            unsigned long arg4, unsigned long arg5) {
  ...
  int res = REAL(prctl)(option, arg2, arg3, arg4, arg5);
  if (option == PR_SET_NAME) {
...
    COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
  } else if (res == 0 && option == PR_GET_NAME) {
...
```

COMMON_INTERCEPTOR_SET_THREAD_NAME is defined as SetThreadName in ASAN here:

https://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libsanitizer/asan/asan_interceptors.h;hb=HEAD

```
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
```

Which will register the thread name with the central ASAN thread registry:

```
void SetThreadName(const char *name) {
  ...
    asanThreadRegistry().SetThreadName(t->tid(), name);
 ...
}
```

And now the thread name is known to ASAN.

ASAN also intercepts pthread_setname_np. It calls the interceptor first, then goes on calling the real pthread_setname_np:

```
INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {

  COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
  return REAL(pthread_setname_np)(thread, name);
}
```

COMMON_INTERCEPTOR_SET_PTHREAD_NAME, however, is a noop:

```
#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
  do {                                                         \
  } while (false)
```

Looking at the thread registry code in ASAN: the internal thread structure (class ThreadContextBase) carries the user-defined thread name. When we call pthread_setname_np, the real glibc version is called correctly, which does prctl(PR_SET_NAME), correctly. However, the name in the ASAN thread registry does not obtain its string from prctl(PR_GET_NAME), the proc file system, or any other source. It only gets the name from intercepting prctl(PR_SET_NAME).

And intercepting prctl(PR_SET_NAME) only works for **an ASAN-instrumented binary**.

So, if we call prctl(PR_SET_NAME) from within the hotspot, the ASAN interception kicks in and modifies the ASAN thread registry name alongside the kernel task structure name. 

If we just call glibc pthread_setname_np, the glibc does call prctl(PR_SET_NAME) correctly, but since glibc is not ASAN-instrumented, the ASAN interception does not kick in and the ASAN thread registry won't be modified.

It seems that the only way to set the ASAN thread name is to call prctl directly from the hotspot.

Comments
Note: after implementing this patch, we found that attached thread names still don't show up correctly. See JDK-8368621.
27-09-2025

Changeset: a6638121 Branch: master Author: Thomas Stuefe <stuefe@openjdk.org> Date: 2025-09-26 06:14:28 +0000 URL: https://git.openjdk.org/jdk/commit/a6638121211afd688a9e25b5cbadf2f1441b1e65
26-09-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/27395 Date: 2025-09-19 18:00:43 +0000
20-09-2025