Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potentially critical bug: Unexpected, reproducible calculation error #22810

Closed
psorowka opened this issue Sep 11, 2018 · 19 comments
Closed

Potentially critical bug: Unexpected, reproducible calculation error #22810

psorowka opened this issue Sep 11, 2018 · 19 comments
Labels
confirmed-bug Issues with confirmed bugs. v8 engine Issues and PRs related to the V8 dependency.

Comments

@psorowka
Copy link

psorowka commented Sep 11, 2018

  • Version: 8.x
  • Platform: docker ( official node as well as mhart/alpine-node)
  • Subsystem: core

The following minimal sample code results in reproducible, unexpected behavior:

const one = 150
const two = 2
let counter = 0

setInterval(() => {
  const res = Math.max(5, Math.floor(one / two))
  if (res > 100) {
    console.log(counter, res)
  } else {
    counter++
  }
}, 1)

Expected behavior
This code should never output anything, because the calculation result is always 75

Actual behavior
After a while, the code starts to output the value of the variable one. This happens reliably once at counter value 5.398 and at each iteration starting from 10.794. The behavior is identical (even more or less the counter values) when changing the values of the variables or making the timer slower. The actual bug seems to happen within the Math.max, the result of Math.floor looks good.

Side notes

  • reliably happens when using node:8, node:8.9, node:8.11, mhart/alpine-node:8.9 (and more) docker images, both on Mac and Linux host systems
  • doesn't happen when changing the setInterval to a while loop
  • doesn't happen when using node:6 or node:10 docker images
  • bug first occured within a big software project and was easily reproducible in this minimal sample
  • the counter isn't needed for showing the bug, it's just to demonstrate how deterministic the problem seems to be
  • even when splitting the calculation into
const floored = Math.floor(one / two)
const res = Math.max(5, floored)

res will carry the value of one after around 10.000 iterations

I don't get what happens under the hood, but I assume this is critical.

@vsemozhetbyt
Copy link
Contributor

vsemozhetbyt commented Sep 11, 2018

Can reproduce on Windows 7 x64 with Node.js 8.11.4

@BridgeAR BridgeAR added the confirmed-bug Issues with confirmed bugs. label Sep 11, 2018
@BridgeAR
Copy link
Member

@nodejs/v8 this seems like a fixed V8 issue. Since this is pretty bad, could you point out what commit fixed this so we can backport that?

@mscdex
Copy link
Contributor

mscdex commented Sep 11, 2018

It looks like this is limited to reuse of the same function. Also FWIW I can reproduce this faster by placing the code in a function and calling the function in an infinite while loop:

const one = 150
const two = 2
let counter = 0

function next() {
  const res = Math.max(5, Math.floor(one / two))
  if (res > 100) {
    console.log(counter, res)
  } else {
    counter++
  }
}

while (true)
  next()

@mscdex
Copy link
Contributor

mscdex commented Sep 11, 2018

Also does not seem to reproduce with --minimal which always uses Ignition and performs no optimizations.

@mscdex
Copy link
Contributor

mscdex commented Sep 12, 2018

It looks like this was fixed between V8 6.6.281 and 6.6.285.

@mscdex
Copy link
Contributor

mscdex commented Sep 12, 2018

Narrowing it down further it seems this commit fixed the issue.

@mscdex mscdex added v8.x v8 engine Issues and PRs related to the V8 dependency. labels Sep 12, 2018
@psorowka
Copy link
Author

Interesting. For completeness I'd like to add that I can only reproduce the problem with Math.floor and not e.g. with Math.round. However, the behavior is the same when doing Math.min instead, but the winner of the min/max operation must point to the result of floor, e.g.

Math.min(Math.floor(one/two), 5e5)

@ryzokuken
Copy link
Contributor

The actual bug seems to happen within the Math.max, the result of Math.floor looks good.

Does it? I mean, I couldn't reproduce this after replacing the Math.floor(...) call with 75 .

@psorowka
Copy link
Author

The actual bug seems to happen within the Math.max, the result of Math.floor looks good.

Does it? I mean, I couldn't reproduce this after replacing the Math.floor(...) call with 75 .

Right, It is the combination of both (see my last comment), meanwhile I also believe that Math.floor has the error, but it only appears when you refer to it in the Math.max....

@ryzokuken
Copy link
Contributor

@psorowka interesting. I'll try to replicate this on v8's master today and dive deeper if it still exists, thanks to @mscdex narrowing it down to turbofan.

Could someone try this on node's master branch as well?

@hashseed
Copy link
Member

hashseed commented Sep 12, 2018

@sigurdschneider @bmeurer is this an accidental fix for this issue? If yes, could you please spend some time to make sure this is actually fixed?

@sigurdschneider
Copy link

I've looked into this, and the CL you bisected to only incidentally fixes this example. The real fix is

https://chromium.googlesource.com/v8/v8/+/d520ebb9a85b73b2a6505e133a7cc940c7d2adbd

which should be floated on top of all affected node versions. @targos Could you take care of this?

@hashseed
Copy link
Member

hashseed commented Oct 9, 2018

@targos did you float this patch? Can this issue be closed?

@targos
Copy link
Member

targos commented Oct 10, 2018

I don't think I did.

@apapirovski
Copy link
Member

I can no longer reproduce this on node 8.x so I assume the patch was floated and this can be closed out. Please feel free to re-open if you believe I've made a mistake.

@apapirovski
Copy link
Member

Nope. :( Appears this is still an issue. Maybe ping @targos?

@targos
Copy link
Member

targos commented Apr 23, 2019

working on it

targos added a commit to targos/node that referenced this issue Apr 23, 2019
Original commit message:

    [turbofan] Fix NumberFloor typing.

    Bug: chromium:841117
    Change-Id: I1e83dfc82f87d0b49d3cca96290ae1d738e37d20
    Reviewed-on: https://chromium-review.googlesource.com/1051228
    Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
    Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#53083}

Refs: v8/v8@d520ebb
Fixes: nodejs#22810
@targos
Copy link
Member

targos commented Apr 23, 2019

Backport: #27358

BethGriggs pushed a commit that referenced this issue Sep 19, 2019
Original commit message:

    [turbofan] Fix NumberFloor typing.

    Bug: chromium:841117
    Change-Id: I1e83dfc82f87d0b49d3cca96290ae1d738e37d20
    Reviewed-on: https://chromium-review.googlesource.com/1051228
    Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
    Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#53083}

Refs: v8/v8@d520ebb
Fixes: #22810

PR-URL: #27358
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Refael Ackermann (רפאל פלחי) <refack@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com>
@BridgeAR
Copy link
Member

BridgeAR commented Jan 2, 2020

This was fixed in v8.16.2 by 37e24b1

@BridgeAR BridgeAR closed this as completed Jan 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug Issues with confirmed bugs. v8 engine Issues and PRs related to the V8 dependency.
Projects
None yet
Development

No branches or pull requests

9 participants