From 1dc9704a2479835571c8947ba781c982f6d43d30 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 22 Aug 2010 23:24:13 +0200 Subject: [PATCH] Avoid reading outside the ringbuffer area. Since the total amount of profile data is not necessary a multiple of the maximum packet size, the code may attempt to read outside the ringbuffer area in some cases. Because the device supports a variable packet size, the problem can simply be avoided by adjusting the packet size. As a side effect of this fix, the code will now also detect when the profile ringbuffer is filling up faster than the logbook ringbuffer, and the progress events are improved as well. --- src/zeagle_n2ition3.c | 62 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index 027828c..ba4201f 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -306,10 +306,6 @@ zeagle_n2ition3_device_foreach (device_t *abstract, dive_callback_t callback, vo return rc; } - // Update and emit a progress event. - progress.current += sizeof (config); - device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); - // Get the logbook pointers. unsigned int last = config[0x7C]; unsigned int first = config[0x7D]; @@ -319,17 +315,51 @@ zeagle_n2ition3_device_foreach (device_t *abstract, dive_callback_t callback, vo // Get the profile pointer. unsigned int eop = array_uint16_le (config + 0x7E); + + // The logbook ringbuffer can store at most 60 dives, even if the profile + // data could store more (e.g. many small dives). But it's also possible + // that the profile ringbuffer is filled faster than the logbook ringbuffer + // (e.g. many large dives). We detect this by checking the total length. + unsigned int total = 0; + unsigned int idx = last; + unsigned int previous = eop; + for (unsigned int i = 0; i < count; ++i) { + // Get the pointer to the profile data. + unsigned int current = array_uint16_le (config + 2 * idx); + + // Get the profile length. + unsigned int length = ringbuffer_distance (current, previous, 1, RB_PROFILE_BEGIN, RB_PROFILE_END); + + // Check for a ringbuffer overflow. + if (total + length > RB_PROFILE_END - RB_PROFILE_BEGIN) { + count = i; + break; + } + + total += length; + + previous = current; + + if (idx == RB_LOGBOOK_BEGIN) + idx = RB_LOGBOOK_END; + idx--; + } + + // Update and emit a progress event. + progress.current += sizeof (config); + progress.maximum = (RB_LOGBOOK_END - RB_LOGBOOK_BEGIN) * 2 + 8 + total; + device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Memory buffer for the profile data. unsigned char buffer[RB_PROFILE_END - RB_PROFILE_BEGIN] = {0}; unsigned int available = 0; + unsigned int remaining = total; unsigned int offset = RB_PROFILE_END - RB_PROFILE_BEGIN; - - unsigned int previous = eop; unsigned int address = previous; - unsigned int idx = last; + idx = last; + previous = eop; for (unsigned int i = 0; i < count; ++i) { // Get the pointer to the profile data. unsigned int current = array_uint16_le (config + 2 * idx); @@ -341,23 +371,31 @@ zeagle_n2ition3_device_foreach (device_t *abstract, dive_callback_t callback, vo while (nbytes < length) { if (address == RB_PROFILE_BEGIN) address = RB_PROFILE_END; - address -= ZEAGLE_N2ITION3_PACKET_SIZE; - offset -= ZEAGLE_N2ITION3_PACKET_SIZE; + + unsigned int len = ZEAGLE_N2ITION3_PACKET_SIZE; + if (RB_PROFILE_BEGIN + len > address) + len = address - RB_PROFILE_BEGIN; // End of ringbuffer. + if (nbytes + len > remaining) + len = remaining - nbytes; // End of profile. + + address -= len; + offset -= len; // Read the memory page. - rc = zeagle_n2ition3_device_read (abstract, address, buffer + offset, ZEAGLE_N2ITION3_PACKET_SIZE); + rc = zeagle_n2ition3_device_read (abstract, address, buffer + offset, len); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Failed to read the memory page."); return rc; } // Update and emit a progress event. - progress.current += ZEAGLE_N2ITION3_PACKET_SIZE; + progress.current += len; device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); - nbytes += ZEAGLE_N2ITION3_PACKET_SIZE; + nbytes += len; } + remaining -= length; available = nbytes - length; previous = current;