diff options
author | Evan Huus <eapache@gmail.com> | 2013-10-22 16:29:10 +0000 |
---|---|---|
committer | Evan Huus <eapache@gmail.com> | 2013-10-22 16:29:10 +0000 |
commit | 7aee8b2dcf70cade2c3732eef0649220a79e82a8 (patch) | |
tree | cb21f0d551aff346b89fe991ae9e1ca364ee914c /epan/tvbuff.c | |
parent | a3a15ff90b3aca7f94e853ddcaeb1f373368a29c (diff) |
Optimize tvb_ensure_bytes_exist through manual inlining and removal of redundant
checks and computations. Should contain no behavioural changes at *all*, I hope.
svn path=/trunk/; revision=52768
Diffstat (limited to 'epan/tvbuff.c')
-rw-r--r-- | epan/tvbuff.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/epan/tvbuff.c b/epan/tvbuff.c index e783746acd..d6c44a08ed 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -467,7 +467,7 @@ tvb_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length) void tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length) { - guint abs_offset, abs_length; + guint real_offset, end_offset; DISSECTOR_ASSERT(tvb && tvb->initialized); @@ -484,7 +484,56 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length if (length < 0) { THROW(ReportedBoundsError); } - check_offset_length(tvb, offset, length, &abs_offset, &abs_length); + + /* XXX: Below this point could be replaced with a call to + * check_offset_length with no functional change, however this is a + * *very* hot path and check_offset_length is not well-optimized for + * this case, so we eat some code duplication for a lot of speedup. */ + + if (offset >= 0) { + /* Positive offset - relative to the beginning of the packet. */ + if ((guint) offset <= tvb->length) { + real_offset = offset; + } else if ((guint) offset <= tvb->reported_length) { + THROW(BoundsError); + } else if (tvb->flags & TVBUFF_FRAGMENT) { + THROW(FragmentBoundsError); + } else { + THROW(ReportedBoundsError); + } + } + else { + /* Negative offset - relative to the end of the packet. */ + if ((guint) -offset <= tvb->length) { + real_offset = tvb->length + offset; + } else if ((guint) -offset <= tvb->reported_length) { + THROW(BoundsError); + } else if (tvb->flags & TVBUFF_FRAGMENT) { + THROW(FragmentBoundsError); + } else { + THROW(ReportedBoundsError); + } + } + + /* + * Compute the offset of the first byte past the length. + */ + end_offset = real_offset + length; + + /* + * Check for an overflow + */ + if (end_offset < real_offset) + THROW(BoundsError); + + if (G_LIKELY(end_offset <= tvb->length)) + return; + else if (end_offset <= tvb->reported_length) + THROW(BoundsError); + else if (tvb->flags & TVBUFF_FRAGMENT) + THROW(FragmentBoundsError); + else + THROW(ReportedBoundsError); } gboolean |