Skip to content

[NativeAOT] Migrate GC bridge logging to printf#12211

Open
jonathanpeppers wants to merge 2 commits into
jonathanpeppers-native-printf-logging-nextfrom
jonathanpeppers-finish-gc-bridge-printf
Open

[NativeAOT] Migrate GC bridge logging to printf#12211
jonathanpeppers wants to merge 2 commits into
jonathanpeppers-native-printf-logging-nextfrom
jonathanpeppers-finish-gc-bridge-printf

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Dependency

Depends on #12210 and targets its jonathanpeppers-native-printf-logging-next branch.

Scope

Migrates the five remaining easy NativeAOT-reachable formatted logging calls in src/native/clr/host/gc-bridge.cc to the canonical shared printf APIs introduced by #12155.

Behavior preservation

  • Retains the LOG_GC category, existing gc_spew_enabled() and Util::should_log() gates, and the no-check write after the explicit gate.
  • Preserves message text and control flow.
  • Uses %zu for size_t values and PRIxPTR for handle-width hexadecimal values, including the explicit 0x prefix corresponding to {:#x}.
  • Preserves null handling for Java class names with optional_string().

Non-goals

Does not migrate the three nearby std::format calls in bridge-processing.cc that feed OSBridge::_monodroid_gref_log; those require a separate API design.

Validation

  • dotnet build src\native\native-nativeaot.csproj -p:AndroidSupportedTargetJitAbis=arm64-v8a -p:AndroidSupportedTargetAotAbis=arm64 -v:minimal
  • dotnet build src\native\native-clr.csproj -p:AndroidSupportedTargetJitAbis=arm64-v8a -p:AndroidSupportedTargetAotAbis=arm64 -v:minimal
  • git diff --check

Convert the remaining easy formatted GC bridge diagnostics reachable by NativeAOT to the canonical shared printf logging APIs while preserving gating, no-check behavior, formatting, and null handling.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4aed776f-8743-45ba-b96b-079253595056
Copilot AI review requested due to automatic review settings July 22, 2026 19:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR continues the NativeAOT/CoreCLR native-host logging migration by converting the remaining GC-bridge formatted log sites in src/native/clr/host/gc-bridge.cc from std::format-style logging to the shared printf-style logging helpers introduced earlier in the series.

Changes:

  • Replace log_info(...) / log_info_nocheck_fmt(...) formatted calls with log_infof(...) and log_writef(...).
  • Preserve existing GC-spew/category gating (Logger::gc_spew_enabled() and Util::should_log()), including the explicit “no-check” write after the gate.
  • Use PRIxPTR + uintptr_t for handle-width hex formatting and add <cinttypes> for the format macro.

…gging-next' into jonathanpeppers-finish-gc-bridge-printf
@jonathanpeppers

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ LGTM — clean, behavior-preserving migration

Reviewed the migration of the five remaining NativeAOT-reachable formatted logging calls in src/native/clr/host/gc-bridge.cc from the std::format-style APIs to the printf-style shared APIs.

Correctness verified against the API definitions:

Old call New call Gating behavior
log_info (macro → DO_LOG_FMT) log_infof Both check log_categories & category before writing — ✅ equivalent
log_info_nocheck_fmt log_writef (..., LogLevel::Info, ...) Both write unconditionally — ✅ equivalent, and correctly placed after the explicit Util::should_log (LOG_GC) gate

Format specifier mapping is correct:

  • {} on size_t%zu
  • {:#x} on handle → 0x%" PRIxPTR " with <cinttypes> added ✅ (and improved by using uintptr_t — see inline)
  • {} on char*%s with optional_string() guard ✅ (a real nullptr-crash fix — see inline)

Positive callouts:

  • The LOG_GC category, gc_spew_enabled() / Util::should_log() gates, message text, and control flow are all preserved exactly as the PR description claims — verified against the full source.
  • <cinttypes> (the C++ header, per repo convention) is the correct include for PRIxPTR.
  • Two of the changes (optional_string guard and signed→unsigned handle) are genuine robustness/correctness improvements over the pre-migration code, not just mechanical swaps.

Notes:

  • CI on the dnceng-public pipeline was still pending at review time (no checks reported yet) — this is not a blocker but should be green before merge, since the change is native code that only the build validates.
  • As the PR states, the three std::format calls in bridge-processing.cc feeding _monodroid_gref_log are intentionally out of scope.

No blocking issues. Two 💡 suggestions posted inline highlighting the subtle improvements for future reference.

Generated by Android PR Reviewer for #12211 · 92.3 AIC · ⌖ 18.9 AIC · ⊞ 6.8K
Comment /review to run again

@@ -161,10 +162,10 @@ void GCBridge::log_handle_context (JNIEnv *env, HandleContext *ctx) noexcept
jclass java_class = env->GetObjectClass (handle);
if (java_class != nullptr) {
char *class_name = Host::get_java_class_name_for_TypeManager (java_class);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 💡 Native memory — Good, necessary change: wrapping class_name in optional_string() guards the %s conversion. Host::get_java_class_name_for_TypeManager() genuinely returns nullptr on several paths (null/failed Class.getName, OOM on UTF8 conversion — see host-shared.cc), and passing a raw nullptr to a printf %s is undefined behavior (crash on most C libraries), whereas the old std::format {} on a char* silently formatted it. This migration is more robust than the code it replaces, not just equivalent.

Rule: Guard printf %s against nullptr (repo optional_string convention)

if (java_class != nullptr) {
char *class_name = Host::get_java_class_name_for_TypeManager (java_class);
log_info (LOG_GC, "gref {:#x} [{}]", reinterpret_cast<intptr_t> (handle), class_name);
log_infof (LOG_GC, "gref 0x%" PRIxPTR " [%s]", reinterpret_cast<uintptr_t> (handle), optional_string (class_name));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 💡 Native C++ — Nice correctness improvement: switching the handle from intptr_t to uintptr_t here means large 64-bit handle addresses (high bit set) now format as plain 0x... hex. The old std::format {:#x} on a signed intptr_t would render negative values as -0x..., which is misleading for a pointer/gref. The explicit 0x prefix + %" PRIxPTR " correctly mirrors the previous {:#x} output for typical values.

Rule: Use unsigned width-matched types for pointer hex formatting

@jonathanpeppers jonathanpeppers added the drop-libcpp Work to remove the libc++ dependency from Android NativeAOT label Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drop-libcpp Work to remove the libc++ dependency from Android NativeAOT

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants