summaryrefslogtreecommitdiff
path: root/libavcodec/get_bits.h
diff options
context:
space:
mode:
authorRonald S. Bultje <rsbultje@gmail.com>2011-12-16 21:42:04 +0000
committerMans Rullgard <mans@mansr.com>2011-12-17 14:03:41 +0000
commit8cfbbd928cc94b4de6ad0a937cb818e999c7d75d (patch)
tree554918ba1509d4c296738f7e4a7313685ee92c41 /libavcodec/get_bits.h
parenta1e98f198e9db4e5ddfc2f777014179d3d7bc4d2 (diff)
get_bits: introduce safe bitreading to prevent overreads.
When turned on, H264/CAVLC gets ~15% (CVPCMNL1_SVA_C.264) slower for ultra-high-bitrate files, or ~2.5% (CVFI1_SVA_C.264) for lower-bitrate files. Other codecs are affected to a lesser extent because they are less optimized; e.g., VC-1 slows down by less than 1% (all on x86). The patch generated 3 extra instructions (cmp, cmovae and mov) per call to get_bits(). The performance penalty on ARM is within the error margin for most files, up to 4% in extreme cases such as CVPCMNL1_SVA_C.264. Based on work (for GCI) by Aneesh Dogra <lionaneesh@gmail.com>, and inspired by patch in Chromium by Chris Evans <cevans@chromium.org>.
Diffstat (limited to 'libavcodec/get_bits.h')
-rw-r--r--libavcodec/get_bits.h37
1 files changed, 36 insertions, 1 deletions
diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
index 684cc992fe..33ddb4b89f 100644
--- a/libavcodec/get_bits.h
+++ b/libavcodec/get_bits.h
@@ -35,12 +35,32 @@
#include "libavutil/log.h"
#include "mathops.h"
+/*
+ * Safe bitstream reading:
+ * optionally, the get_bits API can check to ensure that we
+ * don't read past input buffer boundaries. This is protected
+ * with CONFIG_SAFE_BITSTREAM_READER at the global level, and
+ * then below that with UNCHECKED_BITSTREAM_READER at the per-
+ * decoder level. This means that decoders that check internally
+ * can "#define UNCHECKED_BITSTREAM_READER 1" to disable
+ * overread checks.
+ * Boundary checking causes a minor performance penalty so for
+ * applications that won't want/need this, it can be disabled
+ * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0".
+ */
+#ifndef UNCHECKED_BITSTREAM_READER
+#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
+#endif
+
/* bit input */
/* buffer, buffer_end and size_in_bits must be present and used by every reader */
typedef struct GetBitContext {
const uint8_t *buffer, *buffer_end;
int index;
int size_in_bits;
+#if !UNCHECKED_BITSTREAM_READER
+ int size_in_bits_plus8;
+#endif
} GetBitContext;
#define VLC_TYPE int16_t
@@ -137,7 +157,12 @@ for examples see get_bits, show_bits, skip_bits, get_vlc
# endif
// FIXME name?
+#if UNCHECKED_BITSTREAM_READER
# define SKIP_COUNTER(name, gb, num) name##_index += (num)
+#else
+# define SKIP_COUNTER(name, gb, num) \
+ name##_index = FFMIN((gb)->size_in_bits_plus8, name##_index + (num))
+#endif
# define SKIP_BITS(name, gb, num) do { \
SKIP_CACHE(name, gb, num); \
@@ -164,7 +189,11 @@ static inline int get_bits_count(const GetBitContext *s){
}
static inline void skip_bits_long(GetBitContext *s, int n){
+#if UNCHECKED_BITSTREAM_READER
s->index += n;
+#else
+ s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index);
+#endif
}
/**
@@ -237,7 +266,10 @@ static inline unsigned int get_bits1(GetBitContext *s){
result <<= index & 7;
result >>= 8 - 1;
#endif
- index++;
+#if !UNCHECKED_BITSTREAM_READER
+ if (s->index < s->size_in_bits_plus8)
+#endif
+ index++;
s->index = index;
return result;
@@ -314,6 +346,9 @@ static inline void init_get_bits(GetBitContext *s,
s->buffer = buffer;
s->size_in_bits = bit_size;
+#if !UNCHECKED_BITSTREAM_READER
+ s->size_in_bits_plus8 = bit_size + 8;
+#endif
s->buffer_end = buffer + buffer_size;
s->index = 0;
}