1
0
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:
Harald
2018-03-22 04:01:22 +01:00
committed by Develo
parent 479f1b3fed
commit 3267443348

View File

@ -66,20 +66,56 @@ 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);
} }
size_t cb = _stream.readBytes(reinterpret_cast<char*>(_buffer.get()), size); _buffer.reset(new_buffer);
assert(cb == size); _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; (void)cb;
_streamPos += stream_rem;
}
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
{ {
if (size == 0) {
return;
}
(void)buffer; (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:
@ -88,6 +124,7 @@ protected:
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