Skip to content
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

Remove most usages of the macro-based "don't return in this block" hack #113856

Merged
merged 11 commits into from
Mar 26, 2025

Conversation

jkoritzinsky
Copy link
Member

We have hack in the CoreCLR codebase where we define the return keyword as a macro with a for loop that depends on typedefs to enable blocking returns from within specific blocks of code.

This has caused issues that have had to be fixed in the following PRs:

#67464
#109756
#113279

Many of these blocks of code can be adjusted slightly to not require this mechanism to act correctly or already do not require it. Also, some usages are just dead code entirely.

This PR does not remove the mechanism as it does not remove all usages of it. The final usage (as mentioned in #67470) is in the support logic for HelperMethodFrames. As we are removing HMFs from the runtime (#95695), I figure that we can remove this mechanism after we remove HMFs instead of trying to figure out how to re-implement the HMF logic such that returns are safe.

…ugh those macros are automatically removed by the constructor
…ring that we don't do a return to ensure we call a function in the success case.
…R scope as nothing in the uninstall requires manual unwinding.
…view to not allow people to return out of a contract block.
Copy link
Member Author

Choose a reason for hiding this comment

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

The changes in this file are the most "sketchy" to me as they add a dependency on the C++ Standard Library's exception APIs. As we already use C++ exceptions all over the VM, this isn't that out of the ordinary (and if we used a different mechanism, we wouldn't be considering using this API anyway).

@@ -358,11 +357,9 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
bool __fExceptionCaught = false; \
SCAN_EHMARKER(); \
if (true) PAL_CPP_TRY { \
SCAN_EHMARKER_TRY(); \
DEBUG_ASSURE_NO_RETURN_BEGIN(IUACH);
Copy link
Member Author

Choose a reason for hiding this comment

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

Nothing in the enclosing block in the INSTALL macros nor any code following in the UNINSTALL macros depend on us not returning from within this block.

Copy link
Member Author

@jkoritzinsky jkoritzinsky Mar 24, 2025

Choose a reason for hiding this comment

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

Technically it is still unsafe to return from within a CONTRACT block. However, I believe that it is quite obvious that it is incorrect to do so, to the point that it would immediately pop out in code-review as an issue that must be fixed (to the point that I would expect AI code review tools like Copilot to flag it as suspicious).

@jkoritzinsky jkoritzinsky marked this pull request as ready for review March 24, 2025 21:49
@jkotas jkotas requested a review from janvorli March 24, 2025 22:19

#define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \
GCFrame __gcframe( \
pThread, \
(OBJECTREF*)&(ObjRefStruct), \
sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
FALSE); \
/* work around unreachable code warning */ \
if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
Copy link
Member

Choose a reason for hiding this comment

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

A note - I believe this removal is correct because we have changed the GCFrame to call Pop from the destructor couple of years ago. The requirement for no return was already obsolete.

…er as it shouldn't happen in that case for unwinding.
@jkotas
Copy link
Member

jkotas commented Mar 25, 2025

My suggestion would be:

  • For BEGIN_PRESERVE_LAST_ERROR, delete the macro without replacement. The macro is not used in that many places - it should be ok to depend on code review to catch issues.

  • For CoopTransitionHolder, enforce it using runtime assert (the runtime assert can use std::uncaught_exception). Do not use std::uncaught_exception for release build since it has unknown reliability and performance implications.

…ansitionHolder by a runtime assert instead of a compile-time error.
@jkoritzinsky
Copy link
Member Author

/ba-g failures unrelated

@jkoritzinsky jkoritzinsky merged commit 379af99 into dotnet:main Mar 26, 2025
93 of 95 checks passed
@jkoritzinsky jkoritzinsky deleted the cleanup-noreturn branch March 26, 2025 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants