Skip to content

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

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

[NativeAOT] Reduce owning C++ standard library state#12142
simonrozsival wants to merge 5 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
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