-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
encoding/json: potential deadlock in sync.WaitGroup usage within JSON encoder cache initialization #70753
Comments
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
@ lss25 Is this still an issue with one of the currently supported versions of Go (1.22 or 1.23)? Can you provide a snippet of code that clearly demonstrates the bug? |
@cagedmantis The issue still persists. In Go version 1.23, within the file src/encoding/json/encode.go at line 373, the typeEncoder function does not call wg.Done() before the statement return fi.(encoderFunc), which can still lead to a deadlock. This PR resolves the aforementioned deadlock issue. |
@lss25 Thanks for pointing to the code. Do you have a test case that demonstrates the bug? I ask because we certainly want to add a test when making any change of this sort, and you may already have a test that we can reuse. Thanks. |
@ianlancetaylor The deadlock mentioned above is not a bug; it was my misunderstanding. There will be only one sync.WaitGroup whose count doesn't return to zero, but it will not cause a deadlock. |
Thanks. As far as I can tell the change you suggest will never make a difference. There is no particular rule that we have to call |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I encountered an issue related to the concurrent initialization of type encoders in the JSON package while working with recursive types. The code problematic is located in:
File:
src/encoding/json/encode.go
What did you expect to see?
I expected the JSON package's typeEncoder function to handle recursive types reliably during concurrent initialization without any risk of deadlock, ensuring smooth and efficient operations.
What did you see instead?
Instead, I experienced a potential deadlock scenario caused by the use of
sync.WaitGroup
in the process of initializing these type encoders. Here's a Detailed Explanation of the problem:The implementation uses a
sync.WaitGroup
to block execution for partially initialized encoders concerning recursive types. If two goroutines both attempt to initialize the encoder for the samereflect.Type
simultaneously, a deadlock might occur. Both goroutines find the encoder uninitialized, add to the wait group, and attempt to store their respective partially constructed encoders. However, when one goroutine completes its initialization and callswg.Done()
, the second goroutine is left waiting indefinitely because the wait group's counter is incremented twice but decremented only once.Impact: This deadlock may affect the performance and reliability of applications that use the
encoding/json
package for complex recursive types.Suggested Solution: Ensure that every increment of the wait group counter is matched by its decrement across all execution paths. One approach is always to decrement the counter whenever a goroutine finds it is not the first to execute a store operation.
Proposed Code Snippet:
By improving the synchronization approach or redesigning the caching strategy, such as eliminating the need for
WaitGroup
s in this context, we can safeguard against deadlocks in concurrent setups.The text was updated successfully, but these errors were encountered: