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

JsonDocument.GetString implementation is not thread safe #76440

Closed
eiriktsarpalis opened this issue Sep 30, 2022 · 7 comments · Fixed by #76716
Closed

JsonDocument.GetString implementation is not thread safe #76440

eiriktsarpalis opened this issue Sep 30, 2022 · 7 comments · Fixed by #76716

Comments

@eiriktsarpalis
Copy link
Member

eiriktsarpalis commented Sep 30, 2022

Even though JsonDocument is nominally immutable (modulo disposability), the internal GetString implementation employs a caching scheme that is not thread safe:

private (int, string?) _lastIndexAndString = (-1, null);

Since the cached field is a struct that cannot be written to or read from atomically. It might be that we could fix this in the code using a regular System.Tuple, thus ensuring atomic access to cached entries. Obviously this has the downside of incurring one additional allocation, but at least we can guarantee immutability (modulo disposability of course).

Related to #17975

cc @layomia @krwq

Originally posted by @eiriktsarpalis in dotnet/docs#20563 (comment)

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Sep 30, 2022
@eiriktsarpalis eiriktsarpalis changed the title > however we tripped over the caching that is done via _lastIndexAndString (i.e., if multiple threads call GetString on an element at the same time, then they may get back the wrong value). JsonDocument.GetString implementation is not thread safe Sep 30, 2022
@eiriktsarpalis eiriktsarpalis added area-System.Text.Json and removed untriaged New issue has not been triaged by the area owner labels Sep 30, 2022
@ghost
Copy link

ghost commented Sep 30, 2022

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details
    > however we tripped over the caching that is done via _lastIndexAndString (i.e., if multiple threads call GetString on an element at the same time, then they may get back the wrong value).

Looking at the code, I would guess that this can only happen because of torn reads/writes. It might be that we could fix this in the code using a regular System.Tuple, thus ensuring atomic access to cached entries. Obviously this has the downside of incurring one additional allocation, but at least we can guarantee immutability (modulo disposability of course).

Related to #17975

cc @layomia @krwq

Originally posted by @eiriktsarpalis in dotnet/docs#20563 (comment)

Author: eiriktsarpalis
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@eiriktsarpalis eiriktsarpalis added this to the Future milestone Sep 30, 2022
@eiriktsarpalis
Copy link
Member Author

Related issues: #17975, #31911, #28711

@stephentoub
Copy link
Member

Do we document JsonDocument as being thread-safe? We generally don't make any guarantees about thread-safety of instance members unless otherwise explicitly documented, and there are many places where instance members do non-thread-safe caching. What makes this one special enough to be worth adding cost?

And, what is this particular cache used for? Is it really common to ask for the same string at the same index multiple times in a row with no intervening other requests?

@eiriktsarpalis
Copy link
Member Author

eiriktsarpalis commented Sep 30, 2022

Do we document JsonDocument as being thread-safe?

We do, the original issue in docs was opened to account for that discrepancy. I created this separate issue to track potentially making the type thread safe in the future.

@stephentoub stephentoub self-assigned this Sep 30, 2022
@ghost ghost added in-pr There is an active PR which will close this issue when it is merged and removed in-pr There is an active PR which will close this issue when it is merged labels Sep 30, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Oct 6, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Oct 11, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Nov 10, 2022
@rymeskar
Copy link

@stephentoub
Because of the possible cross-polination of values, should this fix be marked as security fix?

@stephentoub
Copy link
Member

I don't believe that's warranted.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.