| 949 | }; |
| 950 | |
| 951 | Result<S3ClientLock> S3ClientHolder::Lock() { |
| 952 | std::shared_ptr<S3ClientFinalizer> finalizer; |
| 953 | std::shared_ptr<S3Client> client; |
| 954 | { |
| 955 | std::unique_lock lock(mutex_); |
| 956 | finalizer = finalizer_.lock(); |
| 957 | client = client_; |
| 958 | } |
| 959 | // Do not hold mutex while taking finalizer lock below. |
| 960 | // |
| 961 | // Acquiring a shared_mutex in shared mode may block even if not already |
| 962 | // acquired in exclusive mode, because of pending writers: |
| 963 | // https://github.com/google/sanitizers/issues/1668#issuecomment-1624985664 |
| 964 | // """It is implementation-defined whether the calling thread acquires |
| 965 | // the lock when a writer does not hold the lock and there are writers |
| 966 | // blocked on the lock""". |
| 967 | // |
| 968 | // Therefore, we want to avoid potential lock ordering issues |
| 969 | // even when a shared lock is involved (GH-36523). |
| 970 | if (!finalizer) { |
| 971 | return ErrorS3Finalized(); |
| 972 | } |
| 973 | |
| 974 | S3ClientLock client_lock; |
| 975 | // Lock the finalizer before examining it |
| 976 | client_lock.lock_ = finalizer->LockShared(); |
| 977 | if (finalizer->finalized_) { |
| 978 | return ErrorS3Finalized(); |
| 979 | } |
| 980 | // (the client can be cleared only if finalizer->finalized_ is true) |
| 981 | DCHECK(client) << "inconsistent S3ClientHolder"; |
| 982 | client_lock.client_ = std::move(client); |
| 983 | return client_lock; |
| 984 | } |
| 985 | |
| 986 | void S3ClientHolder::Finalize() { |
| 987 | std::shared_ptr<S3Client> client; |
no test coverage detected