Update the internal state in-place

Some of the internal state is cached in local variables at the start of
the function, and is updated only at the end of the function. But the
contents of the packet buffer is never cached. As a result, the two can
go out of sync when an error occurs and the function returns early.
Trying to restore the original state is pointless if the corresponding
data in the packet buffer is no longer available.

Fixed by removing the local variables and always updating the internal
state in-place to reflect the current state.
This commit is contained in:
Jef Driesen 2023-12-11 21:25:54 +01:00
parent e0cf41a14e
commit 00b0169578

View File

@ -125,43 +125,39 @@ dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsign
if (rbstream == NULL) if (rbstream == NULL)
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
unsigned int address = rbstream->address;
unsigned int available = rbstream->available;
unsigned int skip = rbstream->skip;
unsigned int nbytes = 0; unsigned int nbytes = 0;
unsigned int offset = size; unsigned int offset = size;
while (nbytes < size) { while (nbytes < size) {
if (available == 0) { if (rbstream->available == 0) {
// Handle the ringbuffer wrap point. // Handle the ringbuffer wrap point.
if (address == rbstream->begin) if (rbstream->address == rbstream->begin)
address = rbstream->end; rbstream->address = rbstream->end;
// Calculate the packet size. // Calculate the packet size.
unsigned int len = rbstream->packetsize; unsigned int len = rbstream->packetsize;
if (rbstream->begin + len > address) if (rbstream->begin + len > rbstream->address)
len = address - rbstream->begin; len = rbstream->address - rbstream->begin;
// Move to the begin of the current packet.
address -= len;
// Read the packet into the cache. // Read the packet into the cache.
rc = dc_device_read (rbstream->device, address, rbstream->cache, rbstream->packetsize); rc = dc_device_read (rbstream->device, rbstream->address - len, rbstream->cache, rbstream->packetsize);
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
available = len - skip; // Move to the end of the next packet.
skip = 0; rbstream->address -= len;
rbstream->available = len - rbstream->skip;
rbstream->skip = 0;
} }
unsigned int length = available; unsigned int length = rbstream->available;
if (nbytes + length > size) if (nbytes + length > size)
length = size - nbytes; length = size - nbytes;
offset -= length; offset -= length;
available -= length; rbstream->available -= length;
memcpy (data + offset, rbstream->cache + available, length); memcpy (data + offset, rbstream->cache + rbstream->available, length);
// Update and emit a progress event. // Update and emit a progress event.
if (progress) { if (progress) {
@ -172,10 +168,6 @@ dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsign
nbytes += length; nbytes += length;
} }
rbstream->address = address;
rbstream->available = available;
rbstream->skip = skip;
return rc; return rc;
} }