mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-21 21:22:31 +03:00
Fix random crashing of ClientContext::write(Stream) and write_P(PGM_P buf, size_t size) (#2504) (#4530)
* Fix random crashing of ClientContext::write(Stream) and write_P(PGM_P buf, size_t size) (#2504) * - Allow partial buffer release * - Refined comments
This commit is contained in:
@ -31,14 +31,14 @@ public:
|
|||||||
|
|
||||||
const uint8_t* get_buffer(size_t size) override
|
const uint8_t* get_buffer(size_t size) override
|
||||||
{
|
{
|
||||||
(void) size;
|
(void)size;
|
||||||
assert(_pos + size <= _size);
|
assert(_pos + size <= _size);
|
||||||
return _data + _pos;
|
return _data + _pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release_buffer(const uint8_t* buffer, size_t size) override
|
void release_buffer(const uint8_t* buffer, size_t size) override
|
||||||
{
|
{
|
||||||
(void) buffer;
|
(void)buffer;
|
||||||
assert(buffer == _data + _pos);
|
assert(buffer == _data + _pos);
|
||||||
_pos += size;
|
_pos += size;
|
||||||
}
|
}
|
||||||
@ -66,28 +66,65 @@ public:
|
|||||||
const uint8_t* get_buffer(size_t size) override
|
const uint8_t* get_buffer(size_t size) override
|
||||||
{
|
{
|
||||||
assert(_pos + size <= _size);
|
assert(_pos + size <= _size);
|
||||||
if (_bufferSize < size) {
|
|
||||||
_buffer.reset(new uint8_t[size]);
|
//Data that was already read from the stream but not released (e.g. if tcp_write error occured). Otherwise this should be 0.
|
||||||
_bufferSize = size;
|
const size_t stream_read = _streamPos - _pos;
|
||||||
|
|
||||||
|
//Min required buffer size: max(requested size, previous stream data already in buffer)
|
||||||
|
const size_t min_buffer_size = size > stream_read ? size : stream_read;
|
||||||
|
|
||||||
|
//Buffer too small?
|
||||||
|
if (_bufferSize < min_buffer_size) {
|
||||||
|
uint8_t *new_buffer = new uint8_t[min_buffer_size];
|
||||||
|
//If stream reading is ahead, than some data is already in the old buffer and needs to be copied to new resized buffer
|
||||||
|
if (_buffer && stream_read > 0) {
|
||||||
|
memcpy(new_buffer, _buffer.get(), stream_read);
|
||||||
|
}
|
||||||
|
_buffer.reset(new_buffer);
|
||||||
|
_bufferSize = min_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fetch remaining data from stream
|
||||||
|
//If error in tcp_write in ClientContext::_write_some() occured earlier and therefore release_buffer was not called last time, than the requested stream data is already in the buffer.
|
||||||
|
if (size > stream_read) {
|
||||||
|
//Remaining bytes to read from stream
|
||||||
|
const size_t stream_rem = size - stream_read;
|
||||||
|
const size_t cb = _stream.readBytes(reinterpret_cast<char*>(_buffer.get() + stream_read), stream_rem);
|
||||||
|
assert(cb == stream_rem);
|
||||||
|
(void)cb;
|
||||||
|
_streamPos += stream_rem;
|
||||||
}
|
}
|
||||||
size_t cb = _stream.readBytes(reinterpret_cast<char*>(_buffer.get()), size);
|
|
||||||
assert(cb == size);
|
|
||||||
(void) cb;
|
|
||||||
return _buffer.get();
|
return _buffer.get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void release_buffer(const uint8_t* buffer, size_t size) override
|
void release_buffer(const uint8_t* buffer, size_t size) override
|
||||||
{
|
{
|
||||||
(void) buffer;
|
if (size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)buffer;
|
||||||
_pos += size;
|
_pos += size;
|
||||||
|
|
||||||
|
//Cannot release more than acquired through get_buffer
|
||||||
|
assert(_pos <= _streamPos);
|
||||||
|
|
||||||
|
//Release less than requested with get_buffer?
|
||||||
|
if (_pos < _streamPos) {
|
||||||
|
// Move unreleased stream data in buffer to front
|
||||||
|
assert(_buffer);
|
||||||
|
memmove(_buffer.get(), _buffer.get() + size, _streamPos - _pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TStream& _stream;
|
TStream & _stream;
|
||||||
std::unique_ptr<uint8_t[]> _buffer;
|
std::unique_ptr<uint8_t[]> _buffer;
|
||||||
size_t _size;
|
size_t _size;
|
||||||
size_t _pos = 0;
|
size_t _pos = 0;
|
||||||
size_t _bufferSize = 0;
|
size_t _bufferSize = 0;
|
||||||
|
size_t _streamPos = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProgmemStream
|
class ProgmemStream
|
||||||
|
Reference in New Issue
Block a user