Skip to content

Implement a workaround for ld-prime hitting an assert on large addends - #124721

Merged
MichalStrehovsky merged 8 commits into
dotnet:mainfrom
filipnavara:ld-prime-addend
Jul 27, 2026
Merged

Implement a workaround for ld-prime hitting an assert on large addends#124721
MichalStrehovsky merged 8 commits into
dotnet:mainfrom
filipnavara:ld-prime-addend

Conversation

@filipnavara

@filipnavara filipnavara commented Feb 22, 2026

Copy link
Copy Markdown
Member

We translate the IMAGE_REL_BASED_RELPTR32 relocation into ARM64_RELOC_SUBTRACTOR and ARM64_RELOC_UNSIGNED pair on ARM64. To emulate the behavior of PC relative relocation we bake the section-relative PC offset into the addend with negative sign. The ARM64_RELOC_SUBTRACTOR relocation then subtract the base address of the section and finally the ARM64_RELOC_UNSIGNED relocation adds the target symbol address.

This works fine for addends that fit into signed 20-bit integer, but ld-prime hits an assert when the addend is larger. To workaround it we create anchor labels at fixed 2^19 byte offsets in the section and adjust the addend to be relative to the nearest anchor label. This way we can guarantee the addend for ARM64_RELOC_SUBTRACTOR is
always within signed 20-bit range.

Same logic applies to X86_64_RELOC_SUBTRACTOR + X86_64_RELOC_UNSIGNED pair for x64 targets.

Fixes #119380

@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 22, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Feb 22, 2026
@filipnavara filipnavara added os-mac-os-x macOS aka OSX os-ios Apple iOS area-NativeAOT-coreclr and removed area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Feb 22, 2026
@filipnavara
filipnavara marked this pull request as ready for review February 22, 2026 09:04
@filipnavara
filipnavara marked this pull request as draft February 22, 2026 09:47
@filipnavara

filipnavara commented Feb 22, 2026

Copy link
Copy Markdown
Member Author

Needs more work. I'll investigate the unit test failures first.

@filipnavara

filipnavara commented Feb 22, 2026

Copy link
Copy Markdown
Member Author

I don't get the System.Linq.Expressions test failure on Xcode 26.2 anymore. According the log the compiler/linker version on CI is some version of Xcode 26.x Xcode 16.4.

@filipnavara

Copy link
Copy Markdown
Member Author

Going back to the drawing board now.

@filipnavara

Copy link
Copy Markdown
Member Author

@akoeplinger Is there some easy way to switch some CI lane to use newer Xcode? They should be available in the runner images, just not as default.

@akoeplinger

Copy link
Copy Markdown
Member

I assume adding xcode-select to the path mentioned in https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md#xcode somewhere early in the build should suffice?
You could add it to build.sh (if it's just for testing).

@filipnavara

Copy link
Copy Markdown
Member Author

I assume adding xcode-select to the path mentioned in https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md#xcode somewhere early in the build should suffice?

Thanks, seems to pass the smoke test with Xcode 26.2. I'll probably open a separate PR to check what is the behavior just with the Xcode bump alone.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

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 adds a workaround in the Mach-O object writer to avoid Apple ld-prime assertions when emitting IMAGE_REL_BASED_RELPTR32 as *_RELOC_SUBTRACTOR + *_RELOC_UNSIGNED with large addends, by introducing reusable per-section temporary labels to keep addends within the linker’s expected signed 20-bit range.

Changes:

  • Track and emit per-section temporary labels to bound relocation addends for IMAGE_REL_BASED_RELPTR32 on ARM64 and x64 .eh_frame.
  • Adjust Mach relocation emission to optionally reference a temporary label symbol (instead of the section base symbol) for SUBTRACTOR relocs.
  • Modify build.sh to attempt switching Xcode versions on macOS.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/coreclr/tools/Common/Compiler/ObjectWriter/MachObjectWriter.cs Adds temporary-label generation/reuse and uses label symbol indices to avoid ld-prime large-addend assertions.
build.sh Adds macOS-only logic to switch Xcode via sudo xcode-select.

Comment thread src/coreclr/tools/Common/Compiler/ObjectWriter/MachObjectWriter.cs Outdated
Comment thread src/coreclr/tools/Common/Compiler/ObjectWriter/MachObjectWriter.cs Outdated
Comment thread build.sh Outdated
@MichalStrehovsky

Copy link
Copy Markdown
Member

/azp run runtime-extra-platforms, runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member Author

I checked the build/test failures. It definitely deserves a second pair of eyes but I don't think any of the failures are related to the changes in this PR.

@MichalStrehovsky MichalStrehovsky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g various timeouts and a #131262

@MichalStrehovsky
MichalStrehovsky enabled auto-merge (squash) July 27, 2026 14:40
@MichalStrehovsky
MichalStrehovsky merged commit 3aa40d2 into dotnet:main Jul 27, 2026
150 of 164 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc1 milestone Jul 28, 2026
@akoeplinger

Copy link
Copy Markdown
Member

I guess we can reenable the disabled tests now:

<!-- https://github.com/dotnet/runtime/issues/119380 -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Text.Json\tests\System.Text.Json.SourceGeneration.Tests\System.Text.Json.SourceGeneration.Roslyn4.4.Tests.csproj"
Condition="'$(TargetOS)' == 'osx' and '$(TargetArchitecture)' == 'arm64'" />
?

and backport to release/10.0

@filipnavara

Copy link
Copy Markdown
Member Author

I guess we can reenable the disabled tests now:

We should pin the disabled test against different issue. As I mentioned in #124721 (comment):

The CI for outerloop is still pinned on Xcode 16.4 and ld-classic. The failure in System.Text.Json.SourceGeneration.Roslyn4.4.Tests is thus unrelated to the fix in this PR. I downloaded the Helix payload and double checked that ld64 955.13 was used for the linking. We will need to do separate analysis to see why the unwind information seems to be corrupted there.

Backport to release/10.0 would be nice. That said, I would not mind waiting for this to bake in for a few weeks in main/11.0 first. The issue was around for well over a year and for most cases there are workarounds (eg. forcing classic linker).

@andrew-kulikov

Copy link
Copy Markdown
Contributor

Thanks for the fix! We’ve encountered the same issue while migrating a large iOS app from Mono to NativeAOT on .NET 10. The classic-linker workaround also fails, apparently due to #124609. A .NET 10 backport would be greatly appreciated.

@filipnavara

Copy link
Copy Markdown
Member Author

@andrew-kulikov I have a standalone package to workaround the issue by rewriting the ILC output - https://github.com/filipnavara/ld64addend. I need to update it to use the correct limits. Hopefully I can release a new version tomorrow.

@andrew-kulikov

Copy link
Copy Markdown
Contributor

Thanks! I actually tried this package already, but it didn’t work for our app initially. After applying the fix from Fable 5 - which likely addresses the same issue as the latest commits in this PR - it worked :). So an updated package would also be a useful temporary workaround, though having the fix in the runtime itself would of course be preferable.

@agocke

agocke commented Aug 3, 2026

Copy link
Copy Markdown
Member

/backport to release/10.0

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

@agocke

agocke commented Aug 3, 2026

Copy link
Copy Markdown
Member

FYI, I like this approach given that we need to dodge various bugs in various versions, but long term I think we can intend to drop ld-classic support and then we might want to re-visit the grid approach

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

@agocke backporting to release/10.0 failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Implement a workaround for ld-prime hitting an assert on large addends
Using index info to reconstruct a base tree...
A	src/coreclr/tools/Common/Compiler/ObjectWriter/MachNative.cs
A	src/coreclr/tools/Common/Compiler/ObjectWriter/MachObjectWriter.cs
Falling back to patching base and 3-way merge...
Auto-merging src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs
CONFLICT (content): Merge conflict in src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 Implement a workaround for ld-prime hitting an assert on large addends
Error: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

agocke added a commit to agocke/runtime that referenced this pull request Aug 11, 2026
Backport of dotnet#124721, adapted for the release/10.0 NativeAOT object writer.

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

Copilot-Session: 181cbdd7-15a7-4b79-8e2f-614428802360
akoeplinger pushed a commit that referenced this pull request Aug 12, 2026
…on large addends (#132171)

Fixes Issue #119380

main PR #124721

# Description

On Apple platforms, NativeAOT's Mach-O object writer represents
`RELPTR32` relocations with `SUBTRACTOR` and `UNSIGNED` relocation
pairs. Large section-relative addends can exceed ld-prime's signed
20-bit inline encoding, causing ld-prime to assert during linking.

This backport adds sparse, section-relative relocation-anchor symbols.
The writer selects the nearest preceding anchor as the `SUBTRACTOR` base
so every emitted addend stays within the inline range. This is adapted
to the release/10.0 NativeAOT object writer, whose implementation
remains under `ILCompiler.Compiler`.

# Customer Impact

Without this fix, NativeAOT applications targeting Apple platforms can
fail to link when their object files contain sufficiently large
`RELPTR32` relocation addends. The failure is a linker assertion rather
than a successful application build.

# Regression

No. This is a long-standing ld-prime limitation tracked by #119380.

# Testing

Built
`src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj`
with the repository SDK. No new test was added; validation of the Apple
ld-prime scenario relies on this PR's platform CI.

# Risk

Low. The change is narrowly limited to Mach-O emission of `RELPTR32`
relocations on ARM64 and x64 `.eh_frame`. It preserves the relocation
value while replacing the section base with a local anchor only when the
existing addend cannot be encoded by ld-prime.

# Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet
package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older
versions.

Copilot-Session: 181cbdd7-15a7-4b79-8e2f-614428802360
@akoeplinger

Copy link
Copy Markdown
Member

10.0 backport (#132171) got merged, it should go out with 10.0.12

marcschier added a commit to OPCFoundation/UA-.NETStandard that referenced this pull request Sep 8, 2026
# Description

Completes the OPC UA Part 11 Historical Access work requested by #4387
and
the historian framework integration requested by #4400.

The conformance/evidence catalog covers all 37 released UACore 1.05
Historical Access profiles: 15 Server facets and 22 Client facets,
together
with the standard aggregate functions and their conformance units.
Server
facets are advertised only when the resolved providers expose their
required
interfaces and capabilities.

## Server and provider support

- Completes raw, modified, at-time, processed, annotation, structured,
and event history.
- Dispatches best-effort, bulk, and transactional updates with aligned
statuses, old values, diagnostics, and rollback state.
- Supports mixed history-update detail types and batched
structured/annotation operations.
- Uses composite identities and exclusive cursors for same-timestamp
structured, modified, and event values.
- Captures live data and events, installs historical configuration
objects, and emits typed audit payloads.
- Derives aggregate monitoring filters from per-node historian
capabilities and rejects unsupported processed aggregates before
provider dispatch.
- Supports tri-state `Historizing`: set, clear, or preserve
provider-owned state.

## Client support

- Exposes modified values together with `ModificationInfo`.
- Adds event-history reads and event insert/replace/update/delete
operations.
- Adds structured and annotation batching with strict response
validation.
- Shares continuation handling and release-on-abandon across read
families.
- Accepts inherited standard event fields rooted at event subtypes.

## Review hardening

- Registers DI-selected historians before node-manager reconciliation
and capability publication, while preserving provider ownership.
- Uses committed Raft read barriers for linearizable `TryGetAsync` and
`ScanAsync`.
- Keeps claimed continuation state immutable until a fresh successor is
saved, restoring the original after transient failures.
- Uses exact-incarnation compare-and-delete so delayed cleanup cannot
remove a restored same-ID continuation.
- Cleans up indeterminate initial and replacement saves, and propagates
shutdown cancellation through cleanup resolution.
- Preserves legacy continuation envelopes/cursors and distinct
annotation parent/property identities.
- Deletes every structured entry at a requested timestamp and uses the
complete modified-history ordering tuple.
- Shares native/fallback at-time and AnnotationCount calculations,
including reverse endpoints and cross-framework fractional intervals.
- Primes modified aggregate items before buffered live delivery and
deduplicates history/live overlap using provider-specific identities.
- Keeps committed Modify results successful while reporting priming
failures
  through the monitored item's notification queue.
- Keeps protected-notification state live-only for queues larger than
one.
Queue size one retains the newest notification without pinning errors or
transferring priority during resizing. Durable restore retains ordinary
definitions, last values/errors, and raw queues without recreating
priority.
- Isolates aggregate calculation, modification preparation, and
historical/live
handoff in `AggregationFilterHandler`, retaining existing
provider/factory
wiring and supported past-start behavior. The larger-queue protection
policy
  is unchanged pending the open review discussion.
- Uses one `IMonitoringFilter` owner for protocol filters or the
aggregation
handler, eliminating parallel effective-filter storage and retaining the
current definition during preparation. The original client filter stays
distinct.
- Integrates current master, retaining custom monitored-item creation
decisions and per-node history callbacks.

## Redundant-server alignment and samples

- Adds a protected shared historian with immutable segments, manifest
CAS publication, writer fencing, and restart recovery.
- Persists portable continuation state before exposing it to clients and
transfers ownership during mirrored-session takeover.
- Rejects eventual-consistency and active/active multi-writer historian
configurations rather than silently degrading.
- ReferenceServer and ConsoleReferenceClient demonstrate discovery,
paging, raw/modified/at-time/processed reads, annotation/structured
CRUD, event capture, and event CRUD.
- RedundantServer and RedundantClient demonstrate active/passive
history, continuation recovery after replica termination, and
post-promotion writes.
- Updates Historical Access, High Availability, profile, migration, and
sample documentation.

## Compatibility

- New 2.0 collection boundaries use `ArrayOf<T>` and public byte
payloads use `ByteString`.
- Removes the legacy public virtual
`SamplingGroupManager.CreateMonitoredItem` /
`ModifyMonitoredItem` entry points and protected creation factory, as
agreed
  in review. Migration guidance points to the monitored-item manager and
  construction-decision APIs.
- Retains established persisted formats and current write layouts.
Retired interim
notification-state formats (sample v2 / shared v4) are rejected, as
agreed in review.
- Keeps the historian integration compatible with .NET Framework and
NativeAOT.

## Validation

### Latest CI source repair

`73c619435` forwards the existing cancellation token at both
predefined-node
creation calls in the PR-added History event fixture. The merged
lifecycle
overload exposed these two CA2016 errors, which blocked History jobs,
the
solution build matrix, and CodeQL on GitHub and Azure. The exact
compiler
failure was reproduced locally; the repaired fixture passes 4/4
integration
cases on net10.0 and 4/4 on net48 with clean scoped diagnostics. No
assertions,
tests, coverage thresholds, or CI configuration were weakened.

The repaired History jobs on Linux/macOS and all four Azure solution
builds
now pass. The Windows all-TFM GitHub job instead lost its hosted
runner's
connection; no build log was recoverable, and GitHub recorded a
runner-loss
annotation rather than a compiler/test diagnostic. One unchanged retry
was
requested. Remaining checks are monitored with
`gh pr checks --watch --fail-fast --interval 30`; CI is not yet reported
as green.

### Latest base integration

`bd52e5fea` merges upstream `master` at `da7412c42`. The lifecycle
conflict
retains upstream's shared cancellation-aware registration helper and the
historian behavior. The hosted-historian fixture forwards its existing
token
to the new lifecycle overload. GDS project renames and all three AOT
test
hosts are retained, with their project references resolving after the
merge.

| Integrated scope | net10.0 | net48 |
| --- | --- | --- |
| Server lifecycle, fluent authoring/import, historian, monitored-item
and hosting regressions | 732 passed | 732 passed |
| NodeState lifecycle regressions | 216 passed | 216 passed |
| Automatically merged Raft client fixtures | 28 passed | 28 passed |

No selected tests failed or were skipped. The manually resolved files
pass
scoped formatting/analyzer checks. One CA1861 warning remains in the
incoming
`NodeSetImportIntegrationTests.cs`; that file is byte-identical to
upstream
master and was not rewritten or suppressed during integration.

### Latest feedback follow-up

`102954eaa` replaces split filter references with the shared
`IMonitoringFilter`
contract implemented by protocol filters and `AggregationFilterHandler`.
Targeted server regressions pass **103/103 on net10.0 and 103/103 on
net48**;
scoped formatting/analyzers are clean, and the updated XML-documentation
inventory has zero gaps across 188 non-generated PR C# files.

`93c5b5db8` renames `AggregationFilterHandler`, makes it the owner of
the
server-revised aggregate filter while preserving the original client
filter,
and removes the retired interim notification-state readers. Server
regressions
pass **101/101** and shared-store regressions **64/64**, on both net10.0
and
net48, with no failures or skips. Runtime-file formatting/analyzers are
clean.

`5ccf45630` completes the public/internal XML-documentation sweep. The
Roslyn
inventory finds zero undocumented eligible declarations across all 186
non-generated PR C# files; the 110-file documentation slice changes only
XML
comments and spacing. `f17765475` applies the three requested Markdown
edits.

### Earlier feedback follow-ups

`a53950737` removes single-slot notification pinning and extracts
aggregate
implementation from MonitoredItem. Targeted sampling, aggregate
modification,
history/live handoff, queue/lifecycle, restore, and serialization cases
pass
**101/101 on net10.0 and 101/101 on net48**, without failures or skips.
Scoped formatting/analyzers are clean; the focused review found no
significant
issues. The final formatted monitored-item fixtures also pass 45/45 on
net48.

The preceding `b21555568` removes the legacy sampling API bridge and
durable
notification-priority state. Its targeted Server cases passed 97/97 and
shared
subscription-store cases passed 64/64 on each framework. The broader
evidence
below remains pinned to its original tested commit, not attributed to
these
follow-ups.

### Earlier integrated-implementation validation

Validated implementation commit: **`3efae597f`**. The following commit,
`f6dbefb1c`, only adds two explanatory comment lines for the final
standards
review; it changes no executable code.

| Scope | net10.0 | net48 |
| --- | --- | --- |
| Server | 5,187 passed; 56 skipped | Affected surface: 2,160 passed; 1
reproduced baseline failure; 56 skipped |
| Client | 2,202 passed; 2 skipped | 2,204 passed; 5 skipped |
| History integration | 519 passed; 21 skipped | 519 passed; 21 skipped
|
| Redundancy server | 641 passed | 641 passed |
| Redundancy client | 124 passed | 124 passed |
| Core shared-store regression suite | 23 passed | 23 passed |

All six affected samples passed non-incremental Release/net10.0 builds
with
zero warnings and errors: ConsoleReferenceClient,
ConsoleReferenceServer,
RedundantServer, RedundantClient, MinimalBoilerServer, and
PumpDeviceIntegrationServer.

The published self-contained win-x64 NativeAOT executable is 116,924,928
bytes and has no CLR header or managed runtime dependency. Direct
execution
passed **HistoryAotTests 3/3** and **RaftAotTests 2/2**.

Final standards and specification reviews found no confirmed outstanding
high/medium functional gaps or hard standards violations. The remaining
constructor-purpose clarification is addressed in `f6dbefb1c`.

### Reproduced baseline exceptions

The net48 hosted-startup timeout also reproduces in a pristine worktree
at
the previous PR head, `24cf1416d`, in

`RegisterPostStartRegistriesWiresHistorianAndAliasStoresOnPlainServerAsync`,
with the same subsequent certificate-leak assertion. The corresponding
renamed case fails before startup in the reviewed branch as well. This
is
reported separately from the net48 affected-surface results, not counted
as
a passing full Server suite. The net48 matrix selected the historian,
aggregate, monitored-item, fluent, and continuation surfaces and
excluded
the Hosting namespace.

`DurableDataValueQueueVerifyReferenceBatchingAsync` failed at item 1000
in
the net48 affected-surface run and passed its single isolated rerun. The
same
failure at the same assertion reproduces on pristine `849e16acc`; the
test,
sample queue, queue factory, and batch persistor are unchanged. The
original
failure remains in the table rather than being erased by the rerun.

### CI source repairs

- `4be7eb8f7` keeps diagnostics/configuration managers out of
distributed
address-space replication. Those managers inherit the source interface,
but their live server state and redundancy metadata must remain
replica-local.
  The ownership regression passes on net10.0 and net48, and all nine
  redundancy sample CI tests pass locally.
- `d17f467b3` completes the sample startup repair: core managers are
also
replica-local; the startup banner no longer advertises readiness before
initialization; the producer starts after distributed services; and
native
Raft startup no longer forces disruptive extra elections. The full
sample
suite passed 9/9, with initialized `RedundancySupport=Hot`, and focused
  Raft/address-space regressions passed 8/8 and 3/3.
- `81b0b72be` moves the unchanged distributed-historian NativeAOT
scenario
into a smaller, always-run companion executable to bound Apple's linker
input. All 137 AOT tests remain present; the moved test and helpers are
  unchanged. GitHub and Azure publish/run both native executables, with
separate result directories where they share a job. The companion passed
actual Windows NativeAOT execution. Linux and Intel macOS CI passed both
  executables, but this split alone did not fix ARM64 macOS linking.
The remaining historian graph is rooted by ReferenceServer startup, not
just the relocated test. No test exclusion or speculative linker setting
  was added to conceal it.
- `8a5842913` isolates the independent MCP test graph into an always-run
native host. The existing MCP source and assembly leak hooks are linked
  unchanged, and evaluated compiler inputs prove exactly one owner for
  every test source: 133 main + 3 MCP + 1 historian = 137 declarations.
All three hosts run on every AOT platform. The main Windows native
object
is 9.35% smaller; both changed publishes had zero diagnostics. MCP
passed
  3/3; the identical main executable passed 133/133 on one unfiltered
followup after two initial endpoint-discovery connection failures, which
  remain recorded in the local evidence.
- The previous Intel macOS job successfully published and executed its
native
tests, then failed on artifact-upload DNS (`ENOTFOUND`). No upload gate,
  shared environment setting, or cache configuration was disabled.

The first repair round also encountered the unrelated
`MetricsAreEmittedForChannelLifetimeAsync` timing failure on macOS Core.
Neither that test nor channel-manager code is changed by this PR, and
its
assertions remain intact. It passed unchanged on the final repair head.

On `d17f467b3`, the Linux and macOS redundancy sample jobs pass; the
remaining
failure was ARM64 Apple's `too many large addends` assertion. The
verified
upstream relocation-anchor fix (dotnet/runtime#124721, backport
dotnet/runtime#132171) is not present in the shipping ILCompiler
10.0.11.
An experimental multi-module probe failed and was rejected, not added to
CI.
On `8a5842913`,

[`aot-macos-latest`](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/34102158680/job/101678934057)
successfully publishes and executes all three native hosts on ARM64:
136 main runtime cases, 1 historian case, and 3 MCP cases, with no
skips.
The previous Apple linker blocker is resolved. Linux NativeAOT also
passes.
No assertion, test, shared environment setting, cache, or required gate
was
weakened.

The same CI run reports a separate macOS Sessions teardown failure: all
662 executed tests pass, but the global leak assertion detects one
undisposed certificate. The MCP partition changes no runtime, Sessions,
or
test-fixture code. A single unchanged diagnostic rerun is queued once
GitHub
permits rerunning that job; the failure is not suppressed or counted as
green.
Other CI checks are still pending.

## Related issues

- Fixes #4387
- Fixes #4400

## Checklist

- [ ] I have signed the CLA and read the contributing guide.
- [x] I have added regression tests and directly related documentation.
- [x] I have retained working reference and redundant-server sample
wiring.
- [x] Final validation and review evidence is complete, including the
baseline exceptions above.
- [ ] All required CI checks pass; the fail-fast rerun for `73c619435`
is pending.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9dbd9527-d818-47a0-984c-fbb1472d3d6b
marcschier added a commit to OPCFoundation/UA-.NETStandard that referenced this pull request Sep 8, 2026
# Description

Make startup-composed application NodeManagers participate in the live
lifecycle and bind imported NodeSet2 Method argument properties to their
typed `MethodState` children.

This change:

- adopts application NodeManagers created before startup into
`INodeManagerLifecycle.Registrations` after server startup succeeds,
while keeping diagnostics, configuration, and core managers protected;
- retains per-manager startup external-reference ownership and exact
routing positions so reload, removal, rollback, overlapping namespaces,
synchronous adapters, and server restart preserve existing behavior;
counted immutable reference snapshots avoid quadratic startup matching;
- rejects duplicate factory output across active, unpublished, and
retired lifecycle generations without deleting or disposing the live
manager; callers can catch the public
`NodeManagerAlreadyRegisteredException`;
- binds valid namespace-zero `Argument[]` `PropertyType`
`InputArguments` and `OutputArguments` Variables to
`MethodState.InputArguments` and `MethodState.OutputArguments` from
either `HasProperty` direction, without requiring `ParentNodeId`,
including local namespace-URI reference targets;
- preserves authored metadata during NodeSet typed-child promotion
without changing the initialization behavior of unrelated generated
nodes;
- retains generic-import guards for custom and malformed signatures,
duplicate standard-signature validation, and upstream factory-driven
generated-slot replacement and reconciliation callbacks;
- updates lifecycle and Runtime NodeSet documentation and clarifies
`OnServerStartedAsync` timing for both `StartAsync` overloads, including
the unopened default host returned to the caller.

This is a focused follow-up to #4418. That PR preserves registrations
from multiple fluent builders, but does not change lifecycle ownership
or NodeSet child typing. The branch includes upstream `master` through
`da7412c42`, including #4396, #4432, #4437, #4438, and #4440.

The completed review fixes in `686d0561f` are included. The latest base
merge (`a29fc6ca8`) combines them with #4432's shared batch/fluent
importer and generated state factories. One iterative linker supports
available parent nodes, deferred parent side tables, application-owned
handles, and placeholder reconciliation while retaining reference-driven
Method argument binding and URI handling. Upstream cancellation, GDS
assembly renames, certificate leak scoping, and xRegistry changes are
preserved.

## Related Issues

- Fixes #4421
- Fixes #4422

## CI regression fix

`e1a4436f0` fixes the GDS failure reported on Ubuntu and macOS. Copying
permission metadata in general `NodeState` initialization applied
`SecurityAdmin`-only defaults to generated GDS custom certificate groups
and denied their existing GDS-admin Browse requests. Metadata
preservation is now confined to NodeSet typed-child promotion; imported
Method argument permissions remain intact, while unrelated generated
nodes retain their existing initialization behavior.

Local Release validation also exposed a 260-character certificate path
in the startup-failure test added by this PR. Its isolated PKI now uses
a short temporary path. No assertions, authorization checks, or CI gates
were weakened, and no pre-existing tests were changed.

## macOS ARM64 NativeAOT suspension

Per maintainer request, `a15971f32` suspends only the failing
`macos-latest` / `osx-arm64` NativeAOT matrix entry. Re-enabling it once
the compiler contains the runtime fix is tracked in #4443. Intel macOS,
Linux, and Windows NativeAOT coverage, managed macOS tests, and all
other CI gates remain enabled. This is an explicit coverage suspension,
not a claim that the underlying compiler/linker defect is fixed.

The macOS ARM64 NativeAOT job on `a29fc6ca8` fails during native linking
with
`ld: Assertion failed: (_addend == uniqueIndex && "too many large
addends")`.
Both attempts of [run
34191755950](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/34191755950)
hit the same assertion before the native test executable can run; the
build/test summary failure is downstream.

This matches the NativeAOT Mach-O relocation issue in
dotnet/runtime#119380, fixed by relocation-anchor emission in
dotnet/runtime#124721 and its .NET 10 backport dotnet/runtime#132171.
The failing `Microsoft.DotNet.ILCompiler` 10.0.11 package's nuspec
points to `dotnet/dotnet` commit
`e2f47b0110ed922f21a1522da67279133ce28f32` (July 23); its object writer
does not contain the anchor fix merged on August 12. Version 10.0.11 is
currently the latest stable package.

The base commit passed on the same runner image and SDK, so this is not
being dismissed as a generally broken runner or a test flake. The
precise PR-specific object-layout trigger has not been isolated. A
compiler containing the relocation fix is needed before restoring the
lane. No test code, assertions, coverage thresholds, or shared tooling
settings were changed.

## Validation

Latest base-merge validation on both `net10.0` and `net48`, Release:

- Import helpers and argument-binding regressions: 51 passed per
framework.
- Batch/fluent import, generated-state overlays, runtime/startup
lifecycle, cross-source references, routing, reference snapshots, and
node-authoring selection: 344 passed per framework.
- Merge-specific cases cover available Method parents with
forward/inverse and URI/index references while retaining an
application-owned `NodeId` handle.
- The unchanged upstream `NodeSetImportIntegrationTests.cs:210` CA1861
warning remains; no diagnostic suppression or unrelated cleanup was
added.

Release CI-fix validation on both `net10.0` and `net48`:

- `CustomCertificateGroupIntegrationTest`: 4 passed, including the
unchanged CI failure.
- `UANodeSetHelpersTests`: 8 passed, including imported security
metadata.
- `StartupRuntimeNodeSetLifecycleTests`: 5 passed.

Earlier Debug merge and review validation on both frameworks:

- Lifecycle, RuntimeNodeSet, fluent, and OperationContext selection
after merging `978e6d1af`: 638 passed per framework.
- Startup/transport-binding and RuntimeNodeSet integration selection
after merging `017856f4a`: 28 passed per framework.
- Public exception contract and duplicate-registration selection in
`fbf08428b`: 6 passed per framework.

Targeted test invocations rebuilt the affected projects successfully.
The full `UA.slnx` suite was not rerun locally.

## Checklist

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [x] I have addressed **all** PR feedback received.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2bb8a834-7695-4ae6-84cb-2471c76d1b12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-NativeAOT-coreclr community-contribution Indicates that the PR has been added by a community member os-ios Apple iOS os-mac-os-x macOS aka OSX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ld64 crashing while Native AOT compiling Microsoft MCP for .NET 10

6 participants