Skip to content

Replace simple CLR local strings - #12517

Open
simonrozsival wants to merge 26 commits into
mainfrom
dev/simonrozsival/replace-simple-local-strings
Open

Replace simple CLR local strings#12517
simonrozsival wants to merge 26 commits into
mainfrom
dev/simonrozsival/replace-simple-local-strings

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Aug 25, 2026

Copy link
Copy Markdown
Member

Summary

Remove simple CLR local strings while preserving dynamic growth where the old local-string type supported it.

Changes

  • make debug typemap-name and CoreCLR primary-override-path formatters report the negative required capacity and retry with exact-size malloc() storage
  • keep common values in sensible stack buffers and free returned storage only when it differs from the stack buffer
  • avoid separate heap out-parameters and cleanup helpers
  • replace CLR system-property local strings with explicit (buffer, buffer_size) calls using the platform property bound
  • parse logging and timing properties without dynamically growing local strings
  • remove the CLR monodroid_get_system_property(..., dynamic_local_property_string&) overload
  • keep NativeAOT's pre-existing primary-override array intentionally bounded

Validation

  • Local native builds intentionally skipped; relying on CI validation

Follow-up: return const char* rather than std::string_view

The first pass here replaced the local string with a fixed caller-supplied buffer, which regressed bundled properties: those come from @(AndroidEnvironment) and are not bound by Android's PROP_VALUE_MAX, so any value longer than the buffer was reported as absent. Returning a view fixed that — Android system properties view the caller's scratch buffer, bundled properties point straight at immortal static application data, with no copy and no length cap.

That part stands, but std::string_view was the wrong vehicle for it. Every value the function can return is NUL-terminated (__system_property_get() terminates what it writes, and bundled properties are NUL-terminated static strings), yet string_view explicitly promises the opposite. The invariant had to be asserted in a header comment — "The returned value is always NUL-terminated" — precisely because the type denied it, and get_max_gref_count_from_system() quietly depended on it by handing .data() to strtol() and to a %s conversion.

So the getter now returns const char* (nullptr when the property is unset), in both the CoreCLR and MonoVM implementations:

  • the lifetime contract is unchanged and still uniform — the result is valid for at least as long as the buffer you passed in — and callers never have to know which of the two branches produced it;
  • NUL-termination is now guaranteed by the type instead of by a comment, so .data() no longer has to be laundered through a string_view to reach a C API;
  • callers that genuinely tokenize the value (Logger::init_logging_categories(), FastTiming::parse_options()) construct a std::string_view explicitly, which is honest about what they are doing.

No change in libc++ references (string_view is header-only) — this is a type-safety fix, not a size one. All three runtime lanes build clean.

Follow-up: fixes from the offline review

Reviewing the conversion above turned up three problems in the code it touches, all fixed in the last commit.

lookup_system_property() returned the property name, not its value. It returned prop_iter->first — the map key — while reporting prop_iter->second.length() as the length. In a DEBUG build with bundled @(AndroidEnvironment) properties, Logger::init_logging_categories() and get_max_gref_count_from_system() were parsing the property name. This predates the PR, but the conversion above makes that value the direct return of the public getter, and the no-copy contract documented in the header describes exactly this path, so it belongs here.

monodroid__system_property_get() wrote one byte past the end of the caller's buffer. Its small-buffer fallback copied through a heap buffer and then did sp_value[sp_value_len] = '\0'. The branch was already dead — the only caller rejects undersized buffers before calling — so the sp_value_len parameter is gone along with it. That also drops a new[]/delete[] pair, removing two libc++ references. #12523 previously carried its own version of this removal; it is now fixed here, in the PR that makes the path unreachable.

An undersized buffer was reported as an unset property. Returning nullptr conflated a programming error with a legitimate runtime outcome, so it is an abort_unless() now.

Also derives the "gref="/"lref=" prefix length with sizeof() instead of hardcoding 5.

All three runtime lanes build clean; libc++ references at the stack tip are unchanged at 21.

Copilot AI lite review requested due to automatic review settings August 25, 2026 13:51

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 effort to remove straightforward uses of the native local-string hierarchy in the CLR host/runtime by switching to fixed-size buffers (with snprintf) and by using a fixed-buffer system property retrieval API that rejects undersized buffers to avoid truncation.

Changes:

  • Added a monodroid_get_system_property(std::string_view, char*, size_t) overload and updated fixed-array callers to write directly into their buffers.
  • Reworked primary override directory path formatting to use snprintf into fixed buffers.
  • Replaced debug typemap full-name composition with fixed-buffer snprintf formatting.
Show a summary per file
File Description
src/native/clr/runtime-base/android-system-shared.cc Adds fixed-buffer monodroid_get_system_property overload that rejects undersized buffers and avoids truncation.
src/native/clr/include/runtime-base/android-system.hh Switches property callers to fixed buffers and formats primary override dir using snprintf.
src/native/clr/host/typemap.cc Uses snprintf into a fixed buffer to build managed type debug names for typemap lookup.
src/native/clr/host/assembly-store.cc Uses a fixed property buffer for debug.net.asmcache instead of dynamic_local_property_string.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/native/clr/host/typemap.cc Outdated
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from c111658 to 3a05311 Compare August 25, 2026 13:57
@simonrozsival
simonrozsival changed the base branch from dev/simonrozsival/remove-timing-dynamic-strings to main August 25, 2026 13:58
@simonrozsival simonrozsival added the drop-libcpp Work to remove the libc++ dependency from Android NativeAOT label Aug 25, 2026
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from 2a03078 to cda8d20 Compare August 25, 2026 15:08
@simonrozsival
simonrozsival changed the base branch from main to dev/simonrozsival/remove-timing-dynamic-strings August 25, 2026 15:10
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from cda8d20 to 2e9c443 Compare August 25, 2026 15:22
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch 2 times, most recently from 6d947da to ddae8f9 Compare August 25, 2026 15:42
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from ddae8f9 to 4478d1c Compare August 25, 2026 15:51
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from 4478d1c to ce12492 Compare August 25, 2026 15:59
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from ce12492 to 85f0111 Compare August 25, 2026 18:53
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from 85f0111 to 8c8f213 Compare August 25, 2026 21:27
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch 2 times, most recently from 4a079b8 to fb358cf Compare August 25, 2026 21:41
@simonrozsival
simonrozsival force-pushed the dev/simonrozsival/replace-simple-local-strings branch from fb358cf to ea5dfcb Compare August 25, 2026 21:51
Narrowing the `strings.hh` include in `logger.hh` also removed two symbols
that headers were picking up transitively through it:

* `strings.hh` included `shared/helpers.hh`, which is where `os-bridge.hh`
  was getting `abort_unless` from.
* `strings.hh` included `<unistd.h>`, which is where `bridge-processing.cc`
  was getting `gettid()` from.

Include both explicitly at their point of use.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
@jonathanpeppers
jonathanpeppers force-pushed the dev/simonrozsival/replace-simple-local-strings branch from 968857f to a7e70fe Compare August 27, 2026 14:25
Narrowing the strings.hh include in logger.hh removed the transitive
path that util.cc relied on for dynamic_local_string, breaking the
CoreCLR and NativeAOT builds. Include the header where it is used.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
@jonathanpeppers

Copy link
Copy Markdown
Member

/review

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • azcliprod.blob.core.windows.net

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "azcliprod.blob.core.windows.net"

See Network Configuration for more information.

Generated by Android PR Reviewer for #12517

@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.

⚠️ Needs Changes

Findings: 0 errors, 1 warning, 0 suggestions.

The fixed-buffer refactoring is focused, and the retrying path-format changes preserve dynamic growth where expected. However, bundled system-property values can exceed the Android platform limit, so rejecting them at the new fixed boundary silently changes existing logging, profiling, and timing behavior.

CI is not green: Package Tests macOS > Tests > APKs 1 is failing, and the aggregate dotnet-android check had not completed. Deeper failure details were unavailable because Azure DevOps requires authentication.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • azcliprod.blob.core.windows.net

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "azcliprod.blob.core.windows.net"

See Network Configuration for more information.

Generated by Android PR Reviewer for #12517 · gpt56 · 347.6 AIC · ⌖ 8.93 AIC · ⊞ 25.7K
Comment /review to run again

Comment thread src/native/clr/runtime-base/android-system-shared.cc Outdated
simonrozsival and others added 7 commits August 27, 2026 23:30
Addresses review feedback: the fixed-buffer overload returned -1 when a
bundled (build-time) property value did not fit into the caller's buffer,
so long values were treated as if the property were not set at all.  The
`dynamic_local_string` based overload it replaced grew onto the heap and
had no such limit.

Bundled properties come from `@(AndroidEnvironment)` files and are stored
as NUL-terminated strings in static application data, so they are neither
subject to Android's 92 byte property limit nor in need of copying.
Return a `std::string_view` instead of an `int`: for Android system
properties it views the caller's scratch buffer, for bundled properties it
points directly at the application data, which restores the previous
behaviour and avoids a copy.

`FastTiming::parse_options()` used to tokenize its argument in place, which
is not safe for a view over static data, so it now parses without mutating.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
…perty

The previous commit changed `monodroid_get_system_property ()` to return a
`std::string_view` so that bundled properties, whose length is not limited by
`PROPERTY_VALUE_BUFFER_LEN`, could be returned without copying them into the
caller's scratch buffer.

That works, but `std::string_view` deliberately makes no promise about
NUL-termination, while every value this function can return happens to be
NUL-terminated: `__system_property_get ()` terminates what it writes, and
bundled properties are NUL-terminated strings in static application data. The
header had to document that invariant in a comment ("The returned value is
always NUL-terminated") precisely because the type denies it, and callers such
as `get_max_gref_count_from_system ()` silently relied on it by passing
`.data ()` to `strtol ()` and to a `%s` format specifier.

Return `const char*` instead (and `nullptr` when the property is not set). The
lifetime rule is unchanged and still uniform - the result is valid for at least
as long as the caller's buffer - but NUL-termination is now guaranteed by the
type rather than by a comment, so `.data ()` no longer has to be laundered
through a `std::string_view`. Callers that need to tokenize the value construct
a `std::string_view` explicitly, which is honest about what they are doing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
- `format_managed_type_name ()` builds the name with a single `snprintf ()`
  instead of three `memcpy ()` calls and hand-rolled length arithmetic. The
  negative-required-capacity retry contract is unchanged, and the helper is now
  guarded by `#if defined (DEBUG)` like its only caller, which removes the
  unused-function warning this pull request introduced.

- `FastTiming::parse_options ()` takes a `const char*` again and tokenizes with
  `strchr ()`/`strncmp ()`/`strtoull ()`. It had been rewritten around
  `std::string_view`, which added a C++ layer to code that was already plain C.
  The parser still cannot NUL-terminate in place - the value may point at
  immortal bundled property data - so each parameter is bounded by its length
  instead. The `duration=` and `filename=` edge cases behave as they did before.

- The property lookup chain (`monodroid_get_system_property ()`,
  `monodroid__system_property_get ()` and `lookup_system_property ()`) takes
  `const char *name`, matching the other overloads. Previously it took a
  `std::string_view` and immediately called `.data ()` on it, which is the same
  NUL-termination laundering that motivated changing the return type. This also
  lets `HostEnvironment::lookup_system_property ()` use `strcmp ()` directly and
  drops `<string_view>` from `android-system-shared.cc` entirely.

- Shorten the comments added by this pull request, and drop the `strings.hh`
  include from `logger.cc`, which no longer uses `dynamic_local_string`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
`Logger::init_logging_categories ()` split the property value with
`std::string_view`, and `set_category ()`, `set_log_file ()` and `open_file ()`
took views as well. Tokenize the value with `strchr ()`/`strncmp ()` instead and
pass the parameters around as a pointer and a length.

This also removes a subtle NUL-termination assumption: `open_file ()` called
`unlink (path.data ())`, which is only correct because every caller happened to
pass a view over a NUL-terminated buffer. It now takes a `const char*`.

A single `param_matches ()` helper does all of the comparisons, so the
parameters no longer have to be NUL-terminated in place - the value may point at
immortal bundled property data.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
The function returns either the caller's scratch buffer or a pointer into
application data, which is easy to mistake for the "stack buffer or malloc"
convention used elsewhere in this header, where the caller has to free the
result when it differs from the buffer it passed in. Say so explicitly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
`Util::create_public_directory ()`, `Util::monodroid_fopen ()` and
`Util::set_world_accessable ()` each took a `std::string_view` and immediately
called `.data ()` on it to hand the path to `mkdir ()`, `fopen ()` or
`chmod ()`. That is only correct because every caller happens to pass a view
over a NUL-terminated buffer, which nothing enforces. Take a `const char*`
instead, which is what these functions actually need.

`Logger::open_file ()` and `Logger::init_reference_logging ()` follow, so
`logger.cc` no longer refers to `std::string_view` at all and the `"..."sv`
literals are gone with it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
Address issues found while reviewing the C string conversion of the
system property APIs.

`AndroidSystem::lookup_system_property()` returned `prop_iter->first`,
which is the map *key* -- the property name -- rather than its value,
while reporting `prop_iter->second.length ()` as the length. In a DEBUG
build with bundled `@(AndroidEnvironment)` properties, callers such as
`Logger::init_logging_categories()` and
`get_max_gref_count_from_system()` therefore parsed the property name
instead of the value. Return `prop_iter->second` instead.

`monodroid__system_property_get()` had a fallback branch that copied
through a heap buffer whenever the caller's buffer was smaller than
`PROPERTY_VALUE_BUFFER_LEN`. Its only caller now rejects that case
before calling, so the branch was dead -- and it wrote a terminating NUL
one byte past the end of the caller's buffer. Remove it, along with the
now-unused `sp_value_len` parameter. This also drops a `new[]`/`delete[]`
pair, removing two more libc++ references from the object file.

Passing an undersized buffer to `monodroid_get_system_property()` was
reported as `nullptr`, indistinguishable from an unset property. It is a
programming error, so `abort_unless()` on it instead.

Finally, derive the "gref="/"lref=" prefix length with `sizeof()` rather
than hardcoding it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12517

@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.

❌ Reject

Found 1 error and 0 warnings. The Mono DEBUG bundled-property lookup still returns the property name rather than its value through the newly added no-copy getter; this needs to be corrected for parity with the CLR fix in this PR.

The buffer lifetime contracts and exact-size fallback paths are otherwise well documented and consistently cleaned up. CI build 1572360 is still in progress; completed build and tooling lanes are passing with no reported failures so far.

Generated by Android PR Reviewer for #12517 · gpt56 · 331 AIC · ⌖ 9.09 AIC · ⊞ 25.7K
Comment /review to run again

Comment thread src/native/mono/runtime-base/android-system.cc Outdated
… lookup

`AndroidSystem::lookup_system_property (name, value_len)` returned
`p->name` while reporting `p->value_len` as its length, so every
bundled `debug.*` property in a MonoVM Debug build resolved to its own
name instead of its configured value.  When the value was longer than
the name this also read past the end of the name buffer.

The CoreCLR implementation already returns the value; this brings Mono
to parity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12517

@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.

❌ Reject

Found 1 error, 0 warnings, and 0 suggestions. The new pointer-returning property API correctly avoids copying bundled values, but get_max_gref_count_from_system() no longer distinguishes an empty override from a non-empty one; that can set the CoreCLR GREF threshold to zero and force repeated full collections.

CI is still running; the completed checks observed so far passed, with no failure reported at review time.

Generated by Android PR Reviewer for #12517 · gpt56 · 242.5 AIC · ⌖ 8.86 AIC · ⊞ 25.7K
Comment /review to run again

Comment thread src/native/clr/runtime-base/android-system-shared.cc
simonrozsival and others added 5 commits August 28, 2026 18:12
`monodroid_get_system_property()` returned a non-null pointer for a
bundled property that exists with an empty value, where the previous
`dynamic_local_string` overload reported a length of 0 and callers
skipped it.

`get_max_gref_count_from_system()` then ran `strtol ("")` and set the
max JNI global reference count to 0 instead of keeping the 51200
default, and `create_update_dir()` treated an empty `debug.mono.profile`
as a request to create the `.__override__` directory.

The real-property path already behaves this way -- `__system_property_get`
returns 0 for a property that is absent *and* for one set to an empty
string -- so the bundled path now matches it rather than fixing each
call site.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
* `Logger::open_file()` now bails out when `override_dir` is null or
  empty instead of passing it to `Util::create_public_directory()` and
  `Util::join_paths()`. The latter takes `std::string_view`, and
  constructing one from a null `const char*` is undefined behaviour.
  The old `std::string_view const&` signature made this impossible;
  `const char*` does not.

* MonoVM's `monodroid_get_system_property()` now aborts on a too-small
  scratch buffer, matching the CoreCLR implementation. Silently
  returning `nullptr` made a programming error indistinguishable from
  "property not set".

* `format_primary_override_dir()` checked `buffer == nullptr` only
  after already passing `buffer` to `snprintf()`. Assert up front.

* Fix stray indentation on the `Logger::set_category()` declaration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
`monodroid_get_system_property()` claimed that a returned bundled
property value "lives as long as the process". That is only true for
NativeAOT, where the value points into the immortal app-environment
blob. In Debug builds:

* CoreCLR stores bundled properties in a
  `std::unordered_map<std::string, std::string>`, so re-assigning a
  property replaces the mapped `std::string`.
* MonoVM's `add_system_property()` explicitly `free()`s `p->value`
  before installing the replacement.

In both cases a previously returned pointer dangles. No current caller
retains the pointer past the call, but the comment invited them to, so
document the real guarantee instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
* `format_primary_override_dir()` passed `home.get_cstr ()` straight to
  `snprintf()`'s `%s`. `jstring_wrapper::get_cstr()` returns `nullptr`
  for a null `jstring`, and passing `nullptr` to `%s` is undefined
  behaviour. Abort with a clear message instead: an application without
  a files directory cannot work regardless.

* `HostEnvironment::lookup_system_property()` left the `value_len`
  out-parameter untouched on both of its `nullptr` return paths, so the
  NativeAOT implementation of
  `AndroidSystem::lookup_system_property()` returned an uninitialized
  length while the CoreCLR one zeroed it first. The only caller happens
  to be safe because `||` short-circuits on the null pointer, but the
  two implementations of the same declaration should not disagree.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
`format_joined_path()`, `format_primary_override_dir()` and
`format_managed_type_name()` all share one protocol: write into the
supplied buffer and return either the formatted length or the negative
required capacity. Each had its own open-coded "try the stack buffer,
malloc and retry on failure" dance, two of which this branch had just
introduced.

Hoist that into `Util::format_with_retry()` and use it in all three
places. This removes ~25 lines of triplicated code and, more
importantly, leaves a single copy of the logic that has to get the
retry, the abort-on-OOM and the `!= stack_buffer` ownership check
right.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0a35a0db-502d-48c0-8468-e73b5dd0ab2e
@simonrozsival

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

Generated by Android PR Reviewer for #12517

@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.

Reviewed the current 18-file native-runtime diff against the repository’s native C++, JNI/interop, security, and compatibility rules. I found no new actionable defects in this revision; the earlier long bundled-property, Mono property value/name, and empty-value regressions are addressed by the latest commits.

CI is still in progress on Azure DevOps build #1572876: the completed checks are passing, with five checks still running and the aggregate check queued. No failing check is currently reported.

Generated by Android PR Reviewer for #12517 · gpt56 · 222.8 AIC · ⌖ 8.77 AIC · ⊞ 25.7K
Comment /review to run again

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

3 participants