aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Essick <essick@google.com>2019-01-28 14:10:29 -0800
committerRay Essick <essick@google.com>2019-01-28 14:10:29 -0800
commit178dd42cb5bf02cfb162209faf6e8b238b6215bd (patch)
tree55db32199762cebe447d01aaed990085b648a2d6
parent31ed9ac202461bb76d36cf42fcf1f3e1e31ef745 (diff)
downloadlibopus-178dd42cb5bf02cfb162209faf6e8b238b6215bd.tar.gz
Fix integer overflow diagnostics within opus
Recast several points in the Opus code where integer overflow happens. The code expects overflow in these macros, but doesn't expect the system to abort when it happens. This also includes saturating math. Bug: 123428774 Test: Cts android.media.cts.EncoderTest#testOpusEncoders
-rw-r--r--silk/SigProc_FIX.h29
-rw-r--r--silk/macros.h30
2 files changed, 49 insertions, 10 deletions
diff --git a/silk/SigProc_FIX.h b/silk/SigProc_FIX.h
index f9ae3263..a9068908 100644
--- a/silk/SigProc_FIX.h
+++ b/silk/SigProc_FIX.h
@@ -448,13 +448,29 @@ static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot )
/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
(just standard two's complement implementation-specific behaviour) */
-#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b)))
+static OPUS_INLINE opus_int32 silk_ADD32_ovflw(opus_int32 a, opus_int32 b) {
+ opus_int32 _c;
+ __builtin_add_overflow(a, b, &_c);
+ return _c;
+}
+
/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
(just standard two's complement implementation-specific behaviour) */
-#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b)))
+static OPUS_INLINE opus_int32 silk_SUB32_ovflw(opus_int32 a, opus_int32 b) {
+ opus_int32 _c;
+ __builtin_sub_overflow(a, b, &_c);
+ return _c;
+}
/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
-#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32))
+/* .. also ignoring multiply overflows; caller has comment about this happening occasionally */
+static OPUS_INLINE opus_int32 silk_MLA_ovflw(opus_int32 a, opus_int32 b, opus_int32 c) {
+ opus_int32 _d, _e;
+ __builtin_mul_overflow(b, c, &_d);
+ __builtin_add_overflow(a, _d, &_e);
+ return _e;
+}
+
#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))))
#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16)))
@@ -496,7 +512,12 @@ static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot )
/* Add with saturation for positive input values */
#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b)))
#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)))
-#define silk_ADD_POS_SAT32(a, b) ((((opus_uint32)(a)+(opus_uint32)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)))
+static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int32 a, opus_int32 b) {
+ opus_int32 _c;
+ if (__builtin_add_overflow(a, b, &_c))
+ return silk_int32_MAX;
+ return _c;
+}
#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */
#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */
diff --git a/silk/macros.h b/silk/macros.h
index 3c67b6e5..b9579e51 100644
--- a/silk/macros.h
+++ b/silk/macros.h
@@ -96,13 +96,31 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
/* add/subtract with output saturated */
-#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \
- ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \
- ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) )
+/* use clang builtin overflow detectors */
+static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a, opus_int32 b) {
+ opus_int32 c;
+ if (__builtin_add_overflow(a, b, &c)) {
+ // overflowed
+ if (a < 0) // neg+X can only overflow towards -inf
+ c = silk_int32_MIN;
+ else
+ c = silk_int32_MAX;
+ }
+ return c;
+}
-#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \
- (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \
- ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) )
+/* use clang builtin overflow detectors */
+static OPUS_INLINE opus_int32 silk_SUB_SAT32(opus_int32 a, opus_int32 b) {
+ opus_int32 c;
+ if (__builtin_sub_overflow(a, b, &c)) {
+ // overflowed,
+ if (a < 0) // neg-X only overflows towards -inf
+ c = silk_int32_MIN;
+ else
+ c = silk_int32_MAX;
+ }
+ return c;
+}
#if defined(MIPSr1_ASM)
#include "mips/macros_mipsr1.h"