KEMBAR78
Correctly check if profiler is preloaded by Baraa-Hasheesh · Pull Request #1374 · async-profiler/async-profiler · GitHub
Skip to content

Conversation

Baraa-Hasheesh
Copy link
Contributor

Description

Add proper checking to validate that the profiler was preloaded as to avoid false starts

Currently if ASPROF_COMMAND env variable is defined any dlopen on the profiler will cause it to start which means the profiler might start with incorrect profiling options

Furthermore in this case async-profiler will assume that preload hooks exists which might not be true, which will to incomplete profiling by the profiler

Related issues

N/A

Motivation and context

Avoid false early starts for the async-profiler

How has this been tested?

New test added
make test


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

src/os_linux.cpp Outdated

if (info->dlpi_name == NULL) {
return 0;
} else if (strcmp(info->dlpi_name, current_info.dli_fname) == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we compare base address (dli_fbase) instead?

Copy link
Contributor Author

@Baraa-Hasheesh Baraa-Hasheesh Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will need to check on this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have been updated here 78edb2a

From the testing I did it looks like it does the trick

src/os_macos.cpp Outdated
continue;
} else if (strcmp(image_name, current_info.dli_fname) == 0) {
return true;
}else if(strcmp(image_name, sigaction_info.dli_fname) == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handled here 78edb2a

src/os_linux.cpp Outdated
}

Dl_info sigaction_info;
if (dladdr((const void*)sigaction, &sigaction_info) == 0 || sigaction_info.dli_fname == NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering why sigaction? Not the most obvious function in libc - may confuse someone who sees this for the first time. A short comment describing the idea of checkPreloaded would be useful anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to avoid typical functions that some other developer might interpose/preload as that would effect the accuracy of the check

For example dlopenon Linux dladdr will resolve to the async-profiler when it's preloaded

=> I wanted to avoid using functions that we patch/preload to keep the check consistent for all cases

I will add a comment for describing what the function does

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc added here 78edb2a

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, sigaction is a bad choice. Not only because it's some random unrelated function, but also because it does not meet the criteria you've mentioned:

I wanted to avoid typical functions that some other developer might interpose/preload

It's not uncommon to intercept sigaction for signal chaining purposes. A prominent example is JDK's libjsig library.

I'd choose some basic function like exit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated here 6e283d6

src/zInit.cpp Outdated
}

if (!checkJvmLoaded()) {
if (!checkJvmLoaded() && OS::checkPreloaded()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A minor thing, but I'd propose to move this check after ASPROF_COMMAND check, since using async-profiler through native API will be a common thing, while LD_PRELOAD is used rarely and mostly for ad-hoc profiling only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handled here 78edb2a

src/os_linux.cpp Outdated
Comment on lines 399 to 400
if (info->dlpi_name == NULL) {
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed 6e283d6

src/os_linux.cpp Outdated

// Find async-profiler shared objects
Dl_info current_info;
if (dladdr((const void*)OS::checkPreloaded, &current_info) == 0 || current_info.dli_fname == NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is comparing dli_fname really necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update it to check dli_fbase instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated here 6e283d6

src/os_linux.cpp Outdated
}

Dl_info sigaction_info;
if (dladdr((const void*)sigaction, &sigaction_info) == 0 || sigaction_info.dli_fname == NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, sigaction is a bad choice. Not only because it's some random unrelated function, but also because it does not meet the criteria you've mentioned:

I wanted to avoid typical functions that some other developer might interpose/preload

It's not uncommon to intercept sigaction for signal chaining purposes. A prominent example is JDK's libjsig library.

I'd choose some basic function like exit.

src/os_macos.cpp Outdated

uint32_t images = _dyld_image_count();
for (uint32_t i = 0; i < images; i++) {
const char* image_name = _dyld_get_image_name(i);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use base address on macOS, similarly to how you do this on Linux?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some double checking, yes we can check against _dyld_get_image_header

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 6e283d6

src/os_linux.cpp Outdated

// Find async-profiler shared objects
Dl_info current_info;
if (dladdr((const void*)OS::checkPreloaded, &current_info) == 0 || current_info.dli_fbase == NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would dli_fbase be NULL? Is it even possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it shouldn't be needed, will remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/os_macos.cpp Outdated
return false;
}

// Find async-profiler shared objects
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

object (singular)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/os_macos.cpp Outdated
}

// Find async-profiler shared objects
Dl_info current_info;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

current_info and exist_info sound a bit vague.
What about lib_async_profiler (or maybe libprofiler) and libc?

Then conditions like if (image_base == libc.dli_fbase) will be self-descriptive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will use libprofiler & libc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated here 486dc9d

@apangin apangin merged commit 461a3c1 into async-profiler:master Jul 10, 2025
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants