Skip to content

Commit b220bfd

Browse files
committed
correction deadlock
1 parent 405763d commit b220bfd

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

src/AsyncHttpClient.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ AsyncHttpClient::AsyncHttpClient()
3535
// Optional: spawn a lightweight auto-loop task so users don't need to call client.loop() manually.
3636
xTaskCreatePinnedToCore(_autoLoopTaskThunk, // task entry
3737
"AsyncHttpAutoLoop", // name
38-
2048, // stack words
38+
4096, // stack words
3939
this, // parameter
4040
1, // priority (low)
4141
&_autoLoopTaskHandle, // handle out
@@ -1038,7 +1038,10 @@ void AsyncHttpClient::cleanup(RequestContext* context) {
10381038
toDelete->close();
10391039
delete toDelete;
10401040
}
1041-
tryDequeue();
1041+
// Guard against recursion: cleanup → tryDequeue → executeRequest → triggerError → cleanup → tryDequeue
1042+
// The outer tryDequeue's while-loop will handle remaining pending requests.
1043+
if (!_inTryDequeue)
1044+
tryDequeue();
10421045
}
10431046

10441047
void AsyncHttpClient::triggerError(RequestContext* context, HttpClientError errorCode, const char* errorMessage) {
@@ -1064,13 +1067,15 @@ void AsyncHttpClient::loop() {
10641067
unlock();
10651068
triggerError(ctx, REQUEST_TIMEOUT, "Request timeout");
10661069
lock();
1070+
continue; // ctx may be freed; re-read at current index
10671071
}
10681072
#endif
10691073
if (!ctx->cancelled.load() && !ctx->responseProcessed && ctx->transport && !ctx->headersSent &&
10701074
ctx->timing.connectTimeoutMs > 0 && (now - ctx->timing.connectStartMs) > ctx->timing.connectTimeoutMs) {
10711075
unlock();
10721076
triggerError(ctx, CONNECT_TIMEOUT, "Connect timeout");
10731077
lock();
1078+
continue; // ctx may be freed; re-read at current index
10741079
}
10751080
if (!ctx->cancelled.load() && !ctx->responseProcessed && ctx->transport && ctx->transport->isHandshaking()) {
10761081
uint32_t hsTimeout = ctx->transport->getHandshakeTimeoutMs();
@@ -1079,6 +1084,7 @@ void AsyncHttpClient::loop() {
10791084
unlock();
10801085
triggerError(ctx, TLS_HANDSHAKE_TIMEOUT, "TLS handshake timeout");
10811086
lock();
1087+
continue; // ctx may be freed; re-read at current index
10821088
}
10831089
}
10841090
if (!ctx->cancelled.load() && !ctx->responseProcessed && ctx->streamingBodyInProgress &&
@@ -1097,6 +1103,9 @@ void AsyncHttpClient::loop() {
10971103
}
10981104

10991105
void AsyncHttpClient::tryDequeue() {
1106+
if (_inTryDequeue)
1107+
return; // prevent recursion via executeRequest → triggerError → cleanup → tryDequeue
1108+
_inTryDequeue = true;
11001109
while (true) {
11011110
lock();
11021111
bool canStart = (_maxParallel == 0 || _activeRequests.size() < _maxParallel);
@@ -1110,6 +1119,7 @@ void AsyncHttpClient::tryDequeue() {
11101119
unlock();
11111120
executeRequest(ctx);
11121121
}
1122+
_inTryDequeue = false;
11131123
}
11141124

11151125
void AsyncHttpClient::sendStreamData(RequestContext* context) {

src/AsyncHttpClient.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ class AsyncHttpClient {
200200
AsyncHttpTLSConfig _defaultTlsConfig;
201201
bool _keepAliveEnabled = false;
202202
uint32_t _keepAliveIdleMs = 5000;
203+
bool _inTryDequeue = false; // reentrancy guard to prevent cleanup → tryDequeue recursion
203204
std::unique_ptr<AsyncCookieJar> _cookieJar;
204205
std::unique_ptr<ConnectionPool> _connectionPool;
205206
std::unique_ptr<RedirectHandler> _redirectHandler;

0 commit comments

Comments
 (0)