Blob Blame History Raw
diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c
index 3fbce14..ed9e74c 100644
--- a/epan/dissectors/packet-frame.c
+++ b/epan/dissectors/packet-frame.c
@@ -228,9 +228,9 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 	}
 
 	if(pinfo->fd->opt_comment){
-		item = proto_tree_add_item(tree, proto_pkt_comment, tvb, 0, -1, ENC_NA);
+		item = proto_tree_add_item(tree, proto_pkt_comment, tvb, 0, 0, ENC_NA);
 		comments_tree = proto_item_add_subtree(item, ett_comments);
-		comment_item = proto_tree_add_string_format(comments_tree, hf_comments_text, tvb, 0, -1,
+		comment_item = proto_tree_add_string_format(comments_tree, hf_comments_text, tvb, 0, 0,
 							                   pinfo->fd->opt_comment, "%s",
 							                   pinfo->fd->opt_comment);
 		expert_add_info_format(pinfo, comment_item, PI_COMMENTS_GROUP, PI_COMMENT,
@@ -259,7 +259,7 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 		cap_plurality = plurality(cap_len, "", "s");
 		frame_plurality = plurality(frame_len, "", "s");
 
-		ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, -1,
+		ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_length(tvb),
 		    "Frame %u: %u byte%s on wire",
 		    pinfo->fd->num, frame_len, frame_plurality);
 		if (generate_bits_field)
@@ -458,7 +458,7 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 	if (pinfo->fd->flags.ignored) {
 		/* Ignored package, stop handling here */
 		col_set_str(pinfo->cinfo, COL_INFO, "<Ignored>");
-		proto_tree_add_text (tree, tvb, 0, -1, "This frame is marked as ignored");
+		proto_tree_add_text (tree, tvb, 0, 0, "This frame is marked as ignored");
 		return;
 	}
 
diff --git a/epan/proto.c b/epan/proto.c
index 9e55ea7..775aca8 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -3536,15 +3536,7 @@ get_hfi_and_length(int hfindex, tvbuff_t *tvb, const gint start, gint *length,
 			 * end of the tvbuff, so we throw an
 			 * exception.
 			 */
-			*length = tvb_length_remaining(tvb, start);
-			if (*length < 0) {
-				/*
-				 * Use "tvb_ensure_bytes_exist()"
-				 * to force the appropriate exception
-				 * to be thrown.
-				 */
-				tvb_ensure_bytes_exist(tvb, start, 0);
-			}
+			*length = tvb_length_remaining_cheat(tvb, start);
 			DISSECTOR_ASSERT(*length >= 0);
 			break;
 
diff --git a/epan/tvbuff.c b/epan/tvbuff.c
index 0b9d8fb..ca72263 100644
--- a/epan/tvbuff.c
+++ b/epan/tvbuff.c
@@ -427,6 +427,51 @@ tvb_new_with_subset(tvbuff_t *backing, const gint reported_length,
 	return tvb;
 }
 
+static inline int
+compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
+{
+	if (offset >= 0) {
+		/* Positive offset - relative to the beginning of the packet. */
+		if ((guint) offset <= tvb->length) {
+			*offset_ptr = offset;
+		} else if ((guint) offset <= tvb->reported_length) {
+			return BoundsError;
+		} else if (tvb->flags & TVBUFF_FRAGMENT) {
+			return FragmentBoundsError;
+		} else {
+			return ReportedBoundsError;
+		}
+	}
+	else {
+		/* Negative offset - relative to the end of the packet. */
+		if ((guint) -offset <= tvb->length) {
+			*offset_ptr = tvb->length + offset;
+		} else if ((guint) -offset <= tvb->reported_length) {
+			return BoundsError;
+		} else if (tvb->flags & TVBUFF_FRAGMENT) {
+			return FragmentBoundsError;
+		} else {
+			return ReportedBoundsError;
+		}
+	}
+
+	return 0;
+}
+
+
+static inline 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;
+}
+
+
 tvbuff_t *
 tvb_new_subset(tvbuff_t *backing, const gint backing_offset, const gint backing_length, const gint reported_length)
 {
@@ -701,6 +746,24 @@ tvb_length_remaining(const tvbuff_t *tvb, const gint offset)
 	}
 }
 
+/* Just like tvb_length_remaining except it doesn't have to
+ * guarantee that at least one byte is available, it simply guarantees that the
+ * offset exists (so a 0 offset in a 0-length tvb won't throw) */
+guint
+tvb_length_remaining_cheat(const tvbuff_t *tvb, const gint offset)
+{
+	guint abs_offset, rem_length;
+	int exception;
+
+	DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+	exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length);
+	if (exception)
+		THROW(exception);
+
+	return rem_length;
+}
+
 guint
 tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
diff --git a/epan/tvbuff.h b/epan/tvbuff.h
index 8950feb..dbb8c57 100644
--- a/epan/tvbuff.h
+++ b/epan/tvbuff.h
@@ -221,6 +221,12 @@ WS_DLL_PUBLIC guint tvb_length(const tvbuff_t*);
  * indicate that offset is out of bounds. No exception is thrown. */
 WS_DLL_PUBLIC gint tvb_length_remaining(const tvbuff_t*, const gint offset);
 
+/** Same as above, but permits offsets at the end of the tvbuff (such as an
+ * offset of 0 in a tvbuff with a snapshot length of 0, which is a silly thing
+ * to do but we have to be able to handle it gracefully). */
+WS_DLL_PUBLIC guint tvb_length_remaining_cheat(
+    const tvbuff_t *tvb, const gint offset);
+
 /** 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);