Closed Bug 927430 Opened 11 years ago Closed 9 years ago

Add an analysis step to detect is-NaN testing using |x != x| (or is-not-NaN using |x == x|)

Categories

(Developer Infrastructure :: Source Code Analysis, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED
mozilla38

People

(Reporter: Waldo, Assigned: ehsan.akhgari)

References

(Depends on 1 open bug)

Details

Attachments

(1 file)

Various compilers historically have had problems with testing a floating point value for NaN using what you'd expect would work given IEEE-754.  We should break the build, warn, complain, whatever, and tell people to use mozilla::IsNaN instead (the only thing we're aware of that always, correctly, works).
Can you please rephrase what the analysis here should check for more clearly?
Flags: needinfo?(jwalden+bmo)
I would imagine that the check should be for boolean expressions of the form x != x, where x is of type float, double, or long double.
Oh, ok, that's super easy!  :-)
So there is this code <http://dxr.mozilla.org/mozilla-central/source/gfx/skia/trunk/include/core/SkScalar.h#41> in skia which this analysis catches.  George, can we keep a local patch applied on top of skia to make this function return mozilla::IsNaN() instead?
Flags: needinfo?(gwright)
Depends on: 1111786
Comment 2 and comment 3 are exactly right.  :-)
Flags: needinfo?(jwalden+bmo)
...actually, wait, comment 2 is not exactly right.  There's also the inverse case: x == x where x is float, double, or long double, which should be replaced with !SkScalarIsNaN(x).  SkScalarIsFinite several lines below SkScalarIsNaN's definition has such an instance.  (In the specific case of SkScalarIsFinite, the body there could be replaced with a call to mozilla::IsFinite, for what it's worth.)
Summary: Add an analysis step to detect is-NaN testing using |x != x| → Add an analysis step to detect is-NaN testing using |x != x| (or is-not-NaN using |x == x|)
(In reply to Jeff Walden [:Waldo] (remove +bmo to email) from comment #6)
> ...actually, wait, comment 2 is not exactly right.  There's also the inverse
> case: x == x where x is float, double, or long double

Yes, my analysis catches it as well! :-)  Waiting for George before I attach my patch here.
Depends on: 1114348
Depends on: 1114349
Depends on: 1114351
Not forgotten about this. Just wondering how the best way to deal with this is. I really don't like the idea of keeping local patches applied.

Is it possible to upstream our IsNan implementation?
Flags: needinfo?(gwright)
(In reply to George Wright (:gw280) from comment #8)
> Is it possible to upstream our IsNan implementation?

I'm not sure if the upstream project would be interested...  If you can please check with them, I would be happy to write something based on http://dxr.mozilla.org/mozilla-central/source/mfbt/FloatingPoint.h.

Another possible solution, assuming the upstream project is OK with it, is to check in some Mozilla specific code into skia, roughly like this:

static inline bool SkScalarIsNaN(float x) {
#ifdef MOZILLA_CLIENT
  return mozilla::IsNaN(x);
#else
  return x != x;
#endif
}

which option do you think would be more viable?
Flags: needinfo?(gwright)
I think in general they are opposed to having ifdef blocks specifically for various platforms if they can avoid it. If the new IsNaN code is demonstrably better than theirs then my experience has shown that they'll generally take it.
Flags: needinfo?(gwright)
At this point, I don't think that's worth spending time on.  We should just white-list SkScalar.h and move on with our lives.
Assignee: nobody → ehsan
Waldo, do you have any details on the problems? It would be nice to document them in this change.
Flags: needinfo?(jwalden+bmo)
Attachment #8550970 - Flags: review?(jmuizelaar) → review+
Depends on: 1123356
https://hg.mozilla.org/mozilla-central/rev/bd9efbbfa8e6
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla38
(In reply to Jeff Muizelaar [:jrmuizel] from comment #13)
> Waldo, do you have any details on the problems? It would be nice to document
> them in this change.

The failures were either miscompiled code or compile errors, on MSVC and gcc both at the time.  Compiling with PGO enabled typically exacerbated these problems, or made them occur only in particular places, or other mayhem.

Generally there seems to be a very long trail of tears concerning how compilers have compiled floating point comparisons.  A brief survey of the field reveals bug 653056, bug 653777, <http://hg.mozilla.org/mozilla-central/rev/a1ab5a4ed1f3>, bug 654664, bug 640494 comment 39, bug 859892 comment 11, bug 977538, bug 435442 comment 58, and probably others as relevant instances of problems performing floating point comparisons -- most (but not all) of them against NaN.  Granted, most of those are older and in an era of somewhat older compilers -- but generally I'm not sure there's enough detail recorded to be much sure of when the affected compilers may have become unsupported, if indeed all of them even were.

Anyway.  That's not really the sort of braindump I'd want to put in a comment in code, unfortunately, with it being so fuzzy.  :-(  I'd leave it as something along the lines of there having been compiler bugs in these regards in the past, directing to this bug and perhaps this comment for the inchoate research.
Flags: needinfo?(jwalden+bmo)
I see this analysis only works if the locations being compared are exactly the same lvalue.  I don't know how many more places it'd detect, but it might be worth a quick elaboration to detect structurally equivalent expressions -- that is, say, methodReturningFloat() != methodReturningFloat(), or obj->prop() != obj->prop() or so -- that are compared in this manner, but haven't been CSE'd by the human author.  I have memories of having seen such comparisons before and fixed them to store into a local, then do the comparison using that (or to use the mfbt methods), and it wouldn't surprise me if there were more such places in our tree.
(In reply to Jeff Walden [:Waldo] (remove +bmo to email) from comment #17)
> I see this analysis only works if the locations being compared are exactly
> the same lvalue.  I don't know how many more places it'd detect, but it
> might be worth a quick elaboration to detect structurally equivalent
> expressions -- that is, say, methodReturningFloat() !=
> methodReturningFloat(), or obj->prop() != obj->prop() or so -- that are
> compared in this manner, but haven't been CSE'd by the human author.  I have
> memories of having seen such comparisons before and fixed them to store into
> a local, then do the comparison using that (or to use the mfbt methods), and
> it wouldn't surprise me if there were more such places in our tree.

Can you please file some bugs on these so that I don't forget to write the analysis?  I think they're relatively easy to detect.
Depends on: 1126489
Product: Core → Firefox Build System
Product: Firefox Build System → Developer Infrastructure
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: