Skip to content

Commit

Permalink
Bugfix: make sure not to lose teminating 0 byte in StreamBuffer::repl…
Browse files Browse the repository at this point in the history
…ace()
  • Loading branch information
dirk-zimoch committed Mar 19, 2024
1 parent a090cd4 commit 1496089
Showing 1 changed file with 50 additions and 18 deletions.
68 changes: 50 additions & 18 deletions src/StreamBuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ init(const void* s, ssize_t minsize)
}

// How the buffer looks like:
// |----free-----|####used####|--------00--------|
// |----junk-----|####used####|--------00--------|
///|<--- offs -->|<-- len --->|<- cap-offs-len ->|
// 0 offs offs+len cap
// |<-------------- minsize --------------->
Expand Down Expand Up @@ -254,39 +254,71 @@ replace(ssize_t remstart, ssize_t remlen, const void* ins, ssize_t inslen)
if (inslen < 0) inslen = 0;
size_t remend = remstart+remlen;
size_t newlen = len+inslen-remlen;

// How the buffer looks like before and after:
// |---junk---|##content_start##|/////////remove_this////////|##content_end##|0000|
// |<- offs ->|<-- remstart --->|<--------- remlen --------->| | |
// | |<--------------------- len ---------------------------------->| |
// 0 offs offs+remstart offs+remend offs+len cap
//
// If content size stays the same, no need to move old content:
// |---junk---|##content_start##|+++++++inserted_text++++++++|##content_end##|0000|
// |<----- inslen==remlen ----->| newlen==len
//
// If content shrinks (need to clear end of buffer): |< clear this >|
// |---junk---|##content_start##|inserted_text|##content_end##|00000000000000|0000|
// 0 offs |<- inslen -->| |< len-newlen >|
// offs+newlen offs+len
//
// If content grows but still fits (make sure to keep at least one 0 byte at end):
// |---junk---|##content_start##|++++++++inserted_text++++++++++|##content_end##|0|
// |<- offs ->|<--------------------- newlen ---------------------------------->| |
// 0 offs offs+newlen<cap
//
// If content would overflow, moving to offs 0 may help:
// May need to clear end if newlen < offs+len: |<clear>|
// |##content_start##|++++++++inserted_text++++++++++|##content_end##|0000000|0000|
// |<--------------------- newlen ---------------------------------->| |
// newlen offs+len
//
// Otherwise we need to copy to a new buffer.


if (cap <= newlen)
{
// buffer too short
// buffer too short, copy to new buffer
size_t newcap;
for (newcap = sizeof(local)*2; newcap <= newlen; newcap *= 2);
char* newbuffer = new char[newcap];
memcpy(newbuffer, buffer+offs, remstart);
memcpy(newbuffer+remstart, ins, inslen);
memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend);
memset(newbuffer+newlen, 0, newcap-newlen);
memcpy(newbuffer, buffer+offs, remstart); // copy content start
memcpy(newbuffer+remstart, ins, inslen); // insert
memcpy(newbuffer+remstart+inslen, buffer+offs+remend, len-remend); // copy content end
memset(newbuffer+newlen, 0, newcap-newlen); // clear buffer end
if (buffer != local)
{
delete [] buffer;
}
delete[] buffer;
buffer = newbuffer;
cap = newcap;
offs = 0;
}
else
{
if (newlen+offs<=cap)
if (offs+newlen < cap)
{
// move to start of buffer
memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend);
memcpy(buffer+offs+remstart, ins, inslen);
if (newlen<len) memset(buffer+offs+newlen, 0, len-newlen);
// modified content still fits with current offs, just move content end
if (newlen != len)
memmove(buffer+offs+remstart+inslen, buffer+offs+remend, len-remend); // move old content end if necessary
memcpy(buffer+offs+remstart, ins, inslen); // insert before
if (newlen < len)
memset(buffer+offs+newlen, 0, len-newlen); // clear buffer end if content shrunk
}
else
{
memmove(buffer,buffer+offs,remstart);
memmove(buffer+remstart+inslen, buffer+offs+remend, len-remend);
memcpy(buffer+remstart, ins, inslen);
if (newlen<len) memset(buffer+newlen, 0, len-newlen);
// move content to start of buffer
memmove(buffer, buffer+offs, remstart); // move content start to 0 offs
memmove(buffer+remstart+inslen, buffer+offs+remend, len-remend); // move content end
memcpy(buffer+remstart, ins, inslen); // insert in between
if (newlen < offs+len)
memset(buffer+newlen, 0, offs+len-newlen); // clear buffer end if necessary
offs = 0;
}
}
Expand Down

0 comments on commit 1496089

Please sign in to comment.