diff --git a/core/src/avm2/globals/math.rs b/core/src/avm2/globals/math.rs index 9eb065285..f6365fd9e 100644 --- a/core/src/avm2/globals/math.rs +++ b/core/src/avm2/globals/math.rs @@ -145,5 +145,9 @@ pub fn random<'gc>( _this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(activation.context.rng.gen_range(0.0f64..1.0f64).into()) + // See https://github.com/adobe/avmplus/blob/858d034a3bd3a54d9b70909386435cf4aec81d21/core/MathUtils.cpp#L1731C24-L1731C44 + // This generated a restricted set of 'f64' values, which some SWFs implicitly rely on. + const MAX_VAL: u32 = 0x7FFFFFFF; + let rand = activation.context.rng.gen_range(0..MAX_VAL); + Ok(((rand as f64) / (MAX_VAL as f64 + 1f64)).into()) } diff --git a/tests/tests/swfs/avm2/cryptscore/CryptScore.as b/tests/tests/swfs/avm2/cryptscore/CryptScore.as new file mode 100755 index 000000000..51fcd322a --- /dev/null +++ b/tests/tests/swfs/avm2/cryptscore/CryptScore.as @@ -0,0 +1,75 @@ +package +{ + import flash.display.MovieClip; + import flash.events.Event; + + public class CryptScore + { + + private static var randamaroo:MovieClip; + + + private var bs1:Number; + + private var a:Number; + + private var b:Number; + + private var bs2:Number; + + private var c:Number; + + private var bs3:Number; + + private var bs4:Number; + + private var d:Number; + + private var count:int = 0; + + public function CryptScore(param1:Number = 0, param2:Boolean = false) + { + super(); + if(randamaroo == null) + { + randamaroo = new MovieClip(); + } + randamaroo.addEventListener(Event.ENTER_FRAME,this.randomise,false,0,true); + this.count = Math.random() * 30; + this.value = param1; + } + + private function randomise(param1:Event) : void + { + ++this.count; + if(this.count >= 15) + { + this.value = this.value; + this.count -= 15; + } + } + + public function get value() : Number + { + return this.a - this.b + (this.c - this.d); + } + + public function set value(param1:Number) : void + { + this.bs1 = param1; + this.a = Math.random() * 32; + this.bs2 = -this.a; + do + { + this.b = Math.random() * 14; + this.bs3 = -this.b; + } + while(false); + + var _loc2_:Number = param1 - (this.a - this.b); + this.c = Math.random() * 23; + this.d = this.c - _loc2_; + this.bs4 = -param1; + } + } +} diff --git a/tests/tests/swfs/avm2/cryptscore/Test.as b/tests/tests/swfs/avm2/cryptscore/Test.as new file mode 100755 index 000000000..5bfa0c561 --- /dev/null +++ b/tests/tests/swfs/avm2/cryptscore/Test.as @@ -0,0 +1,28 @@ +package { + + import flash.display.MovieClip; + import flash.events.Event; + + + + public class Test extends MovieClip { + + + public function Test() { + var score = new CryptScore(); + for (var i = 0; i < 10000; i ++) { + if (i % 1000 == 0) { + trace("i = " + i); + } + score.value = score.value; + var value = score.value; + if (value !== 0) { + trace("i = " + i + " Bad value: " + value); + } + } + trace("Done!"); + } + + } + +} diff --git a/tests/tests/swfs/avm2/cryptscore/output.txt b/tests/tests/swfs/avm2/cryptscore/output.txt new file mode 100644 index 000000000..94c9a25b9 --- /dev/null +++ b/tests/tests/swfs/avm2/cryptscore/output.txt @@ -0,0 +1,11 @@ +i = 0 +i = 1000 +i = 2000 +i = 3000 +i = 4000 +i = 5000 +i = 6000 +i = 7000 +i = 8000 +i = 9000 +Done! diff --git a/tests/tests/swfs/avm2/cryptscore/test.fla b/tests/tests/swfs/avm2/cryptscore/test.fla new file mode 100755 index 000000000..88f776a15 Binary files /dev/null and b/tests/tests/swfs/avm2/cryptscore/test.fla differ diff --git a/tests/tests/swfs/avm2/cryptscore/test.swf b/tests/tests/swfs/avm2/cryptscore/test.swf new file mode 100644 index 000000000..342c64d34 Binary files /dev/null and b/tests/tests/swfs/avm2/cryptscore/test.swf differ diff --git a/tests/tests/swfs/avm2/cryptscore/test.toml b/tests/tests/swfs/avm2/cryptscore/test.toml new file mode 100644 index 000000000..e94c41b4e --- /dev/null +++ b/tests/tests/swfs/avm2/cryptscore/test.toml @@ -0,0 +1,7 @@ +# This file tests that our Math.random() implementation works +# correctly for some weird memory-obfuscation logic. +# Flash Player's `Math.random()` implementation generates +# a limited range of `Number`s in the range [0.0, 1.0), which +# allows this swf to correctly compute the original value +# (instead of a very close value due to rounding). +num_ticks = 1 \ No newline at end of file