-
Notifications
You must be signed in to change notification settings - Fork 2.5k
config_file: fix race when creating an iterator #5282
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
Does clar provide a facility to test async behavior? |
On Sat, Oct 26, 2019 at 01:04:24AM -0700, Erik Aigner wrote:
Does clar provide a facility to test async behavior?
Well, we do have some tests in "tests/threads", but that's about
it. Things is that "docs/threading.md" explicitly says:
Unless otherwise specified, libgit2 objects cannot be safely
accessed by multiple threads simultaneously.
Thus, things cannot be used from multiple threads at the same
time, at least officially. The truth is probably somewhat mixed,
as we tried to get some subsystems to behave just fine with
locking and refcounting. I'm always happy to fix any race
conditions as well, but one should always keep in mind our
official stance.
|
Yes, I know. Still, its hard to avoid race conditions if you are not using libgit in a commandline fashion, at which point one might just as well parse git output ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for the fixes and cleanups @pks-t 🙇 !
The configuration snapshot backend has been extracted from the old files backend back in 2bff84b (config_file: separate out read-only backend, 2019-07-26). To keep code churn manageable, the local functions weren't renamed yet and thus still have references to the old diskfile backend. Rename them accordingly to make them easier to understand.
As with the predecessing commit, this commit renames backend functions of the configuration file backend. This helps to clearly separate functionality and also to be able to see from backtraces which backend is currently in use.
The function to take a reference to the config file's config entries currently returns the reference via return value. Due to this, it's harder than necessary to integrate into our typical coding style, as one needs to make sure that a proper error code is set before erroring out from the caller. This bites us in `config_file_delete`, where we call `goto out` directly when `config_file_entries_take` returns `NULL`, but we actually forget to set up the error code and thus return success. Fix the issue by refactoring the function to return an error code and pass the reference via an out-pointer.
When creating a configuration file iterator, then we first refresh the backend and then afterwards duplicate all refreshed configuration entries into the iterator in order to avoid seeing any concurrent modifications of the entries while iterating. The duplication of entries is not guarded, though, as we do not increase the refcount of the entries that we duplicate right now. This opens us up for a race, as another thread may concurrently refresh the repository configuration and thus swap out the current set of entries. As we didn't increase the refcount, this may lead to the entries being free'd while we iterate over them in the first thread. Fix the issue by properly handling the lifecycle of the backend's entries via `config_file_entries_take` and `git_config_entries_free`, respectively.
63bc45e
to
56b203a
Compare
Rebased to fix conflicts with #5293 |
When creating a configuration file iterator, then we first refresh the
backend and then afterwards duplicate all refreshed configuration
entries into the iterator in order to avoid seeing any concurrent
modifications of the entries while iterating. The duplication of entries
is not guarded, though, as we do not increase the refcount of the
entries that we duplicate right now. This opens us up for a race, as
another thread may concurrently refresh the repository configuration and
thus swap out the current set of entries. As we didn't increase the
refcount, this may lead to the entries being free'd while we iterate
over them in the first thread.
Fix the issue by properly handling the lifecycle of the backend's
entries via
config_file_entries_take
andgit_config_entries_free
,respectively.
I think this may be the likely cause of #5281, as it fixes a severe race condition in exactly the code path that #5281 shows.