Merge pull request #32955 from azat/read-fix

Fix UB in case of unexpected EOF during filling a set from HTTP query
This commit is contained in:
Vitaly Baranov 2021-12-23 06:41:14 +03:00 committed by GitHub
commit 7660530fcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 5 deletions

View File

@ -29,7 +29,8 @@ bool LimitReadBuffer::nextImpl()
if (!in->next())
{
working_buffer = in->buffer();
/// Clearing the buffer with existing data.
set(in->position(), 0);
return false;
}

View File

@ -183,8 +183,8 @@ void HTMLForm::readMultipart(ReadBuffer & in_, PartHandler & handler)
size_t fields = 0;
MultipartReadBuffer in(in_, boundary);
/// Assume there is at least one part
in.skipToNextBoundary();
if (!in.skipToNextBoundary())
throw Poco::Net::HTMLFormException("No boundary line found");
/// Read each part until next boundary (or last boundary)
while (!in.eof())
@ -241,7 +241,9 @@ HTMLForm::MultipartReadBuffer::MultipartReadBuffer(ReadBuffer & in_, const std::
bool HTMLForm::MultipartReadBuffer::skipToNextBoundary()
{
assert(working_buffer.empty() || eof());
if (in.eof())
return false;
assert(boundary_hit);
boundary_hit = false;
@ -257,7 +259,7 @@ bool HTMLForm::MultipartReadBuffer::skipToNextBoundary()
}
}
throw Poco::Net::HTMLFormException("No boundary line found");
return false;
}
std::string HTMLForm::MultipartReadBuffer::readLine(bool append_crlf)

View File

@ -0,0 +1,2 @@
124
124

View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
tmp_file=$(mktemp "$CURDIR/clickhouse.XXXXXX.csv")
trap 'rm $tmp_file' EXIT
# NOTE: this file should be huge enough, so that it is impossible to upload it
# in 0.15s, see timeout command below, this will ensure, that EOF will be
# received during creating a set from externally uploaded table.
#
# Previously code there wasn't ready for EOF, and you will get one of the
# following assertions:
#
# - ./src/IO/ReadBuffer.h:58: bool DB::ReadBuffer::next(): Assertion `!hasPendingData()' failed.
# - ./src/Server/HTTP/HTMLForm.cpp:245: bool DB::HTMLForm::MultipartReadBuffer::skipToNextBoundary(): Assertion `boundary_hit' failed.
# - ./src/IO/LimitReadBuffer.cpp:17: virtual bool DB::LimitReadBuffer::nextImpl(): Assertion `position() >= in->position()' failed.
#
$CLICKHOUSE_CLIENT -q "SELECT toString(number) FROM numbers(10e6) FORMAT TSV" > "$tmp_file"
# NOTE: Just in case check w/ input_format_parallel_parsing and w/o
timeout 0.15s ${CLICKHOUSE_CURL} -sS -F "s=@$tmp_file;" "${CLICKHOUSE_URL}&s_structure=key+Int&query=SELECT+dummy+IN+s&input_format_parallel_parsing=true" -o /dev/null
echo $?
timeout 0.15s ${CLICKHOUSE_CURL} -sS -F "s=@$tmp_file;" "${CLICKHOUSE_URL}&s_structure=key+Int&query=SELECT+dummy+IN+s&input_format_parallel_parsing=false" -o /dev/null
echo $?