geos icon indicating copy to clipboard operation
geos copied to clipboard

Unit test unit-geom-Envelope fails on FreeBSD 14.1 (clang vs gcc)

Open diizzyy opened this issue 1 year ago • 14 comments

Hi,

One unit test fails on FreeBSD

183/494 Testing: unit-geom-Envelope
183/494 Test: unit-geom-Envelope
Command: "/usr/ports/graphics/geos/work/.build/bin/test_geos_unit" "geos::geom::Envelope"
Directory: /usr/ports/graphics/geos/work/.build/tests/unit
"unit-geom-Envelope" start time: Dec 07 12:21 CET
Output:
----------------------------------------------------------
===============================
  GEOS Unit Test Suite
===============================

geos::geom::Envelope: .....[6=F].......[14=F]......

---> group: geos::geom::Envelope, test: test<6>
     problem: assertion failed
     failed assertion: `FE_INVALID raised`

---> group: geos::geom::Envelope, test: test<14>
     problem: assertion failed
     failed assertion: `FE_INVALID raised`

tests summary: failures:2 ok:18
<end of output>
Test time =   0.02 sec
----------------------------------------------------------
Test Failed.
"unit-geom-Envelope" end time: Dec 07 12:21 CET
"unit-geom-Envelope" time elapsed: 00:00:00
----------------------------------------------------------

OS: FreeBSD 14.1 (amd64) Version: 3.13.0 and latest main (dd0fdc5 Compiler: Clang 18.1.5 CMake: 3.31.0

Edit: All tests passes with GCC 13.3.0 but it would be nice if Clang also passed Also fails using Clang 15.0.7 Passes if -ffp-model=strict is added to CXXFLAGS https://clang.llvm.org/docs/UsersManual.html#controlling-floating-point-behavior

diizzyy avatar Dec 07 '24 11:12 diizzyy

Friendly ping

diizzyy avatar Mar 04 '25 19:03 diizzyy

Patches accepted! These things are obscure and since I do not have a FreeBSD system lying around to test it on, it is best to wait for someone with the system in question to fix it.

pramsey avatar Mar 04 '25 19:03 pramsey

I'm going to guess it's not a FreeBSD thing but rather clang(llvm) vs gcc, unfortunately I don't have a Linux box to verify on.

diizzyy avatar Mar 04 '25 19:03 diizzyy

We test many versions of gcc and clang on Linux in our CI and aren't seeing this.

pramsey avatar Mar 04 '25 19:03 pramsey

It's showing on our FreeBSD ci - -

FreeBSD bessie 14.1-RELEASE FreeBSD 14.1-RELEASE releng/14.1-n267679-10e31f0946d8 GENERIC amd64

FreeBSD clang version 18.1.5 (https://github.com/llvm/llvm-project.git llvmorg-18.1.5-0-g617a15a9eac9) Target: x86_64-unknown-freebsd14.1

robe2 avatar Mar 04 '25 23:03 robe2

@robe2 @pramsey I can take a look. I know that Clang 18.x raises many compiler bugs/errors (like gcc 15, some warnings become errors,etc).

@robe2 btw, can you update FreeBSD to 14.2, please?

lbartoletti avatar Mar 05 '25 06:03 lbartoletti

I can confirm a problem with the test on FreeBSD and clang (@diizzyy tested on 14.2-RELEASE clang 15 to 19 (and 15.0-CURRENT clang19) vs 14.2-RELEASE gcc 14 and 15)

At contrary to @diizzyy, on my computer, only test 6 fails.

Never mind, the problem seems at https://github.com/libgeos/geos/blob/c1a3d838ced34c29f2d4ba9982dbde31f79b2a05/tests/unit/geom/EnvelopeTest.cpp#L75 and more exactly this line: https://github.com/libgeos/geos/blob/c1a3d838ced34c29f2d4ba9982dbde31f79b2a05/tests/unit/geom/EnvelopeTest.cpp#L78

I think that the problem is with the empty Enveloppe.

If you move tests inside the if (!e1.isNull()), it hides the assertion :

    static void
    check_intersects(const Envelope& e1, const CoordinateXY& q, bool expected)
    {
        if (!e1.isNull()) {
            ensure_equals(e1.intersects(q), expected);
            ensure_equals(e1.intersects(q.x, q.y), expected);
            ensure_equals(e1.contains(q), expected);
            ensure_equals(e1.contains(q.x, q.y), expected);
            ensure_equals(e1.covers(&q), expected);
            ensure_equals(e1.covers(q.x, q.y), expected);
      
            CoordinateXY p0{e1.getMinX(), e1.getMinY()};
            CoordinateXY p1{e1.getMaxX(), e1.getMaxY()};
            ensure_equals(Envelope::intersects(p0, p1, q), expected);
        }
    }

    static void
    ensure_no_fp_except()
    {
        ensure("FE_DIVBYZERO raised", !std::fetestexcept(FE_DIVBYZERO));
        //ensure("FE_INEXACT raised", !std::fetestexcept(FE_INEXACT));
        ensure("FE_INVALID raised", !std::fetestexcept(FE_INVALID));
        ensure("FE_OVERFLOW raised", !std::fetestexcept(FE_OVERFLOW));
        ensure("FE_UNDERFLOW raised", !std::fetestexcept(FE_UNDERFLOW));
    }

But, I don't understand, why this patch does not fix the FE_INVALID assert: e1.intersects* are fixed but not covers (contains uses covers)

geos_enveloppe.txt

lbartoletti avatar Mar 17 '25 09:03 lbartoletti

Thanks @lbartoletti , this is helpful. It makes sense that the exception would be raised from e1.intersects(q.x, q.y). Looking at that overload I can see that it uses comparison operators that will raise this exception with nan arguments.

Could you please try changing line 60 of Envelope.cpp from

double envminx = (a.x < b.x) ? a.x : b.x;

to

double envminx = std::isless(a.x, b.x) ? a.x : b.x;

and so on for the other comparisons in this method?

dbaston avatar Mar 17 '25 11:03 dbaston

@dbaston doesn't resolve the issue :/

Actual situation, individually tested:

 ensure_equals(e1.intersects(q), expected); //fails                                                                                                                                                                                                                                                                                           
 ensure_equals(e1.intersects(q.x, q.y), expected); // fails                                                                                                                                                                                                                                                                                   
 ensure_equals(e1.contains(q), expected); //fails                                                                                                                                                                                                                                                                                             
 ensure_equals(e1.contains(q.x, q.y), expected); //fails                                                                                                                                                                                                                                                                                      
 ensure_equals(e1.covers(&q), expected); // fails                                                                                                                                                                                                                                                                                             
 ensure_equals(e1.covers(q.x, q.y), expected); // fails  

With my geos_enveloppe_v2.txt patch

(false if enveloppe isNull, or coordinate(s) is/are null, or double is nan):

ensure_equals(e1.intersects(q), expected); // OK                                                                                                                                                                                                                                                                                             
ensure_equals(e1.intersects(q.x, q.y), expected); // fails                                                                                                                                                                                                                                                                                   
ensure_equals(e1.contains(q), expected); //fails                                                                                                                                                                                                                                                                                             
ensure_equals(e1.contains(q.x, q.y), expected); //fails                                                                                                                                                                                                                                                                                      
ensure_equals(e1.covers(&q), expected); // fails                                                                                                                                                                                                                                                                                             
ensure_equals(e1.covers(q.x, q.y), expected); // fails 

meh.... Moreover, it's ok with:

    static void
    check_intersects(const Envelope& e1, const CoordinateXY& q, bool expected)
    {
        if (!e1.isNull()) {
            ensure_equals(e1.intersects(q), expected);
            ensure_equals(e1.intersects(q.x, q.y), expected);
            ensure_equals(e1.contains(q), expected);
            ensure_equals(e1.contains(q.x, q.y), expected);
            ensure_equals(e1.covers(&q), expected);
            ensure_equals(e1.covers(q.x, q.y), expected);
      
            CoordinateXY p0{e1.getMinX(), e1.getMinY()};
            CoordinateXY p1{e1.getMaxX(), e1.getMaxY()};
            ensure_equals(Envelope::intersects(p0, p1, q), expected);
        }
    }

lbartoletti avatar Mar 17 '25 15:03 lbartoletti

@lbartoletti

I can confirm a problem with the test on FreeBSD and clang (@diizzyy tested on 14.2-RELEASE clang 15 to 19 (and 15.0-CURRENT clang19) vs 14.2-RELEASE gcc 14 and 15)

At contrary to @diizzyy, on my computer, only test 6 fails.

I only get one if I unset CPUTYPE?=znver4 in /etc/make.conf, also able to reproduce it on my laptop which uses CPUTYPE?=tigerlake (two vs one failures), CPUTYPE translates to --march= in this case

This is what we have in ports https://cgit.freebsd.org/ports/commit/graphics/geos/files/patch-CMakeLists.txt?id=53d2b997aba6f272d3f78e504e3c1911a6ff5b15

Best regards, Daniel

diizzyy avatar Mar 17 '25 17:03 diizzyy

@robe2 @pramsey I can take a look. I know that Clang 18.x raises many compiler bugs/errors (like gcc 15, some warnings become errors,etc).

@robe2 btw, can you update FreeBSD to 14.2, please?

@lbartoletti sorry missed this note. I'll update to latest FreeBSD in a bit.

robe2 avatar Jul 05 '25 22:07 robe2

You probably want to go for 14.3 as 14.2 is EoL in September

diizzyy avatar Jul 06 '25 20:07 diizzyy

@robe2 @pramsey I can take a look. I know that Clang 18.x raises many compiler bugs/errors (like gcc 15, some warnings become errors,etc).

@robe2 btw, can you update FreeBSD to 14.2, please?

okay updated bessie to freebsd 14.2

robe2 avatar Jul 07 '25 14:07 robe2

You probably want to go for 14.3 as 14.2 is EoL in September Okay I'll upgrade again later today.

robe2 avatar Jul 07 '25 14:07 robe2