-
Notifications
You must be signed in to change notification settings - Fork 802
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
Handle nan float cast overflow in PJ_robin.c and nad_intr.c #887
Conversation
I thought this was the preferred way to check for
But I get this from cppcheck:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change
indx.lam =
t.lam == t.lam && ct->del.lam == ct->del.lam
? (int)floor(t.lam /= ct->del.lam)
: 0;
to
t.lam /= ct->del.lam;
indx.lam = t.lam == t.lam ? (int)floor(t.lam) : 0;
Ditto for indx.phi. Then you get the intended side-effect of the
division and you also catch the catch where a NaN is generated with 0/0.
src/PJ_robin.c
Outdated
(void) P; | ||
|
||
i = (int)floor((dphi = fabs(lp.phi)) * C1); | ||
i = lp.phi == lp.phi ? (int)floor((dphi = fabs(lp.phi)) * C1) : -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this pattern commonly used and recognized? I find it quite unintuitive and will definitely not understand this the next time I stumble on this part of the code.
Would it be possible to create a well-named function that takes care of this? Like pj_avoid_nan_on_assignment()
(or something better...). Otherwise comments describing what's going on would be welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest adding an internal pj_is_nan() function to encapsulate NaN testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me. I've got no idea how to write such a function, but I agree that it would be a better way to go in these situations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just
int pj_is_nan(double x)
{
/* cppcheck-suppress duplicateExpression */
return x != x;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. pj_is_nan
would be less confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with that then.
@schwehr can you add that function to this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave it a go with the simplest possible implementation in pj_internal.c.
I avoided messing with isnan or other GCC custom craziness as seen here:
https://trac.osgeo.org/gdal/browser/trunk/gdal/port/cpl_port.h?rev=41149#L575
And I didn't patch other instances of x == x nan checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. We can add craziness when needed.
And I didn't patch other instances of x == x nan checks.
We can fix the rest as we come across them. Or if a master grepper want to search them out they can be done once and for all.
@cffk are you happy with the changes? |
A couple of comments... Non-urgent: The definition of
and similiarly is Urgent: surely the idiom
is dangerous? If BTW, surely assignments in arguments lists is a bad practice? |
Let me do one more cleanup iteration. I agree that the assignment inside is not a great idea. |
Good catch. That should be done, yes. If not done here a new issue should be added so we don't forget. |
I have to check if fabs of NaN is safe or not. |
Surely the standard says |
While I was pretty sure that fabs is just fine with NaN, it didn't hurt to check :) This passed UBSan in my testing env. #include <cmath>
#include <limits>
#include "testing/base/public/gunit.h"
namespace {
TEST(FabsTest, HandlesNan) {
constexpr double nan = std::numeric_limits<double>::quiet_NaN();
constexpr double inf = std::numeric_limits<double>::infinity();
EXPECT_TRUE(std::isnan(nan));
EXPECT_TRUE(std::isnan(-nan));
EXPECT_FALSE(std::isnan(inf));
EXPECT_FALSE(std::isnan(-inf));
EXPECT_TRUE(std::isnan(std::fabs(nan)));
EXPECT_TRUE(std::isnan(std::fabs(-nan)));
EXPECT_FALSE(std::isnan(std::fabs(inf)));
EXPECT_FALSE(std::isnan(std::fabs(-inf)));
}
} // namespace |
@schwehr Once you are happy with this, do you mind rebasing the commits into one for the addition of |
@kbevers Not having done that kind of rebase, can you point me at something that explains what you mean? |
Now that I look closer at your commits it might just be easier to reset all your commits ( Does that make sense? |
That does make sense. I will give it a go. |
Awesome. Normally I would just squash everything when merging, but since this is actually two separate things I think it is best handled as two commits. |
Uses the new pj_is_nan to avoid x == x checks. Removes an assignment from an arg list
3b8af6f
to
ec494f1
Compare
There are now 2 commits in the history. The mac osx test timed out before. Hopefully this time around that travis-ci target will complete and that the timeout was just a flake. |
Perfect. Thanks! The OS X test has been a bit flaky lately so don't worry about that. |
See #843
Found with autofuzz UndefinedBehaviorSanitizer (UBSan)