-
Notifications
You must be signed in to change notification settings - Fork 1
Added KeyedSignal that represents a wait-by-key async signaling operation #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| catch (Exception ex) | ||
| { | ||
| LibraryEvents.OnSuppressedException(this, ex); | ||
| } |
Check notice
Code scanning / CodeQL
Generic catch clause Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
The best practice in scenarios requiring exception suppression (e.g., inside Dispose patterns) is to only catch exceptions derived from Exception that are not considered fatal—that is, not system-critical exceptions such as OutOfMemoryException, StackOverflowException, ThreadAbortException, or the base SystemException. The catch-all block should be narrowed by adding a when filter that ignores fatal exceptions, or by explicitly catching only non-fatal exceptions.
In modern .NET, the recommended method is to exclude these fatal exceptions using a helper function, e.g., IsFatal(Exception), to determine if an exception is fatal before handling it/suppressing it. We can introduce this helper, and catch only if the exception is not fatal—otherwise, allow it to propagate.
To implement this, edit the catch block in the Dispose method in src/Gemstone.Threading/KeyedSignal.cs as follows:
- Add a private static helper method, e.g.,
IsFatal(Exception ex), inside the same class. - Change the
catch (Exception ex)line to include awhenclause:catch (Exception ex) when (!IsFatal(ex)).
No additional dependencies are needed.
-
Copy modified line R134 -
Copy modified lines R406-R413
| @@ -131,7 +131,7 @@ | ||
| { | ||
| m_pruneTask.Wait(); | ||
| } | ||
| catch (Exception ex) | ||
| catch (Exception ex) when (!IsFatal(ex)) | ||
| { | ||
| LibraryEvents.OnSuppressedException(this, ex); | ||
| } | ||
| @@ -403,4 +403,12 @@ | ||
| } | ||
|
|
||
| #endregion | ||
| /// <summary> | ||
| /// Determines if the exception is considered fatal and should not be caught/suppressed. | ||
| /// </summary> | ||
| private static bool IsFatal(Exception ex) => | ||
| ex is OutOfMemoryException | ||
| or StackOverflowException | ||
| or ThreadAbortException | ||
| or AccessViolationException; | ||
| } |
| catch (Exception ex) | ||
| { | ||
| LibraryEvents.OnSuppressedException(this, ex); | ||
| } |
Check notice
Code scanning / CodeQL
Generic catch clause Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
To fix the overly broad generic catch clause, narrow the set of caught exceptions in DisposeAsync. The most likely expected exception from await m_pruneTask.ConfigureAwait(false); is OperationCanceledException, given the cancellation logic. Other exceptions are either unexpected or indicative of deeper errors that might better be allowed to propagate or rethrow (or at least have more targeted handling).
Best approach:
- Change
catch (Exception ex)tocatch (OperationCanceledException ex), which aligns with expected cancellation and suppression intent in Dispose. - Optionally, if other exception types are reasonably safe to suppress (e.g.,
ObjectDisposedException), catch and log those specifically. - If you must catch other exceptions (because disposal should never fail), add a second
catchfor genericException ex, log it, but document that this is intentional, or rethrow critical exceptions (such as those inheriting fromSystemError).
Specifically:
- In file
src/Gemstone.Threading/KeyedSignal.cs:- Line 162: Replace
catch (Exception ex)withcatch (OperationCanceledException ex) - Optionally add a broader catch below for unexpected exceptions documenting why they're being suppressed (optional per project policy)
- Line 162: Replace
- No new imports needed.
-
Copy modified line R162 -
Copy modified line R164 -
Copy modified lines R167-R172
| @@ -159,10 +159,17 @@ | ||
| { | ||
| await m_pruneTask.ConfigureAwait(false); | ||
| } | ||
| catch (Exception ex) | ||
| catch (OperationCanceledException ex) | ||
| { | ||
| // Suppress expected cancellation exceptions during disposal. | ||
| LibraryEvents.OnSuppressedException(this, ex); | ||
| } | ||
| // Optionally, handle and log other unexpected exceptions. | ||
| // Uncomment below if you wish to report/log all exceptions but not suppress critical errors: | ||
| //catch (Exception ex) when (!(ex is OutOfMemoryException || ex is StackOverflowException || ex is ThreadAbortException)) | ||
| //{ | ||
| // LibraryEvents.OnSuppressedException(this, ex); | ||
| //} | ||
|
|
||
| m_pruneTimer?.Dispose(); | ||
| m_pruneCompletionSource.Dispose(); |
| catch (Exception ex) | ||
| { | ||
| return (default!, ex); | ||
| } |
Check notice
Code scanning / CodeQL
Generic catch clause Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
To fix the problem, replace the overly broad catch (Exception ex) block in the Wait method with more specific catch clauses for the exceptions that are part of normal operation and intended error modes. In this context, these likely include OperationCanceledException for cancellations and ObjectDisposedException for disposed object access. Any unhandled exceptions should be allowed to propagate to the caller. Make this change only in the Wait method, lines 212–215 in file src/Gemstone.Threading/KeyedSignal.cs, and do not change other code or imports unless essential.
-
Copy modified line R212 -
Copy modified lines R216-R219
| @@ -209,10 +209,14 @@ | ||
| TResult result = WaitAsync(key, cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult(); | ||
| return (result, null); | ||
| } | ||
| catch (Exception ex) | ||
| catch (OperationCanceledException ex) | ||
| { | ||
| return (default!, ex); | ||
| } | ||
| catch (ObjectDisposedException ex) | ||
| { | ||
| return (default!, ex); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> |
Merge development branch into master