diff --git a/epan/tvbuff.c b/epan/tvbuff.c index 98968a0..db2cfd1 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -53,7 +53,7 @@ static const guint8* ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint length, - int *exception); + int *pexception); static const guint8* ensure_contiguous(tvbuff_t *tvb, const gint offset, const gint length); @@ -241,45 +241,48 @@ tvb_new_child_real_data(tvbuff_t *parent, const guint8* data, const guint length return tvb; } -/* Computes the absolute offset and length based on a possibly-negative offset - * and a length that is possible -1 (which means "to the end of the data"). - * Returns TRUE/FALSE indicating whether the offset is in bounds or - * not. The integer ptrs are modified with the new offset and length. - * No exception is thrown. +/* + * Check whether that offset goes more than one byte past the + * end of the buffer. * - * XXX - we return TRUE, not FALSE, if the offset is positive and right - * after the end of the tvbuff (i.e., equal to the length). We do this - * so that a dissector constructing a subset tvbuff for the next protocol - * will get a zero-length tvbuff, not an exception, if there's no data - * left for the next protocol - we want the next protocol to be the one - * that gets an exception, so the error is reported as an error in that - * protocol rather than the containing protocol. */ -static gboolean -compute_offset_length(const tvbuff_t *tvb, - const gint offset, const gint length_val, - guint *offset_ptr, guint *length_ptr, int *exception) + * If not, return 0; otherwise, return exception + */ +static inline int +validate_offset(const tvbuff_t *tvb, const guint abs_offset) { - DISSECTOR_ASSERT(offset_ptr); - DISSECTOR_ASSERT(length_ptr); + int exception; + + if (G_LIKELY(abs_offset <= tvb->length)) + exception = 0; + else if (abs_offset <= tvb->reported_length) + exception = BoundsError; + else { + if (tvb->flags & TVBUFF_FRAGMENT) + exception = FragmentBoundsError; + else + exception = ReportedBoundsError; + } + + return exception; +} + +static int +compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr) +{ + int exception; - /* Compute the offset */ if (offset >= 0) { /* Positive offset - relative to the beginning of the packet. */ if ((guint) offset > tvb->reported_length) { - if (exception) { - if (tvb->flags & TVBUFF_FRAGMENT) { - *exception = FragmentBoundsError; - } else { - *exception = ReportedBoundsError; - } + if (tvb->flags & TVBUFF_FRAGMENT) { + exception = FragmentBoundsError; + } else { + exception = ReportedBoundsError; } - return FALSE; + return exception; } else if ((guint) offset > tvb->length) { - if (exception) { - *exception = BoundsError; - } - return FALSE; + return BoundsError; } else { *offset_ptr = offset; @@ -288,95 +291,90 @@ compute_offset_length(const tvbuff_t *tvb, else { /* Negative offset - relative to the end of the packet. */ if ((guint) -offset > tvb->reported_length) { - if (exception) { - if (tvb->flags & TVBUFF_FRAGMENT) { - *exception = FragmentBoundsError; - } else { - *exception = ReportedBoundsError; - } + if (tvb->flags & TVBUFF_FRAGMENT) { + exception = FragmentBoundsError; + } else { + exception = ReportedBoundsError; } - return FALSE; + return exception; } else if ((guint) -offset > tvb->length) { - if (exception) { - *exception = BoundsError; - } - return FALSE; + return BoundsError; } else { *offset_ptr = tvb->length + offset; } } - /* Compute the length */ - if (length_val < -1) { - if (exception) { - /* XXX - ReportedBoundsError? */ - *exception = BoundsError; - } - return FALSE; - } - else if (length_val == -1) { - *length_ptr = tvb->length - *offset_ptr; - } - else { - *length_ptr = length_val; - } + return 0; +} - return TRUE; +static int +compute_offset_and_remaining(const tvbuff_t *tvb, const gint offset, guint *offset_ptr, guint *rem_len) +{ + int exception; + + exception = compute_offset(tvb, offset, offset_ptr); + if (!exception) + *rem_len = tvb->length - *offset_ptr; + + return exception; } -static gboolean +/* Computes the absolute offset and length based on a possibly-negative offset + * and a length that is possible -1 (which means "to the end of the data"). + * Returns integer indicating whether the offset is in bounds (0) or + * not (exception number). The integer ptrs are modified with the new offset and length. + * No exception is thrown. + * + * XXX - we return success (0), if the offset is positive and right + * after the end of the tvbuff (i.e., equal to the length). We do this + * so that a dissector constructing a subset tvbuff for the next protocol + * will get a zero-length tvbuff, not an exception, if there's no data + * left for the next protocol - we want the next protocol to be the one + * that gets an exception, so the error is reported as an error in that + * protocol rather than the containing protocol. */ +static int check_offset_length_no_exception(const tvbuff_t *tvb, const gint offset, gint const length_val, - guint *offset_ptr, guint *length_ptr, int *exception) + guint *offset_ptr, guint *length_ptr) { - guint end_offset; + guint end_offset; + int exception; - if (!compute_offset_length(tvb, - offset, length_val, offset_ptr, length_ptr, exception)) { - return FALSE; + DISSECTOR_ASSERT(offset_ptr); + DISSECTOR_ASSERT(length_ptr); + + /* Compute the offset */ + exception = compute_offset(tvb, offset, offset_ptr); + if (exception) + return exception; + + if (length_val < -1) { + /* XXX - ReportedBoundsError? */ + return BoundsError; } + /* Compute the length */ + if (length_val == -1) + *length_ptr = tvb->length - *offset_ptr; + else + *length_ptr = length_val; + /* * Compute the offset of the first byte past the length. */ end_offset = *offset_ptr + *length_ptr; /* - * Check for an overflow, and clamp "end_offset" at the maximum - * if we got an overflow - that should force us to indicate that - * we're past the end of the tvbuff. + * Check for an overflow */ if (end_offset < *offset_ptr) - end_offset = UINT_MAX; - - /* - * Check whether that offset goes more than one byte past the - * end of the buffer. - * - * If not, return TRUE; otherwise, return FALSE and, if "exception" - * is non-null, return the appropriate exception through it. - */ - if (end_offset <= tvb->length) { - return TRUE; - } - else { - if (exception) { - if (end_offset <= tvb->reported_length) { - *exception = BoundsError; - } - else { - if (tvb->flags & TVBUFF_FRAGMENT) { - *exception = FragmentBoundsError; - } else { - *exception = ReportedBoundsError; - } - } - } + exception = BoundsError; + else + exception = validate_offset(tvb, end_offset); - return FALSE; - } + return exception; } /* Checks (+/-) offset and length and throws an exception if @@ -387,13 +385,11 @@ check_offset_length(const tvbuff_t *tvb, const gint offset, gint const length_val, guint *offset_ptr, guint *length_ptr) { - int exception = 0; - - if (!check_offset_length_no_exception(tvb, - offset, length_val, offset_ptr, length_ptr, &exception)) { - DISSECTOR_ASSERT(exception > 0); + int exception; + + exception = check_offset_length_no_exception(tvb, offset, length_val, offset_ptr, length_ptr); + if (exception) THROW(exception); - } } static tvbuff_t * @@ -538,7 +534,7 @@ tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits) right = 8 - left; /* for right-shifting */ if (no_of_bits == -1) { - datalen = tvb_length_remaining(tvb, byte_offset); + datalen = tvb_captured_length_remaining(tvb, byte_offset); remaining_bits = 0; } else { datalen = no_of_bits >> 3; @@ -560,7 +556,7 @@ tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits) * if non extra byte is available, the last shifted byte requires * special treatment */ - if (tvb_length_remaining(tvb, byte_offset) > datalen) { + if (tvb_captured_length_remaining(tvb, byte_offset) > datalen) { data = tvb_get_ptr(tvb, byte_offset, datalen + 1); /* Do this allocation AFTER tvb_get_ptr() (which could throw an exception) */ @@ -679,7 +675,7 @@ tvb_composite_finalize(tvbuff_t *tvb) guint -tvb_length(const tvbuff_t *tvb) +tvb_captured_length(const tvbuff_t *tvb) { DISSECTOR_ASSERT(tvb && tvb->initialized); @@ -687,32 +683,33 @@ tvb_length(const tvbuff_t *tvb) } gint -tvb_length_remaining(const tvbuff_t *tvb, const gint offset) +tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset) { - guint abs_offset, abs_length; + guint abs_offset, rem_length; + int exception; DISSECTOR_ASSERT(tvb && tvb->initialized); - if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) { - return abs_length; - } - else { - return -1; - } + exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length); + if (exception) + return 0; + + return rem_length; } guint -tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset) +tvb_ensure_captured_length_remaining(const tvbuff_t *tvb, const gint offset) { - guint abs_offset, abs_length; + guint abs_offset, rem_length; int exception; DISSECTOR_ASSERT(tvb && tvb->initialized); - if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, &exception)) { + exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length); + if (exception) THROW(exception); - } - if (abs_length == 0) { + + if (rem_length == 0) { /* * This routine ensures there's at least one byte available. * There aren't any bytes available, so throw the appropriate @@ -727,7 +724,7 @@ tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset) } else THROW(BoundsError); } - return abs_length; + return rem_length; } @@ -739,18 +736,15 @@ gboolean tvb_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length) { guint abs_offset, abs_length; + int exception; DISSECTOR_ASSERT(tvb && tvb->initialized); - if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL)) + exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length); + if (exception) return FALSE; - if (abs_offset + abs_length <= tvb->length) { - return TRUE; - } - else { - return FALSE; - } + return TRUE; } /* Validates that 'length' bytes are available starting from @@ -781,10 +775,13 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length gboolean tvb_offset_exists(const tvbuff_t *tvb, const gint offset) { - guint abs_offset, abs_length; + guint abs_offset; + int exception; DISSECTOR_ASSERT(tvb && tvb->initialized); - if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) + + exception = compute_offset(tvb, offset, &abs_offset); + if (exception) return FALSE; if (abs_offset < tvb->length) { @@ -806,19 +803,19 @@ tvb_reported_length(const tvbuff_t *tvb) gint tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset) { - guint abs_offset, abs_length; + guint abs_offset; + int exception; DISSECTOR_ASSERT(tvb && tvb->initialized); - if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) { - if (tvb->reported_length >= abs_offset) - return tvb->reported_length - abs_offset; - else - return -1; - } - else { - return -1; - } + exception = compute_offset(tvb, offset, &abs_offset); + if (exception) + return 0; + + if (tvb->reported_length >= abs_offset) + return tvb->reported_length - abs_offset; + else + return 0; } /* Set the reported length of a tvbuff to a given value; used for protocols @@ -896,6 +893,7 @@ composite_ensure_contiguous_no_exception(tvbuff_t *tvb, const guint abs_offset, tvbuff_t *member_tvb = NULL; guint member_offset, member_length; GSList *slist; + int exception; DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE); @@ -913,10 +911,11 @@ composite_ensure_contiguous_no_exception(tvbuff_t *tvb, const guint abs_offset, } DISSECTOR_ASSERT(member_tvb); - if (check_offset_length_no_exception(member_tvb, + exception = check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i], - abs_length, &member_offset, &member_length, NULL)) { + abs_length, &member_offset, &member_length); + if (!exception) { /* * The range is, in fact, contiguous within member_tvb. */ @@ -932,12 +931,15 @@ composite_ensure_contiguous_no_exception(tvbuff_t *tvb, const guint abs_offset, } static const guint8* -ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint length, int *exception) +ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint length, int *pexception) { guint abs_offset, abs_length; + int exception; - if (!check_offset_length_no_exception(tvb, offset, length, - &abs_offset, &abs_length, exception)) { + exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length); + if (exception) { + if (pexception) + *pexception = exception; return NULL; } @@ -1046,7 +1048,7 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, size_t abs_len tvb_comp_t *composite; tvbuff_t *member_tvb = NULL; guint member_offset, member_length; - gboolean retval; + int exception; GSList *slist; DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE); @@ -1065,9 +1067,10 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, size_t abs_len } DISSECTOR_ASSERT(member_tvb); - if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i], - (gint) abs_length, &member_offset, &member_length, NULL)) { - + exception = check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i], + (gint) abs_length, &member_offset, &member_length); + + if (!exception) { DISSECTOR_ASSERT(!tvb->real_data); return tvb_memcpy(member_tvb, target, member_offset, member_length); } @@ -1077,9 +1080,9 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, size_t abs_len * then iterate across the other member tvb's, copying their portions * until we have copied all data. */ - retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1, - &member_offset, &member_length, NULL); - DISSECTOR_ASSERT(retval); + exception = compute_offset_and_remaining(member_tvb, abs_offset - composite->start_offsets[i], + &member_offset, &member_length); + DISSECTOR_ASSERT(!exception); /* composite_memcpy() can't handle a member_length of zero. */ DISSECTOR_ASSERT(member_length); @@ -1909,6 +1912,21 @@ tvb_get_bits(tvbuff_t *tvb, const guint bit_offset, const gint no_of_bits, const return (guint32)_tvb_get_bits64(tvb, bit_offset, no_of_bits); } +static gint +tvb_find_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle) +{ + const guint8 *ptr; + const guint8 *result; + + ptr = tvb_get_ptr(tvb, abs_offset, limit); + + result = (const guint8 *) memchr(ptr, needle, limit); + if (!result) + return -1; + + return (gint) ((result - ptr) + abs_offset); +} + /* Find first occurrence of needle in tvbuff, starting at offset. Searches * at most maxlength number of bytes; if maxlength is -1, searches to * end of tvbuff. @@ -1920,16 +1938,15 @@ gint tvb_find_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const guint8 needle) { const guint8 *result; - guint abs_offset, junk_length; + guint abs_offset; guint tvbufflen; guint limit; DISSECTOR_ASSERT(tvb && tvb->initialized); - check_offset_length(tvb, offset, 0, &abs_offset, &junk_length); + check_offset_length(tvb, offset, -1, &abs_offset, &tvbufflen); /* Only search to end of tvbuff, w/o throwing exception. */ - tvbufflen = tvb_length_remaining(tvb, abs_offset); if (maxlength == -1) { /* No maximum length specified; search to end of tvbuff. */ limit = tvbufflen; @@ -1985,16 +2002,15 @@ gint tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const guint8 *needles, guchar *found_needle) { const guint8 *result; - guint abs_offset, junk_length; + guint abs_offset; guint tvbufflen; guint limit; DISSECTOR_ASSERT(tvb && tvb->initialized); - check_offset_length(tvb, offset, 0, &abs_offset, &junk_length); + check_offset_length(tvb, offset, -1, &abs_offset, &tvbufflen); /* Only search to end of tvbuff, w/o throwing exception. */ - tvbufflen = tvb_length_remaining(tvb, abs_offset); if (maxlength == -1) { /* No maximum length specified; search to end of tvbuff. */ limit = tvbufflen; @@ -2845,11 +2861,12 @@ static gint _tvb_get_nstringz(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8* buffer, gint *bytes_copied) { gint stringlen; - guint abs_offset, junk_length; + guint abs_offset; gint limit, len; gboolean decreased_max = FALSE; - check_offset_length(tvb, offset, 0, &abs_offset, &junk_length); + /* Only read to end of tvbuff, w/o throwing exception. */ + check_offset_length(tvb, offset, -1, &abs_offset, &len); /* There must at least be room for the terminating NUL. */ DISSECTOR_ASSERT(bufsize != 0); @@ -2861,9 +2878,6 @@ _tvb_get_nstringz(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8* return 0; } - /* Only read to end of tvbuff, w/o throwing exception. */ - len = tvb_length_remaining(tvb, abs_offset); - /* check_offset_length() won't throw an exception if we're * looking at the byte immediately after the end of the tvbuff. */ if (len == 0) { @@ -2984,7 +2998,7 @@ tvb_find_line_end(tvbuff_t *tvb, const gint offset, int len, gint *next_offset, guchar found_needle = 0; if (len == -1) - len = tvb_length_remaining(tvb, offset); + len = tvb_captured_length_remaining(tvb, offset); /* * XXX - what if "len" is still -1, meaning "offset is past the * end of the tvbuff"? @@ -3100,7 +3114,7 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, const gint offset, int len, gint *next int linelen; if (len == -1) - len = tvb_length_remaining(tvb, offset); + len = tvb_captured_length_remaining(tvb, offset); /* * XXX - what if "len" is still -1, meaning "offset is past the * end of the tvbuff"? @@ -3238,7 +3252,7 @@ tvb_skip_wsp(tvbuff_t *tvb, const gint offset, const gint maxlength) guint8 tempchar; /* Get the length remaining */ - tvb_len = tvb_length(tvb); + tvb_len = tvb_captured_length(tvb); end = offset + maxlength; if (end >= tvb_len) { @@ -3310,7 +3324,7 @@ tvb_bcd_dig_to_ep_str(tvbuff_t *tvb, const gint offset, const gint len, dgt_set_ dgt = &Dgt1_9_bcd; if (len == -1) { - length = tvb_length(tvb); + length = tvb_captured_length(tvb); if (length < offset) { return ""; } diff --git a/epan/tvbuff.h b/epan/tvbuff.h index 8950feb..f815c1f 100644 --- a/epan/tvbuff.h +++ b/epan/tvbuff.h @@ -213,16 +213,28 @@ WS_DLL_PUBLIC tvbuff_t* tvb_new_composite(void); WS_DLL_PUBLIC void tvb_composite_finalize(tvbuff_t* tvb); -/* Get total length of buffer */ -WS_DLL_PUBLIC guint tvb_length(const tvbuff_t*); +/* Get amount of captured data in the buffer (which is *NOT* necessarily the + * * length of the packet). You probably want tvb_reported_length instead. */ +WS_DLL_PUBLIC guint tvb_captured_length(const tvbuff_t *tvb); + +/* DEPRECATED, do not use in new code, call tvb_captured_length directly! */ +#define tvb_length tvb_captured_length /** Computes bytes to end of buffer, from offset (which can be negative, - * to indicate bytes from end of buffer). Function returns -1 to - * indicate that offset is out of bounds. No exception is thrown. */ -WS_DLL_PUBLIC gint tvb_length_remaining(const tvbuff_t*, const gint offset); + * to indicate bytes from end of buffer). Function returns 0 if offset is out + * of bounds. No exception is thrown. */ +WS_DLL_PUBLIC gint tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset); + +/* DEPRECATED, do not use in new code, call tvb_captured_length_remaining directly! */ +#define tvb_length_remaining tvb_captured_length_remaining + /** Same as above, but throws an exception if the offset is out of bounds. */ -WS_DLL_PUBLIC guint tvb_ensure_length_remaining(const tvbuff_t*, const gint offset); +WS_DLL_PUBLIC guint tvb_ensure_captured_length_remaining(const tvbuff_t *tvb, + const gint offset); + +/* DEPRECATED, do not use in new code, call tvb_ensure_captured_length_remaining directly! */ +#define tvb_ensure_length_remaining tvb_ensure_captured_length_remaining /* Checks (w/o throwing exception) that the bytes referred to by * 'offset'/'length' actually exist in the buffer */ @@ -240,8 +252,7 @@ WS_DLL_PUBLIC guint tvb_reported_length(const tvbuff_t*); /** Computes bytes of reported packet data to end of buffer, from offset * (which can be negative, to indicate bytes from end of buffer). Function - * returns -1 to indicate that offset is out of bounds. No exception is - * thrown. */ + * returns 0 if offset is out of bounds. No exception is thrown. */ WS_DLL_PUBLIC gint tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset); /** Set the reported length of a tvbuff to a given value; used for protocols