Skip to content

Commit befa1bb

Browse files
author
Harald Frostel
committed
Fix random crashing of ClientContext::write(Stream) and write_P(PGM_P buf, size_t size) (esp8266#2504)
1 parent 06352ab commit befa1bb

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

libraries/ESP8266WiFi/src/include/DataSource.h

+29-9
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ class BufferDataSource : public DataSource {
3131

3232
const uint8_t* get_buffer(size_t size) override
3333
{
34-
(void) size;
34+
(void)size;
3535
assert(_pos + size <= _size);
3636
return _data + _pos;
3737
}
3838

3939
void release_buffer(const uint8_t* buffer, size_t size) override
4040
{
41-
(void) buffer;
41+
(void)buffer;
4242
assert(buffer == _data + _pos);
4343
_pos += size;
4444
}
@@ -66,28 +66,48 @@ class BufferedStreamDataSource : public DataSource {
6666
const uint8_t* get_buffer(size_t size) override
6767
{
6868
assert(_pos + size <= _size);
69+
70+
//Data that was already read from the stream but not released (e.g. if error occured). Otherwise this should be 0.
71+
const size_t stream_read = _streamPos - _pos;
72+
6973
if (_bufferSize < size) {
70-
_buffer.reset(new uint8_t[size]);
74+
uint8_t *new_buffer = new uint8_t[size];
75+
//If stream reading is ahead, than some data is already in the old buffer and needs to be copied to new resized buffer
76+
if (_buffer && stream_read > 0) {
77+
memcpy(new_buffer, _buffer.get(), stream_read);
78+
}
79+
_buffer.reset(new_buffer);
7180
_bufferSize = size;
7281
}
73-
size_t cb = _stream.readBytes(reinterpret_cast<char*>(_buffer.get()), size);
74-
assert(cb == size);
75-
(void) cb;
82+
83+
//If error in tcp_write in ClientContext::_write_some() occured earlier and therefore release_buffer was not called, than there might not even be data needed to be read from the stream
84+
if (size > stream_read) {
85+
//Remaining bytes to read from stream
86+
const size_t stream_rem = size - stream_read;
87+
const size_t cb = _stream.readBytes(reinterpret_cast<char*>(_buffer.get() + stream_read), stream_rem);
88+
assert(cb == stream_rem);
89+
(void)cb;
90+
_streamPos += stream_rem;
91+
}
7692
return _buffer.get();
93+
7794
}
7895

7996
void release_buffer(const uint8_t* buffer, size_t size) override
8097
{
81-
(void) buffer;
98+
(void)buffer;
8299
_pos += size;
100+
//Release size needs to be the same as get_buffer(size)
101+
assert(_pos == _streamPos);
83102
}
84103

85104
protected:
86-
TStream& _stream;
105+
TStream & _stream;
87106
std::unique_ptr<uint8_t[]> _buffer;
88107
size_t _size;
89108
size_t _pos = 0;
90109
size_t _bufferSize = 0;
110+
size_t _streamPos = 0;
91111
};
92112

93113
class ProgmemStream
@@ -104,7 +124,7 @@ class ProgmemStream
104124
size_t will_read = (_left < size) ? _left : size;
105125
memcpy_P((void*)dst, (PGM_VOID_P)_buf, will_read);
106126
_left -= will_read;
107-
_buf += will_read;
127+
_buf += will_read;
108128
return will_read;
109129
}
110130

0 commit comments

Comments
 (0)