Skip to content

[NativeAOT] Reduce owning C++ standard library state#12142

Open
simonrozsival wants to merge 6 commits into
mainfrom
dev/simonrozsival/nativeaot-owning-stl-cleanup
Open

[NativeAOT] Reduce owning C++ standard library state#12142
simonrozsival wants to merge 6 commits into
mainfrom
dev/simonrozsival/nativeaot-owning-stl-cleanup

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Jul 16, 2026

Copy link
Copy Markdown
Member

Summary

Reduce owning C++ standard-library state reachable from the Android NativeAOT host.

This PR is intentionally limited to three areas:

  1. gref/lref logging path ownership;
  2. NativeAOT-only Android path storage;
  3. source-location function-name parsing used by native argument-validation diagnostics.

The GC bridge temporary-peer cleanup was split into #12145. The two PRs are independent and can merge in either order.

Part of #12139, which tracks removing the Android NativeAOT app's libc++ dependency.

Motivation

The NativeAOT host shares a significant amount of code with CoreCLR. Several shared helpers still introduced owning C++ standard-library objects or template instantiations into the NativeAOT build even though the NativeAOT path only needs bounded, process-lifetime data:

  • custom gref/lref log paths were stored in global std::string instances;
  • Android override/native-library paths were represented by shared owning containers intended primarily for CoreCLR behavior;
  • source-location formatting split compiler signatures through ranges and materialized std::vector<std::string> plus an owning result string.

These are small individually, but each can root additional constructors, destructors, allocation helpers, exception machinery, or ranges/container implementation code in the final NativeAOT binary.

Changes

1. Reference logging paths

File: src/native/clr/runtime-base/logger.cc

  • replace global std::string instances for gref_file and lref_file with nullable C-string pointers;
  • add set_log_file() to perform overflow-checked allocation, copy the selected path, NUL-terminate it, and release the previous value;
  • treat an empty path as clearing the configured custom path;
  • expose parsed gref= / lref= values as std::string_view instead of returning a pointer into the parser without a length;
  • preserve the existing behavior where identical gref/lref paths reuse the same FILE*;
  • construct fallback paths such as <override>/grefs.txt in bounded dynamic_local_string<SENSIBLE_PATH_MAX> storage instead of an owning std::string.

The observable logging behavior is unchanged: configured paths are tried first, fallback files remain under the override directory, and file-open failures continue to be logged by existing helpers.

2. NativeAOT Android path storage

File: src/native/clr/include/runtime-base/android-system.hh

Under XA_HOST_NATIVEAOT:

  • store primary_override_dir and native_libraries_dir in fixed process-lifetime buffers sized by Constants::SENSIBLE_PATH_MAX;
  • return C-string views of those buffers to NativeAOT callers;
  • construct the primary override path in bounded local storage, validate its length, then copy the complete NUL-terminated path into the static buffer;
  • compile out CoreCLR-oriented owning state that NativeAOT does not use, including the owning app-library/override-directory containers and debug bundled-property map;
  • keep CoreCLR's existing std::string, array, span, update-directory, and debug-property behavior unchanged.

This is a compile-time host specialization, not a runtime behavior switch.

3. Source-location function-name parsing

File: src/native/common/include/shared/cpp-util.hh

  • remove the ranges, vector, and owning-string implementation previously used by get_function_name();
  • scan the compiler-provided signature in place through std::string_view;
  • locate the outer function parameter list while accounting for nested parentheses;
  • locate the relevant function component while accounting for template, array, and parenthesized nesting;
  • preserve readable handling of scoped functions, free operators, scoped operators, anonymous namespaces, lambdas, and templated signatures;
  • return a non-owning view and pass it to diagnostics with %.*s, avoiding construction of a temporary result string.

Malformed or empty signatures continue to fall back safely rather than being dereferenced blindly.

Scope and non-goals

  • This PR does not change GC bridge behavior; that is isolated in [NativeAOT] Use indexed temporary peers in GC bridge #12145.
  • It does not attempt to remove every use of C++ standard-library headers from shared native code.
  • It does not change CoreCLR behavior where the existing owning containers remain appropriate.
  • It does not change log categories, log-file naming, update-directory policy, or native diagnostic text beyond how the function name is extracted.

Expected impact

  • remove direct owning basic_string storage and destructor roots from the NativeAOT logging/path code changed here;
  • avoid ranges/vector/string materialization in native validation diagnostics;
  • reduce transient allocations and associated C++ exception/runtime symbol roots;
  • retain bounded, deterministic storage for process-lifetime NativeAOT paths;
  • preserve functional behavior while making the remaining libc++ dependency easier to identify and remove.

Exact archive/shared-library measurements will be refreshed after CI validates the final split revision.

Validation

The remaining three-file change was included in the earlier combined revision that passed:

  • git diff --check;
  • Release build of src/native/native-nativeaot.csproj;
  • Release build of src/native/native-clr.csproj;
  • NDK Clang C++23 syntax compilation;
  • zero-runtime-cost static_assert coverage for ordinary functions, scoped methods, templates and GCC substitution suffixes, lambdas, free and scoped operators, malformed signatures, null, and empty input;
  • focused review of allocation ownership, bounded path copying, NUL termination, CoreCLR/NativeAOT preprocessor scoping, and fallback logging behavior.

CI is validating head 4412ea395.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 187b207a-083b-461e-9071-e9aab61c9d07
Copilot AI review requested due to automatic review settings July 16, 2026 23:48
@simonrozsival simonrozsival added the drop-libcpp Work to remove the libc++ dependency from Android NativeAOT label Jul 16, 2026

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

Reduces owning C++ standard-library state reachable from the Android NativeAOT host to help shrink binaries and remove libc++-related symbol roots (part of #12139).

Changes:

  • Replaces GC-bridge temporary peer storage from std::unordered_map to tsl::robin_map, and tightens lifetime cleanup.
  • Removes/avoids owning std::string storage in logging paths and source-location function-name parsing (moves to bounded std::string_view parsing).
  • Introduces NativeAOT-specific bounded storage for Android override/native-library paths (while keeping CoreCLR behavior).
Show a summary per file
File Description
src/native/common/include/shared/cpp-util.hh Reworks function-name extraction to bounded std::string_view parsing and updates formatted error messages to avoid owning strings.
src/native/CMakeLists.txt Makes robin-map include path available to CLR/NativeAOT targets and unconditionally defines ROBIN_MAP_DIR.
src/native/clr/runtime-base/logger.cc Switches gref/lref path storage away from owning std::string to explicit malloc/free management and uses bounded path building.
src/native/clr/include/runtime-base/android-system.hh Adds NativeAOT-specific bounded path storage/return types for override/native-library directories.
src/native/clr/include/host/bridge-processing-shared.hh Swaps temporary peer map to tsl::robin_map and adds guarded include/diagnostic handling.
src/native/clr/host/bridge-processing.cc Updates temporary-peer insertion/iteration for robin-map and ensures local refs are deleted before clearing the map.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 1

Comment thread src/native/clr/include/runtime-base/android-system.hh
Use the negative-index TemporaryPeerMap approach from #11311 so CoreCLR and NativeAOT no longer need robin-map for GC bridge processing.

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

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Move the TemporaryPeerMap changes to #12145 so this branch only contains the remaining owning-state cleanup.

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

Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
@simonrozsival

Copy link
Copy Markdown
Member Author

CI failure analysis

The public dotnet-android build #1513910 completed with 41 of 42 jobs passing.

The sole failure was MSBuild+Emulator 9, specifically:

DotNetInstallAndRunMinorAPILevels(True, "net10.0-android36.1", NativeAOT)

The final link reports duplicate symbols such as __unw_init_local, __unw_resume, and unw_local_addr_space between:

  • .NET 10.0.9: libRuntime.WorkstationGC.a
  • NDK 29.0.14206865: libunwind.a

This is the same pre-existing collision independently reproduced by #12140 build #1513800. It is unrelated to this PR's container/string cleanup and provides further evidence for #12139.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 70f63eb7-6599-414c-a947-d860705aa0fa
Preserve the NativeAOT fixed-buffer state while keeping the new CoreCLR application code-cache directory state behind the non-NativeAOT path.

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

Copilot-Session: 3f8e6959-6647-4d07-ab74-492a1e60d3ec
@simonrozsival

Copy link
Copy Markdown
Member Author

/reivew

@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@simonrozsival simonrozsival added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Jul 18, 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 ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants