Skip to content

Commit 7fa60a3

Browse files
committed
handle the race where the result is modified after its reference is returned
1 parent 190d114 commit 7fa60a3

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

libs/internal/include/launchdarkly/async/promise.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,17 @@ class PromiseInternal {
150150
// Returns a const reference to the optional result. The optional contains
151151
// a value if resolved, or is empty if not yet resolved. The reference is
152152
// valid for the lifetime of any Future referring to this PromiseInternal.
153+
//
154+
// Thread-safety: if the future is already resolved, the reference points
155+
// to write-once storage and is safe to read without holding the lock. If
156+
// the future is not yet resolved, the reference points to empty_, a const
157+
// member that is never written, so it is equally safe.
153158
std::optional<T> const& GetResult() const {
154159
std::lock_guard lock(mutex_);
155-
return *result_;
160+
if (result_->has_value()) {
161+
return *result_;
162+
}
163+
return empty_;
156164
}
157165

158166
// Then where the continuation returns R directly, yielding Future<R>.
@@ -260,6 +268,7 @@ class PromiseInternal {
260268
new std::optional<T>(std::nullopt)};
261269
std::vector<Continuation<void(std::shared_ptr<std::optional<T>>)>>
262270
continuations_;
271+
std::optional<T> const empty_{};
263272
};
264273

265274
// Promise is the write end of a one-shot async value, similar to std::promise.

0 commit comments

Comments
 (0)