Bug 867174 - Part 2: Protect against invalid sample rates a bit harder; r=padenot

This commit is contained in:
Ehsan Akhgari 2013-05-06 11:34:03 -04:00
parent 765b164af0
commit f73325c4ae
4 changed files with 151 additions and 4 deletions

View File

@ -297,9 +297,16 @@ public:
return mStart + mPosition;
}
int32_t ComputeFinalOutSampleRate() const
uint32_t ComputeFinalOutSampleRate()
{
return static_cast<uint32_t>(IdealAudioRate() / (mPlaybackRate * mDopplerShift));
if (mPlaybackRate <= 0 || mPlaybackRate != mPlaybackRate) {
mPlaybackRate = 1.0f;
}
if (mDopplerShift <= 0 || mDopplerShift != mDopplerShift) {
mDopplerShift = 1.0f;
}
return WebAudioUtils::TruncateFloatToInt<uint32_t>(IdealAudioRate() /
(mPlaybackRate * mDopplerShift));
}
bool ShouldResample() const
@ -317,9 +324,11 @@ public:
mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition());
}
// Make sure the playback rate if something our resampler can work with.
if (mPlaybackRate <= 0.0 || mPlaybackRate >= 1024) {
// Make sure the playback rate and the doppler shift are something
// our resampler can work with.
if (ComputeFinalOutSampleRate() == 0) {
mPlaybackRate = 1.0;
mDopplerShift = 1.0;
}
uint32_t currentOutSampleRate, currentInSampleRate;

View File

@ -8,6 +8,9 @@
#define WebAudioUtils_h_
#include <cmath>
#include <limits>
#include "mozilla/TypeTraits.h"
#include "mozilla/Assertions.h"
#include "AudioParamTimeline.h"
#include "MediaSegment.h"
@ -95,6 +98,100 @@ struct WebAudioUtils {
static double StreamPositionToDestinationTime(TrackTicks aSourcePosition,
AudioNodeStream* aSource,
AudioNodeStream* aDestination);
/**
* Converts a floating point value to an integral type in a safe and
* platform agnostic way. The following program demonstrates the kinds
* of ways things can go wrong depending on the CPU architecture you're
* compiling for:
*
* #include <stdio.h>
* volatile float r;
* int main()
* {
* unsigned int q;
* r = 1e100;
* q = r;
* printf("%f %d\n", r, q);
* r = -1e100;
* q = r;
* printf("%f %d\n", r, q);
* r = 1e15;
* q = r;
* printf("%f %x\n", r, q);
* r = 0/0.;
* q = r;
* printf("%f %d\n", r, q);
* }
*
* This program, when compiled for unsigned int, generates the following
* results depending on the architecture:
*
* x86 and x86-64
* ---
* inf 0
* -inf 0
* 999999995904.000000 -727384064 d4a50000
* nan 0
*
* ARM
* ---
* inf -1
* -inf 0
* 999999995904.000000 -1
* nan 0
*
* When compiled for int, this program generates the following results:
*
* x86 and x86-64
* ---
* inf -2147483648
* -inf -2147483648
* 999999995904.000000 -2147483648
* nan -2147483648
*
* ARM
* ---
* inf 2147483647
* -inf -2147483648
* 999999995904.000000 2147483647
* nan 0
*
* Note that the caller is responsible to make sure that the value
* passed to this function is not a NaN. This function will abort if
* it sees a NaN.
*/
template <typename IntType, typename FloatType>
static IntType TruncateFloatToInt(FloatType f)
{
using namespace std;
MOZ_STATIC_ASSERT((mozilla::IsIntegral<IntType>::value == true),
"IntType must be an integral type");
MOZ_STATIC_ASSERT((mozilla::IsFloatingPoint<FloatType>::value == true),
"FloatType must be a floating point type");
if (f != f) {
// It is the responsibility of the caller to deal with NaN values.
// If we ever get to this point, we have a serious bug to fix.
NS_RUNTIMEABORT("We should never see a NaN here");
}
if (f > FloatType(numeric_limits<IntType>::max())) {
// If the floating point value is outside of the range of maximum
// integral value for this type, just clamp to the maximum value.
return numeric_limits<IntType>::max();
}
if (f < FloatType(numeric_limits<IntType>::min())) {
// If the floating point value is outside of the range of minimum
// integral value for this type, just clamp to the minimum value.
return numeric_limits<IntType>::min();
}
// Otherwise, this conversion must be well defined.
return IntType(f);
}
};
}

View File

@ -20,6 +20,7 @@ MOCHITEST_FILES := \
test_bug866570.html \
test_bug866737.html \
test_bug867089.html \
test_bug867174.html \
test_bug867203.html \
test_analyserNode.html \
test_AudioBuffer.html \

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Crashtest for bug 867174</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var ctx = new AudioContext();
var source = ctx.createBufferSource();
var buffer = ctx.createBuffer(2, 2048, 8000);
source.playbackRate.setTargetValueAtTime(0, 2, 3);
var sp = ctx.createScriptProcessor();
source.connect(sp);
sp.connect(ctx.destination);
source.start(0);
sp.onaudioprocess = function(e) {
// Now set the buffer
source.buffer = buffer;
ok(true, "We did not crash.");
sp.onaudioprocess = null;
SpecialPowers.clearUserPref("media.webaudio.enabled");
SimpleTest.finish();
};
});
</script>
</pre>
</body>
</html>