Skip to content

Fix Race condition in OnPublishComplete#3837

Merged
marcschier merged 1 commit into
OPCFoundation:master378from
markuswallen:fix/session-publish-complete-subscription-list-race-condition
Jun 3, 2026
Merged

Fix Race condition in OnPublishComplete#3837
marcschier merged 1 commit into
OPCFoundation:master378from
markuswallen:fix/session-publish-complete-subscription-list-race-condition

Conversation

@markuswallen

Copy link
Copy Markdown
Contributor

Description

The catch block in OnPublishComplete reads m_subscriptions.Count and m_subscriptions.Any(s => s.Created) without holding m_lock, while all other accesses (AddSubscription, RemoveSubscriptionAsync, RemoveTransferredSubscription) correctly lock before modifying the list.

This causes an InvalidOperationException ("Collection was modified; enumeration operation may not execute") when a publish response errors concurrently with a subscription being removed during reconnect.

Snapshot both values under m_lock, consistent with all other call sites.

Related Issues

Checklist

Put an x in the boxes that apply. You can complete these step by step after opening the PR.

  • I have signed the CLA and read the CONTRIBUTING doc.
  • I have added tests that prove my fix is effective or that my feature works and increased code coverage.
  • I have added all necessary documentation.
  • 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.
  • I have addressed all PR feedback received.

The catch block in OnPublishComplete reads m_subscriptions.Count and
m_subscriptions.Any(s => s.Created) without holding m_lock, while all
other accesses (AddSubscription, RemoveSubscriptionAsync,
RemoveTransferredSubscription) correctly lock before modifying the list.

This causes an InvalidOperationException ("Collection was modified;
enumeration operation may not execute") when a publish response errors
concurrently with a subscription being removed during reconnect.

Snapshot both values under m_lock, consistent with all other call sites.
@romanett

romanett commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@marcschier is this fix also needed for master (ClassicSubscriptionEngine)

@marcschier

Copy link
Copy Markdown
Collaborator

@marcschier is this fix also needed for master (ClassicSubscriptionEngine)

No, we already lock and copy in master. The copilot provided fix was just replacing linq Any, which would make it faster, sure, but this is on exception path, so lets leave for now.

@marcschier
marcschier merged commit af06431 into OPCFoundation:master378 Jun 3, 2026
51 checks passed
GoetzGoerisch pushed a commit to umati/connect that referenced this pull request Jul 2, 2026
…5.378.152 (#21)

This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [OPCFoundation.NetStandard.Opc.Ua](https://github.com/OPCFoundation/UA-.NETStandard) | `1.5.378.145` → `1.5.378.152` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/OPCFoundation.NetStandard.Opc.Ua/1.5.378.152?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/OPCFoundation.NetStandard.Opc.Ua/1.5.378.145/1.5.378.152?slim=true) |

---

### Release Notes

<details>
<summary>OPCFoundation/UA-.NETStandard (OPCFoundation.NetStandard.Opc.Ua)</summary>

### [`v1.5.378.152`](https://github.com/OPCFoundation/UA-.NETStandard/releases/tag/1.5.378.152): OPC UA 1.05 Maintenance Update

[Compare Source](OPCFoundation/UA-.NETStandard@1.5.378.145...1.5.378.152)

Maintenance Release for fixing bugs found on the main378 development branch.

#### Released packages

[OPCFoundation.NetStandard.Opc.Ua](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Core](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Core/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Security.Certificates](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Security.Certificates/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Configuration](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Configuration/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Server](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Server/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Client](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Client/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Bindings.Https](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Bindings.Https/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.PubSub](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.PubSub/1.5.378.152)

#### What's Changed

- Fix memory leak: dispose linked CancellationTokenSource in ChannelAsyncOperation.EndAsync by [@&#8203;romanett](https://github.com/romanett) with [@&#8203;Copilot](https://github.com/Copilot) in [#&#8203;3812](OPCFoundation/UA-.NETStandard#3812)
- Fix Race condition in OnPublishComplete by [@&#8203;markuswallen](https://github.com/markuswallen) in [#&#8203;3837](OPCFoundation/UA-.NETStandard#3837)
- \[master378] Use request.SessionId instead of request.Session.Id in the ReportAuditCancelEvent call from CancelRequests. by [@&#8203;mrsuciu](https://github.com/mrsuciu) in [#&#8203;3853](OPCFoundation/UA-.NETStandard#3853)
- Prune extra decoded children that should stay on the type definition only. by [@&#8203;mrsuciu](https://github.com/mrsuciu) in [#&#8203;3843](OPCFoundation/UA-.NETStandard#3843)
- \[Server] Fix NRE in ActivateSession if Session times out before activation completes by [@&#8203;romanett](https://github.com/romanett) in [#&#8203;3844](OPCFoundation/UA-.NETStandard#3844)
- \[Server] Fix [#&#8203;3896](OPCFoundation/UA-.NETStandard#3896): send full certificate chain when CA is in the issuer store (1.5.x) by [@&#8203;marcschier](https://github.com/marcschier) in [#&#8203;3898](OPCFoundation/UA-.NETStandard#3898)
- Synchronize ConditionState branch collection access by [@&#8203;marcschier](https://github.com/marcschier) with [@&#8203;Copilot](https://github.com/Copilot) in [#&#8203;3895](OPCFoundation/UA-.NETStandard#3895)
- Prepare 1.5.378 maintenence release by [@&#8203;mrsuciu](https://github.com/mrsuciu) in [#&#8203;3893](OPCFoundation/UA-.NETStandard#3893)

**Full Changelog**: <OPCFoundation/UA-.NETStandard@1.5.378.145...1.5.378.152>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM (`* 0-3 * * *`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://codeberg.org/umati/connect/pulls/21
GoetzGoerisch pushed a commit to umati/connect that referenced this pull request Jul 2, 2026
…r to 1.5.378.152 (#22)

This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [OPCFoundation.NetStandard.Opc.Ua.Server](https://github.com/OPCFoundation/UA-.NETStandard) | `1.5.378.145` → `1.5.378.152` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/OPCFoundation.NetStandard.Opc.Ua.Server/1.5.378.152?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/OPCFoundation.NetStandard.Opc.Ua.Server/1.5.378.145/1.5.378.152?slim=true) |

---

### Release Notes

<details>
<summary>OPCFoundation/UA-.NETStandard (OPCFoundation.NetStandard.Opc.Ua.Server)</summary>

### [`v1.5.378.152`](https://github.com/OPCFoundation/UA-.NETStandard/releases/tag/1.5.378.152): OPC UA 1.05 Maintenance Update

[Compare Source](OPCFoundation/UA-.NETStandard@1.5.378.145...1.5.378.152)

Maintenance Release for fixing bugs found on the main378 development branch.

#### Released packages

[OPCFoundation.NetStandard.Opc.Ua](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Core](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Core/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Security.Certificates](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Security.Certificates/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Configuration](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Configuration/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Server](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Server/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Client](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Client/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.Bindings.Https](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.Bindings.Https/1.5.378.152)
[OPCFoundation.NetStandard.Opc.Ua.PubSub](https://www.nuget.org/packages/OPCFoundation.NetStandard.Opc.Ua.PubSub/1.5.378.152)

#### What's Changed

- Fix memory leak: dispose linked CancellationTokenSource in ChannelAsyncOperation.EndAsync by [@&#8203;romanett](https://github.com/romanett) with [@&#8203;Copilot](https://github.com/Copilot) in [#&#8203;3812](OPCFoundation/UA-.NETStandard#3812)
- Fix Race condition in OnPublishComplete by [@&#8203;markuswallen](https://github.com/markuswallen) in [#&#8203;3837](OPCFoundation/UA-.NETStandard#3837)
- \[master378] Use request.SessionId instead of request.Session.Id in the ReportAuditCancelEvent call from CancelRequests. by [@&#8203;mrsuciu](https://github.com/mrsuciu) in [#&#8203;3853](OPCFoundation/UA-.NETStandard#3853)
- Prune extra decoded children that should stay on the type definition only. by [@&#8203;mrsuciu](https://github.com/mrsuciu) in [#&#8203;3843](OPCFoundation/UA-.NETStandard#3843)
- \[Server] Fix NRE in ActivateSession if Session times out before activation completes by [@&#8203;romanett](https://github.com/romanett) in [#&#8203;3844](OPCFoundation/UA-.NETStandard#3844)
- \[Server] Fix [#&#8203;3896](OPCFoundation/UA-.NETStandard#3896): send full certificate chain when CA is in the issuer store (1.5.x) by [@&#8203;marcschier](https://github.com/marcschier) in [#&#8203;3898](OPCFoundation/UA-.NETStandard#3898)
- Synchronize ConditionState branch collection access by [@&#8203;marcschier](https://github.com/marcschier) with [@&#8203;Copilot](https://github.com/Copilot) in [#&#8203;3895](OPCFoundation/UA-.NETStandard#3895)
- Prepare 1.5.378 maintenence release by [@&#8203;mrsuciu](https://github.com/mrsuciu) in [#&#8203;3893](OPCFoundation/UA-.NETStandard#3893)

**Full Changelog**: <OPCFoundation/UA-.NETStandard@1.5.378.145...1.5.378.152>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - Between 12:00 AM and 03:59 AM (`* 0-3 * * *`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI0OS41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://codeberg.org/umati/connect/pulls/22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants