Double precision value computation errors on MediaTek processors

后端 未结 4 1762
时光取名叫无心
时光取名叫无心 2021-01-03 22:44

I\'ve found that one of my application posted on the market produces weird results on some phones. Upon investigation it turns out there is an issue with one function which

4条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-03 23:19

    I spent the last week investigating this issue and here's what I've found:

    • This bug has been noticed before by the users of MT6589 devices (e.g. here and here)
    • Common workaround was the disabling of JIT (for specific app or for the whole system)
    • I was able to reproduce this issue on the couple of devices with MT6589 and MT8125/8389, currently it hasn't been reproduced on the devices with chips other than mentioned see update sections below
    • The expression which reproduces the bug if far simpler than I posted in the question, just:
      X = A + b / D
    • The delay between calculations is a crucial part of the bug: without it bug appears sporadically, with a small sleep after calculation it reproduces always (once the code has been JITed)
    • I've created a script which assembles a simple jar file and runs dalvikvm directly, passing parameters to it. This allowed to set jit threshold and receive output ARM code generated by JIT
    • Passing -Xjitdisableopt:1 to the Dalvik fixes the issue (this parameter disables kLoadStoreElimination optimization). One may also add dalvik.vm.extra-opts=-Xjitdisableopt:1 to build.prop file as a quick workaround which preserves JIT (root and reboot are required)
    • Though this issue looks similar to the bug #63790 mentioned by Scott Barta, I think it's the different one (also author of mentioned bug Dmitry have confirmed that this "Mediatek" bug doesn't reproduces on the phone affected by #63790)
    • UPDATE: I've putted libdvm.so (from Fly IQ4410 with MT6589 chip) on the emulator and the bug reproduced there. But if I use libdvm.so compiled from the Android 4.2 sources the bug disappears. It looks like there is an issue with JIT compiled code produced by some specific version of libdvm library shipped with affected devices
    • UPDATE: Successfully reproduced the bug on Samsung Ace 2 phone (NovaThor U8500, Android 4.1.2) using the same technique as above - took libdvm.so from Fly IQ444 (MT6589, Android 4.1.2)

    I've submitted a bug report #65750.

    Here are the source and the JIT assembly output of the test used to reproduce the bug:

    public class Calc {
    
      static final double A = 0.5;
      static final double B = 1;
      static final double D = 16384;
    
      public double calcX() {
        double t = B;
        double X = A + t / D;
        return X;
      }    
    }
    

    JIT output for a usual run of Dalvik:

    D/dalvikvm: Dumping LIR insns
    D/dalvikvm: installed code is at 0x45deb000
    D/dalvikvm: total size is 124 bytes
    D/dalvikvm: 0x45deb000 (0000): data    0xc278(49784)
    D/dalvikvm: 0x45deb002 (0002): data    0x457a(17786)
    D/dalvikvm: 0x45deb004 (0004): data    0x0044(68)
    D/dalvikvm: 0x45deb006 (0006): ldr     r0, [r15pc, -#8]
    D/dalvikvm: 0x45deb00a (000a): ldr     r1, [r0, #0]
    D/dalvikvm: 0x45deb00c (000c): adds    r1, r1, #1
    D/dalvikvm: 0x45deb00e (000e): str     r1, [r0, #0]
    D/dalvikvm: -------- entry offset: 0x0000
    D/dalvikvm: L0x4579e28c:
    D/dalvikvm: -------- dalvik offset: 0x0000 @ const-wide/high16 v0, (#16368), (#0)
    D/dalvikvm: 0x45deb010 (0010): vldr    d8, [r15, #96]
    D/dalvikvm: -------- dalvik offset: 0x0002 @ const-wide/high16 v2, (#16352), (#0)
    D/dalvikvm: 0x45deb014 (0014): vmov.f64  d9, d8
    D/dalvikvm: -------- dalvik offset: 0x0004 @ const-wide/high16 v4, (#16592), (#0)
    D/dalvikvm: 0x45deb018 (0018): vmov.f64  d10, d9
    D/dalvikvm: -------- dalvik offset: 0x0006 @ div-double/2addr v0, v4, (#0)
    D/dalvikvm: 0x45deb01c (001c): vdivd   d8, d8, d10
    D/dalvikvm: -------- dalvik offset: 0x0007 @ add-double/2addr v0, v2, (#0)
    D/dalvikvm: 0x45deb020 (0020): vadd    d8, d8, d9
    D/dalvikvm: -------- dalvik offset: 0x0008 @ return-wide v0, (#0), (#0)
    D/dalvikvm: 0x45deb024 (0024): vmov.f64  d11, d8
    D/dalvikvm: 0x45deb028 (0028): vstr    d11, [r6, #16]
    D/dalvikvm: 0x45deb02c (002c): vstr    d8, [r5, #0]
    D/dalvikvm: 0x45deb030 (0030): vstr    d10, [r5, #16]
    D/dalvikvm: 0x45deb034 (0034): vstr    d9, [r5, #8]
    D/dalvikvm: 0x45deb038 (0038): blx_1   0x45dea028
    D/dalvikvm: 0x45deb03a (003a): blx_2   see above
    D/dalvikvm: 0x45deb03c (003c): b       0x45deb040 (L0x4579f068)
    D/dalvikvm: 0x45deb03e (003e): undefined
    D/dalvikvm: L0x4579f068:
    D/dalvikvm: -------- reconstruct dalvik PC : 0x457b83f4 @ +0x0008
    D/dalvikvm: 0x45deb040 (0040): ldr     r0, [r15pc, #28]
    D/dalvikvm: Exception_Handling:
    D/dalvikvm: 0x45deb044 (0044): ldr     r1, [r6, #108]
    D/dalvikvm: 0x45deb046 (0046): blx     r1
    D/dalvikvm: -------- end of chaining cells (0x0048)
    D/dalvikvm: 0x45deb060 (0060): .word (0x457b83f4)
    D/dalvikvm: 0x45deb064 (0064): .word (0)
    D/dalvikvm: 0x45deb068 (0068): .word (0x40d00000)
    D/dalvikvm: 0x45deb06c (006c): .word (0)
    D/dalvikvm: 0x45deb070 (0070): .word (0x3fe00000)
    D/dalvikvm: 0x45deb074 (0074): .word (0)
    D/dalvikvm: 0x45deb078 (0078): .word (0x3ff00000)
    D/dalvikvm: End LCalc;calcX, 6 Dalvik instructions.
    

    The most interesting part is:

    vldr    d8, [r15, #96]   ;  d8 := 1.0
    vmov.f64  d9, d8         ;  d9 := d8
    vmov.f64  d10, d9        ;  d10 := d9   // now d8, d9 and d10 contains 1.0 !!!
    vdivd   d8, d8, d10      ;  d8 := d8 / d10 = 1.0
    vadd    d8, d8, d9       ;  d8 := d8 + d9 = 2.0
    vmov.f64  d11, d8
    

    Well the code produced by JIT looks completely wrong. Instead of three only one constant is read 1.0, and as a result we receive the computation of X = 1.0 + 1.0 / 1.0 which not surprisingly evaluates to 2.0

    And here is the JIT output for Dalvik run with kLoadStoreElimination optimization disabled (which fixes the bug):

    D/dalvikvm: Dumping LIR insns
    D/dalvikvm: installed code is at 0x45d64000
    D/dalvikvm: total size is 124 bytes
    D/dalvikvm: 0x45d64000 (0000): data    0x5260(21088)
    D/dalvikvm: 0x45d64002 (0002): data    0x4572(17778)
    D/dalvikvm: 0x45d64004 (0004): data    0x0044(68)
    D/dalvikvm: 0x45d64006 (0006): ldr     r0, [r15pc, -#8]
    D/dalvikvm: 0x45d6400a (000a): ldr     r1, [r0, #0]
    D/dalvikvm: 0x45d6400c (000c): adds    r1, r1, #1
    D/dalvikvm: 0x45d6400e (000e): str     r1, [r0, #0]
    D/dalvikvm: -------- entry offset: 0x0000
    D/dalvikvm: L0x45717274:
    D/dalvikvm: -------- dalvik offset: 0x0000 @ const-wide/high16 v0, (#16368), (#0)
    D/dalvikvm: 0x45d64010 (0010): vldr    d8, [r15, #96]
    D/dalvikvm: -------- dalvik offset: 0x0002 @ const-wide/high16 v2, (#16352), (#0)
    D/dalvikvm: 0x45d64014 (0014): vldr    d10, [r15, #76]
    D/dalvikvm: 0x45d64018 (0018): vldr    d9, [r15, #80]
    D/dalvikvm: 0x45d6401c (001c): vstr    d9, [r5, #8]
    D/dalvikvm: -------- dalvik offset: 0x0004 @ const-wide/high16 v4, (#16592), (#0)
    D/dalvikvm: 0x45d64020 (0020): vstr    d10, [r5, #16]
    D/dalvikvm: -------- dalvik offset: 0x0006 @ div-double/2addr v0, v4, (#0)
    D/dalvikvm: 0x45d64024 (0024): vdivd   d8, d8, d10
    D/dalvikvm: -------- dalvik offset: 0x0007 @ add-double/2addr v0, v2, (#0)
    D/dalvikvm: 0x45d64028 (0028): vadd    d8, d8, d9
    D/dalvikvm: 0x45d6402c (002c): vstr    d8, [r5, #0]
    D/dalvikvm: -------- dalvik offset: 0x0008 @ return-wide v0, (#0), (#0)
    D/dalvikvm: 0x45d64030 (0030): vmov.f64  d11, d8
    D/dalvikvm: 0x45d64034 (0034): vstr    d11, [r6, #16]
    D/dalvikvm: 0x45d64038 (0038): blx_1   0x45d63028
    D/dalvikvm: 0x45d6403a (003a): blx_2   see above
    D/dalvikvm: 0x45d6403c (003c): b       0x45d64040 (L0x45718050)
    D/dalvikvm: 0x45d6403e (003e): undefined
    D/dalvikvm: L0x45718050:
    D/dalvikvm: -------- reconstruct dalvik PC : 0x457313f4 @ +0x0008
    D/dalvikvm: 0x45d64040 (0040): ldr     r0, [r15pc, #28]
    D/dalvikvm: Exception_Handling:
    D/dalvikvm: 0x45d64044 (0044): ldr     r1, [r6, #108]
    D/dalvikvm: 0x45d64046 (0046): blx     r1
    D/dalvikvm: -------- end of chaining cells (0x0048)
    D/dalvikvm: 0x45d64060 (0060): .word (0x457313f4)
    D/dalvikvm: 0x45d64064 (0064): .word (0)
    D/dalvikvm: 0x45d64068 (0068): .word (0x40d00000)
    D/dalvikvm: 0x45d6406c (006c): .word (0)
    D/dalvikvm: 0x45d64070 (0070): .word (0x3fe00000)
    D/dalvikvm: 0x45d64074 (0074): .word (0)
    D/dalvikvm: 0x45d64078 (0078): .word (0x3ff00000)
    D/dalvikvm: End LCalc;calcX, 6 Dalvik instructions
    

    All three constants loaded as expected and correct evaluation is performed.

提交回复
热议问题