Skip to content

Commit f3f1b7b

Browse files
fix(cpp): resolve Task UB and idempotent get() in base.hpp
1 parent 5923b5a commit f3f1b7b

2 files changed

Lines changed: 20 additions & 8 deletions

File tree

examples/cpp/include/appwrite/base.hpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ struct Task {
192192
~Task() { if (handle) handle.destroy(); }
193193
Task(Task&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
194194
T get() {
195-
handle.resume(); // single resume — safe, coroutine runs to completion
195+
if (handle && !handle.done()) handle.resume();
196196
if (!handle.promise().result) throw AppwriteException("Coroutine did not return a value");
197197
if (handle.promise().result->index() == 1) std::rethrow_exception(std::get<1>(*handle.promise().result));
198198
return std::move(std::get<0>(*handle.promise().result));
@@ -206,7 +206,11 @@ struct Task {
206206
task_.handle.resume();
207207
h.resume();
208208
}
209-
T await_resume() { return task_.get(); }
209+
T await_resume() {
210+
auto& res = *task_.handle.promise().result;
211+
if (res.index() == 1) std::rethrow_exception(std::get<1>(res));
212+
return std::move(std::get<0>(res));
213+
}
210214
};
211215
// Note: Task is move-only. After co_await, the original Task handle is null.
212216
return Awaiter{std::move(*this)};
@@ -229,7 +233,7 @@ struct Task<void> {
229233
~Task() { if (handle) handle.destroy(); }
230234
Task(Task&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
231235
void get() {
232-
handle.resume(); // single resume
236+
if (handle && !handle.done()) handle.resume();
233237
if (handle.promise().exception) std::rethrow_exception(handle.promise().exception);
234238
}
235239

@@ -241,7 +245,9 @@ struct Task<void> {
241245
task_.handle.resume();
242246
h.resume();
243247
}
244-
void await_resume() { task_.get(); }
248+
void await_resume() {
249+
if (task_.handle.promise().exception) std::rethrow_exception(task_.handle.promise().exception);
250+
}
245251
};
246252
// Note: Task is move-only. After co_await, the original Task handle is null.
247253
return Awaiter{std::move(*this)};

templates/cpp/include/base.hpp.twig

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ struct Task {
192192
~Task() { if (handle) handle.destroy(); }
193193
Task(Task&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
194194
T get() {
195-
handle.resume(); // single resume — safe, coroutine runs to completion
195+
if (handle && !handle.done()) handle.resume();
196196
if (!handle.promise().result) throw AppwriteException("Coroutine did not return a value");
197197
if (handle.promise().result->index() == 1) std::rethrow_exception(std::get<1>(*handle.promise().result));
198198
return std::move(std::get<0>(*handle.promise().result));
@@ -206,7 +206,11 @@ struct Task {
206206
task_.handle.resume();
207207
h.resume();
208208
}
209-
T await_resume() { return task_.get(); }
209+
T await_resume() {
210+
auto& res = *task_.handle.promise().result;
211+
if (res.index() == 1) std::rethrow_exception(std::get<1>(res));
212+
return std::move(std::get<0>(res));
213+
}
210214
};
211215
// Note: Task is move-only. After co_await, the original Task handle is null.
212216
return Awaiter{std::move(*this)};
@@ -229,7 +233,7 @@ struct Task<void> {
229233
~Task() { if (handle) handle.destroy(); }
230234
Task(Task&& other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
231235
void get() {
232-
handle.resume(); // single resume
236+
if (handle && !handle.done()) handle.resume();
233237
if (handle.promise().exception) std::rethrow_exception(handle.promise().exception);
234238
}
235239

@@ -241,7 +245,9 @@ struct Task<void> {
241245
task_.handle.resume();
242246
h.resume();
243247
}
244-
void await_resume() { task_.get(); }
248+
void await_resume() {
249+
if (task_.handle.promise().exception) std::rethrow_exception(task_.handle.promise().exception);
250+
}
245251
};
246252
// Note: Task is move-only. After co_await, the original Task handle is null.
247253
return Awaiter{std::move(*this)};

0 commit comments

Comments
 (0)