Skip to content

[4.2] [PlaygroundLogger] Add checks in the logger entrypoints to prevent recursive logging. #30

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

Merged

Conversation

cwakamo
Copy link
Member

@cwakamo cwakamo commented Sep 9, 2018

The logger entrypoints now consult a C-defined thread-local bool and exit immediately if the current thread is already logging. If the current thread is not logging, they set the bool to indicate that it is, and then unset it at the end of the function.

This allows types which reference self in their implementations of CustomPlaygroundQuickLookable or CustomStringConvertible (among other things) in such a way that self would be logged to not cause infinite recursion in the logger. It also means that logging won't log the side-effects of logging anymore.

This pulls the changes from #29 into swift-4.2-branch for a potential 4.2.x update, addressing rdar://problem/41460357 / SR-8349.

Added a thread-local `bool`, `PGLThreadIsLogging`, which is used in each of the logger entrypoints. This is defined in C as it's not possible (to my knowledge) to create a thread-local variable in Swift.
Each of the logger entrypoints first checks this value; if it's `true`, then the function returns nil. If it's `false`, then the function sets it to `true`, defers setting it back to `false`, and then generates the log packet.
This allows logging to complete successfully in cases when logging a value would cause that value to be logged (e.g. if the implementation of `CustomStringConvertible` or `CustomPlaygroundDisplayConvertible` caused `self` to be logged).

This addresses <rdar://problem/41460357> / SR-8349.

(cherry picked from commit c8af268)
Added tests for both the new and legacy entrypoints to ensure that recursive logging does not occur.
In both cases, a struct whose implementation of `CustomStringConvertible` logs `self` is logged.
Without the changes in the previous commit, this causes infinite recursion.
With those changes, these tests pass as expected.

This is for <rdar://problem/41460357> / SR-8349.

(cherry picked from commit 58f43da)
…d set `PGLThreadIsLogging`.

This is to insulate from any issues which might arise because Swift may or may not handle `__thread` variables correctly.

(cherry picked from commit e2fcd53)
@cwakamo
Copy link
Member Author

cwakamo commented Sep 9, 2018

• Explanation: Previous versions of PlaygroundLogger would never skip logging, even if a thread was already logging. This causes the side-effects of logging to be logged, which can cause infinite recursion in otherwise valid code. This change makes it so each thread tracks whether or not it is logging and returns nil if it already is logging, preventing this infinite recursion.
• Scope of Issue: Affects playgrounds which reference self in CustomStringConvertible, CustomPlaygroundDisplayConvertible, or other protocols or methods consulted during logging.
• SR Issue: SR-8349
• Risk: The biggest risk here is that we may skip logging too many things, but the changes are very straightforward so I think this is a low risk.
• Testing: Added new tests to the PlaygroundLogger test suite which simulate this scenario.
• Reviewer: @jonathanpenn (in #29)

@tkremenek previously approved pulling this into swift-4.2-branch in email, so I'll be merging this shortly.

@cwakamo cwakamo merged commit 7da6532 into apple:swift-4.2-branch Sep 9, 2018
@cwakamo cwakamo deleted the prevent-recursive-logging-4.2 branch September 9, 2018 21:25
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.

1 participant