Skip to content

Boundary condition in cbuf #4002

Closed
Closed
@boblemaire

Description

@boblemaire

Basic Infos

Hardware

Hardware: NodeMCU 1 (ESP-12E)
Core Version: 2.4.0-rc2

Description

Problem description
While trying to figure out how data is being lost in webserver responses, I went through the code for cbuf. I discovered a boundary condition in the resize function. If you were to issue the function:
cbuf:resize(cbuf.available());
to reduce the size of a buffer to it's current contents, the new cbuf will be the exact size of the current contents, but cbuf logic requires that the buffer always be at least one byte larger than it's current contents.

Settings in IDE

platformio
Module: NodeMCU 1 (ESP-12E)
Flash Size: 4MM
CPU Frequency: 80Mhz
Upload Using: USB

SKETCH
Here is a sequence of calls to cbuf that illustrates the problem with a cbuf(10):

cbuf buf(10);
Serial.printf("\r\nsize=%d, available=%d, room=%d, full=%s\r\n", buf.size(), buf.available(), buf.room(), buf.full() ? "true" : "false");
for (int i=0; i<8; i++){
    Serial.printf("Write one byte, returned write count=%d, cbuf:",buf.write("X",1));
    Serial.printf("size=%d, available=%d, room=%d, full=%s\r\n", buf.size(), buf.available(), buf.room(), buf.full() ? "true" : "false");
}
Serial.printf("Resize=%d, returned size=%d, cbuf:",buf.available(),buf.resize(buf.available()));
    
Serial.printf("size=%d, available=%d, room=%d, full=%s\r\n", buf.size(), buf.available(), buf.room(), buf.full() ? "true" : "false");
for (int i=0; i<8; i++){
    Serial.printf("Write one byte, returned write count=%d, cbuf:",buf.write("X",1));
    Serial.printf("size=%d, available=%d, room=%d, full=%s\r\n", buf.size(), buf.available(), buf.room(), buf.full() ? "true" : "false");
}

Serial OUTPUT

size=10, available=0, room=9, full=false
Write one byte, returned write count=1, cbuf:size=10, available=1, room=8, full=false
Write one byte, returned write count=1, cbuf:size=10, available=2, room=7, full=false
Write one byte, returned write count=1, cbuf:size=10, available=3, room=6, full=false
Write one byte, returned write count=1, cbuf:size=10, available=4, room=5, full=false
Write one byte, returned write count=1, cbuf:size=10, available=5, room=4, full=false
Write one byte, returned write count=1, cbuf:size=10, available=6, room=3, full=false
Write one byte, returned write count=1, cbuf:size=10, available=7, room=2, full=false
Write one byte, returned write count=1, cbuf:size=10, available=8, room=1, full=false
Resize=8, returned size=8, cbuf:size=8, available=8, room=-1, full=false
Write one byte, returned write count=1, cbuf:size=8, available=1, room=6, full=false
Write one byte, returned write count=1, cbuf:size=8, available=2, room=5, full=false
Write one byte, returned write count=1, cbuf:size=8, available=3, room=4, full=false
Write one byte, returned write count=1, cbuf:size=8, available=4, room=3, full=false
Write one byte, returned write count=1, cbuf:size=8, available=5, room=2, full=false
Write one byte, returned write count=1, cbuf:size=8, available=6, room=1, full=false
Write one byte, returned write count=1, cbuf:size=8, available=7, room=0, full=true
Write one byte, returned write count=0, cbuf:size=8, available=7, room=0, full=true

As you can see, seven bytes are lost as a result of this.

The solution is to change cbuf line 40 from:
if((newSize < bytes_available) || (newSize == _size)) {
to:
if((newSize <= bytes_available) || (newSize == _size)) {

I have tried this fix and it seems to work, in that the buffer is not resized. I haven't yet tried this to see if it solves my missing data problem (I have a workaround in place), but thought someone would like to know about this possible problem in what is a widely used core class.

As an afterthought, invoking the resize as cbuf:resize(cbuf.available()+1); would avoid the problem. Of course recoding cbuf to be able to utilize all of it's size would be the best long term solution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions