Skip to content

Commit

Permalink
Potential crash under NetworkDataTaskBlob::dispatchDidReceiveResponse()
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=258951
rdar://111798349

Reviewed by Youenn Fablet.

In getSizeForNext(), we call seek() and then dispatchDidReceiveResponse().
After 261968@main, seek() could call fail internally and call didFail().
However, we could still call dispatchDidReceiveResponse() right after in
case of failure.

We now propagate the error state out of seek() and have the caller call
didFail() and then early return instead of calling dispatchDidReceiveResponse().

* Source/WebKit/NetworkProcess/NetworkDataTaskBlob.cpp:
(WebKit::NetworkDataTaskBlob::getSizeForNext):
(WebKit::NetworkDataTaskBlob::seek):
* Source/WebKit/NetworkProcess/NetworkDataTaskBlob.h:

Canonical link: https://commits.webkit.org/265848@main
  • Loading branch information
cdumez committed Jul 7, 2023
1 parent a9bf099 commit d7832a4
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 19 deletions.
22 changes: 12 additions & 10 deletions Source/WebCore/platform/network/BlobResourceHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ void BlobResourceHandle::start()
void BlobResourceHandle::doStart()
{
ASSERT(isMainThread());
Ref protectedThis { *this };

// Do not continue if the request is aborted or an error occurs.
if (erroredOrAborted())
Expand Down Expand Up @@ -227,13 +228,14 @@ void BlobResourceHandle::getSizeForNext()

// Do we finish validating and counting size for all items?
if (m_sizeItemCount >= m_blobData->items().size()) {
seek();
if (auto error = seek()) {
notifyFail(*error);
return;
}

// Start reading if in asynchronous mode.
if (m_async) {
Ref<BlobResourceHandle> protectedThis(*this);
if (m_async)
notifyResponse();
}
return;
}

Expand All @@ -257,6 +259,7 @@ void BlobResourceHandle::getSizeForNext()
void BlobResourceHandle::didGetSize(long long size)
{
ASSERT(isMainThread());
Ref protectedThis { *this };

// Do not continue if the request is aborted or an error occurs.
if (erroredOrAborted())
Expand Down Expand Up @@ -284,23 +287,21 @@ void BlobResourceHandle::didGetSize(long long size)
getSizeForNext();
}

void BlobResourceHandle::seek()
auto BlobResourceHandle::seek() -> std::optional<Error>
{
ASSERT(isMainThread());

// Bail out if the range is not provided.
if (!m_isRangeRequest)
return;
return std::nullopt;

// Adjust m_rangeStart / m_rangeEnd
if (m_rangeStart == kPositionNotSpecified) {
m_rangeStart = m_totalSize - m_rangeEnd;
m_rangeEnd = m_rangeStart + m_rangeEnd - 1;
} else {
if (m_rangeStart >= m_totalSize) {
notifyFail(Error::RangeError);
return;
}
if (m_rangeStart >= m_totalSize)
return Error::RangeError;
if (m_rangeEnd == kPositionNotSpecified || m_rangeEnd >= m_totalSize)
m_rangeEnd = m_totalSize - 1;
}
Expand All @@ -317,6 +318,7 @@ void BlobResourceHandle::seek()
long long rangeSize = m_rangeEnd - m_rangeStart + 1;
if (m_totalRemainingSize > rangeSize)
m_totalRemainingSize = rangeSize;
return std::nullopt;
}

int BlobResourceHandle::readSync(uint8_t* buf, int length)
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/platform/network/BlobResourceHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class BlobResourceHandle final : public FileStreamClient, public ResourceHandle

void doStart();
void getSizeForNext();
void seek();
std::optional<Error> seek();
void consumeData(const uint8_t* data, int bytesRead);
void failed(Error);

Expand Down
17 changes: 10 additions & 7 deletions Source/WebKit/NetworkProcess/NetworkDataTaskBlob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,10 @@ void NetworkDataTaskBlob::getSizeForNext()

// Do we finish validating and counting size for all items?
if (m_sizeItemCount >= m_blobData->items().size()) {
seek();
if (auto error = seek()) {
didFail(*error);
return;
}
dispatchDidReceiveResponse();
return;
}
Expand All @@ -186,6 +189,7 @@ void NetworkDataTaskBlob::getSizeForNext()
void NetworkDataTaskBlob::didGetSize(long long size)
{
ASSERT(RunLoop::isMain());
Ref protectedThis { *this };

if (m_state == State::Canceling || m_state == State::Completed || (!m_client && !isDownload())) {
clearStream();
Expand Down Expand Up @@ -214,23 +218,21 @@ void NetworkDataTaskBlob::didGetSize(long long size)
getSizeForNext();
}

void NetworkDataTaskBlob::seek()
auto NetworkDataTaskBlob::seek() -> std::optional<Error>
{
ASSERT(RunLoop::isMain());

// Bail out if the range is not provided.
if (!m_isRangeRequest)
return;
return std::nullopt;

// Adjust m_rangeStart / m_rangeEnd
if (m_rangeStart == kPositionNotSpecified) {
m_rangeStart = m_totalSize - m_rangeEnd;
m_rangeEnd = m_rangeStart + m_rangeEnd - 1;
} else {
if (m_rangeStart >= m_totalSize) {
didFail(Error::RangeError);
return;
}
if (m_rangeStart >= m_totalSize)
return Error::RangeError;
if (m_rangeEnd == kPositionNotSpecified || m_rangeEnd >= m_totalSize)
m_rangeEnd = m_totalSize - 1;
}
Expand All @@ -247,6 +249,7 @@ void NetworkDataTaskBlob::seek()
long long rangeSize = m_rangeEnd - m_rangeStart + 1;
if (m_totalRemainingSize > rangeSize)
m_totalRemainingSize = rangeSize;
return std::nullopt;
}

void NetworkDataTaskBlob::dispatchDidReceiveResponse()
Expand Down
2 changes: 1 addition & 1 deletion Source/WebKit/NetworkProcess/NetworkDataTaskBlob.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class NetworkDataTaskBlob final : public NetworkDataTask, public WebCore::FileSt
void clearStream();
void getSizeForNext();
void dispatchDidReceiveResponse();
void seek();
std::optional<Error> seek();
void consumeData(const uint8_t* data, int bytesRead);
void read();
void readData(const WebCore::BlobDataItem&);
Expand Down

0 comments on commit d7832a4

Please sign in to comment.