mapbox / mapnik-vector-tile

Mapnik implemention of Mapbox Vector Tile specification
BSD 3-Clause "New" or "Revised" License
553 stars 117 forks source link

Exception when running AddPath #111

Closed flippmoke closed 9 years ago

flippmoke commented 9 years ago
Program terminated with signal SIGABRT, Aborted.
#0  0x00007fd0cc3a4cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007fd0cc3a4cc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007fd0cc3a80d8 in __GI_abort () at abort.c:89
#2  0x00007fd0ccecd6b5 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007fd0ccecb836 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007fd0ccecb863 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007fd0ccecbaf6 in __cxa_rethrow () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007fd0c7084b60 in ClipperLib::ClipperBase::AddPath(mapnik::geometry::line_string<long> const&, ClipperLib::PolyType, bool) () from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/libmapnik.so
#7  0x00007fd0c7c7d5ad in mapnik::vector_tile_impl::encoder_visitor<mapnik::vector_tile_impl::backend_pbf>::operator()(mapnik::geometry::polygon<long>&) ()
   from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/mapnik.node
#8  0x00007fd0c7c8dd32 in mapnik::vector_tile_impl::simplify_visitor<mapnik::vector_tile_impl::backend_pbf>::operator()(mapnik::geometry::polygon<long> const&) ()
   from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/mapnik.node
#9  0x00007fd0c7c7c4fd in mapnik::vector_tile_impl::processor<mapnik::vector_tile_impl::backend_pbf>::handle_geometry(mapnik::feature_impl const&, mapnik::util::variant<mapnik::geometry::geometry_empty, mapnik::geometry::point<double>, mapnik::geometry::line_string<double>, mapnik::geometry::polygon<double>, mapnik::geometry::multi_point<double>, mapnik::geometry::multi_line_string<double>, mapnik::geometry::multi_polygon<double>, mapnik::util::recursive_wrapper<mapnik::geometry::geometry_collection<double> > > const&, mapnik::proj_transform const&, mapnik::box2d<double> const&) ()
   from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/mapnik.node
#10 0x00007fd0c7c7b22a in mapnik::vector_tile_impl::processor<mapnik::vector_tile_impl::backend_pbf>::apply_to_layer(mapnik::layer const&, mapnik::projection const&, double, double, unsigned int, unsigned int, mapnik::box2d<double> const&, int) () from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/mapnik.node
#11 0x00007fd0c7c79731 in mapnik::vector_tile_impl::processor<mapnik::vector_tile_impl::backend_pbf>::apply(double)
    () from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/mapnik.node
#12 0x00007fd0c7c78255 in Map::EIO_RenderVectorTile(uv_work_s*) ()
   from /usr/local/src/service-worker/node_modules/mapnik/lib/binding/node-v11-linux-x64/mapnik.node
#13 0x000000000099c6f0 in worker (arg=<optimized out>) at ../deps/uv/src/unix/threadpool.c:74

Revealed a coredump that was uncaught in AddPath. More then likely it is due to:

Either https://github.com/mapnik/mapnik/blob/master/deps/clipper/src/clipper.cpp#L889 or https://github.com/mapnik/mapnik/blob/master/deps/clipper/src/clipper.cpp#L1040 or https://github.com/mapnik/mapnik/blob/master/deps/clipper/src/clipper.cpp#L1069 as the callstack doesn't show it getting any deeper.

springmeyer commented 9 years ago

TODO:

springmeyer commented 9 years ago

Above commits will ensure this exception is handled and does not abort.

How coordinates are getting through - that are outside the valid range of clipper - is still a mystery. All we know is that this occurred at z15. We don't know what kind of geometry triggered this.

One thought was that doubles were overflowing here however that is very unlikely the case. Clipper's hirange value of 0x3FFFFFFFFFFFFFFFLL or 4611686018427387903 is half the size of std::numeric_limits<std::int64_t>::max(). So we don't need an int64 overflow to trigger a value greater than hirange and an exception in ClipperLib::RangeTest.

springmeyer commented 9 years ago

Based on 1fba0d2 it does not look feasible for vector_tile_strategy alone to produce values greater than hirange at z15 even for a geometry that spans the world.

The only way I could trigger values beyond hirange was with an unrealistic scaling factor that is absurdly big (1000000000000.0). Even though that test is unrealistic I left it in - if it ever changes behavior we'll want to know.

So, I think the best way forward is to try to isolate a geometry next time this happens /cc @MateoV. For now I'll close this ticket but will re-open if we find a way to replicate.

springmeyer commented 9 years ago

For future debugging:

diff --git a/src/vector_tile_strategy.hpp b/src/vector_tile_strategy.hpp
index 1f8c045..fd9d030 100644
--- a/src/vector_tile_strategy.hpp
+++ b/src/vector_tile_strategy.hpp
@@ -64,6 +64,16 @@ struct vector_tile_strategy
         y = y * scaling_;
         x = std::round(x);
         y = std::round(y);
+#if defined(DEBUG)
+        if (x >= 0x3FFFFFFFFFFFFFFFLL || x <= -0x3FFFFFFFFFFFFFFFLL)
+        {
+            std::clog << std::fixed << " x out of bounds: " << x << "\n";
+        }
+        if (y >= 0x3FFFFFFFFFFFFFFFLL || y <= -0x3FFFFFFFFFFFFFFFLL)
+        {
+            std::clog << std::fixed << " y out of bounds: " << y << "\n";
+        }
+#endif
         boost::geometry::set<0>(p2, static_cast<p2_type>(x));
         boost::geometry::set<1>(p2, static_cast<p2_type>(y));
         return true;
springmeyer commented 9 years ago

How coordinates are getting through - that are outside the valid range of clipper - is still a mystery.

Mystery solved: pj_transform may set x/y to HUGE_VAL while returning no error. This triggers this bug: https://github.com/mapbox/mapnik-vector-tile/issues/116#issuecomment-110964474

springmeyer commented 9 years ago

How coordinates are getting through - that are outside the valid range of clipper - is still a mystery.

Mystery solved: pj_transform may set x/y to HUGE_VAL while returning no error. This triggers this bug: #116 (comment)

Now with the help of @MateoV - we've isolated a testcase for another way this can happen. Which is an extremely invalid coordinate which cannot fit within a 64 bit integer after being scaled to integer space. Will track at #120