#3579 closed defect (fixed)
Backend crash with mixed collections
Reported by: | pramsey | Owned by: | pramsey |
---|---|---|---|
Priority: | blocker | Milestone: | PostGIS 2.2.3 |
Component: | postgis | Version: | 2.2.x |
Keywords: | Cc: |
Description
When called with a collection that include empty sub-components, the back-end may crash
with params as ( select 11 :: float as sidewalk_offset, 1 :: float as epsilon ), road as ( -- L-shaped road, 10 m select 'SRID=3857;LINESTRING(10 0, 0 0, 0 10)' :: geometry as geom ), sidewalks as ( select ST_Collect( ST_OffsetCurve(geom, sidewalk_offset), ST_OffsetCurve(geom, -sidewalk_offset) ) geom from road, params ) select ST_Intersects(road.geom, sidewalks.geom), -- should be false ST_Intersects(ST_Buffer(road.geom, sidewalk_offset + epsilon), sidewalks.geom) -- should be true from road, sidewalks, params;
Originally reported on github at https://github.com/postgis/postgis/pull/105
Change History (10)
comment:1 by , 8 years ago
comment:5 by , 8 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:6 by , 8 years ago
Did you find out _what_ was crashing, exactly ? The fix seems to workaround a deeper bug, which would be good to fix. Was it in GEOS or in PostGIS ?
comment:7 by , 8 years ago
I never actually fired up the debugger, just confirmed that the fix worked and didn't regress.
comment:8 by , 8 years ago
Here's a stack-trace. Seems like a pretty common code path (geometry.intersects()). Is it possible we never exercised GEOS w/ collections containing a mixture of full/empty geometry before?
* thread #1: tid = 0x1a7a62, 0x000000010be7a09b libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(geos::geom::Coordinate const&, geos::geom::LineString const*) [inlined] geos::geom::Coordinate::equals2D(this=<unavailable>, other=0x0000000000000000) const + 5 at Coordinate.inl:52, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: 0x000000010be7a09b libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(geos::geom::Coordinate const&, geos::geom::LineString const*) [inlined] geos::geom::Coordinate::equals2D(this=<unavailable>, other=0x0000000000000000) const + 5 at Coordinate.inl:52 49 INLINE bool 50 Coordinate::equals2D(const Coordinate& other) const 51 { -> 52 if (x != other.x) return false; 53 if (y != other.y) return false; 54 return true; 55 } (lldb) bt * thread #1: tid = 0x1a7a62, 0x000000010be7a09b libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(geos::geom::Coordinate const&, geos::geom::LineString const*) [inlined] geos::geom::Coordinate::equals2D(this=<unavailable>, other=0x0000000000000000) const + 5 at Coordinate.inl:52, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) * frame #0: 0x000000010be7a09b libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(geos::geom::Coordinate const&, geos::geom::LineString const*) [inlined] geos::geom::Coordinate::equals2D(this=<unavailable>, other=0x0000000000000000) const + 5 at Coordinate.inl:52 frame #1: 0x000000010be7a096 libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(geos::geom::Coordinate const&, geos::geom::LineString const*) [inlined] geos::geom::operator==(b=0x0000000000000000) at Coordinate.inl:123 frame #2: 0x000000010be7a096 libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(this=<unavailable>, p=0x00007f9881e022e0, l=<unavailable>) + 54 at PointLocator.cpp:133 frame #3: 0x000000010be7a412 libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::computeLocation(this=0x00007fff5dba46f0, p=0x00007f9881e022e0, geom=<unavailable>) + 418 at PointLocator.cpp:82 frame #4: 0x000000010be7a026 libgeos-3.6.0dev.dylib`geos::algorithm::PointLocator::locate(this=0x00007fff5dba46f0, p=0x00007f9881e022e0, geom=0x00007f9881e01520) + 182 at PointLocator.cpp:55 frame #5: 0x000000010bef71f4 libgeos-3.6.0dev.dylib`geos::operation::relate::RelateComputer::labelIsolatedNodes() [inlined] geos::operation::relate::RelateComputer::labelIsolatedNode(targetIndex=1) + 31 at RelateComputer.cpp:508 frame #6: 0x000000010bef71d5 libgeos-3.6.0dev.dylib`geos::operation::relate::RelateComputer::labelIsolatedNodes(this=0x00007fff5dba4678) + 165 at RelateComputer.cpp:499 frame #7: 0x000000010bef69c6 libgeos-3.6.0dev.dylib`geos::operation::relate::RelateComputer::computeIM(this=0x00007fff5dba4678) + 374 at RelateComputer.cpp:162 frame #8: 0x000000010bef8276 libgeos-3.6.0dev.dylib`geos::operation::relate::RelateOp::relate(geos::geom::Geometry const*, geos::geom::Geometry const*) [inlined] geos::operation::relate::RelateOp::getIntersectionMatrix() + 8 at RelateOp.cpp:74 frame #9: 0x000000010bef826e libgeos-3.6.0dev.dylib`geos::operation::relate::RelateOp::relate(a=<unavailable>, b=<unavailable>) + 78 at RelateOp.cpp:42 frame #10: 0x000000010be83b0d libgeos-3.6.0dev.dylib`geos::geom::Geometry::intersects(this=0x00007f9881e017f0, g=0x00007f9881e01520) const + 333 at Geometry.cpp:344 frame #11: 0x000000010306d0b5 libgeos_c.1.dylib`::GEOSIntersects_r(extHandle=<unavailable>, g1=<unavailable>, g2=<unavailable>) + 53 at geos_ts_c.cpp:500 frame #12: 0x0000000102f6682c postgis-2.3.so`geos_intersects(fcinfo=0x00007f98830648a8) + 1628 at lwgeom_geos.c:2418 frame #13: 0x0000000102f69738 postgis-2.3.so`intersects(fcinfo=0x00007f98830648a8) + 40 at lwgeom_backend_api.c:173 frame #14: 0x00000001022bb29a postgres`ExecMakeFunctionResultNoSets(fcache=0x00007f9883064838, econtext=0x00007f988305b580, isNull="", isDone=0x0000000000000000) + 346 at execQual.c:2026 frame #15: 0x00000001022b4d47 postgres`ExecEvalFunc(fcache=0x00007f9883064838, econtext=0x00007f988305b580, isNull="", isDone=0x0000000000000000) + 199 at execQual.c:2417 frame #16: 0x00000001022b5d16 postgres`ExecEvalAnd(andExpr=0x00007f988305b678, econtext=0x00007f988305b580, isNull="", isDone=0x00007f98830689c0) + 134 at execQual.c:2831 frame #17: 0x00000001022ba0ef postgres`ExecTargetList(targetlist=0x00007f9883068960, econtext=0x00007f988305b580, values=0x00007f9883068820, isnull="", itemIsDone=0x00007f98830689c0, isDone=0x00007fff5dba4c84) + 175 at execQual.c:5307 frame #18: 0x00000001022ba005 postgres`ExecProject(projInfo=0x00007f9883068868, isDone=0x00007fff5dba4c84) + 741 at execQual.c:5522 frame #19: 0x00000001022d8084 postgres`ExecNestLoop(node=0x00007f988305b468) + 1140 at nodeNestloop.c:267 frame #20: 0x00000001022adeaa postgres`ExecProcNode(node=0x00007f988305b468) + 490 at execProcnode.c:449 frame #21: 0x00000001022a98d3 postgres`ExecutePlan(estate=0x00007f9883056438, planstate=0x00007f988305b468, operation=CMD_SELECT, sendTuples='\x01', numberTuples=0, direction=ForwardScanDirection, dest=0x00007f988304ac40) + 115 at execMain.c:1490 frame #22: 0x00000001022a97fa postgres`standard_ExecutorRun(queryDesc=0x00007f988302aa38, direction=ForwardScanDirection, count=0) + 490 at execMain.c:319 frame #23: 0x00000001022a960a postgres`ExecutorRun(queryDesc=0x00007f988302aa38, direction=ForwardScanDirection, count=0) + 74 at execMain.c:267 frame #24: 0x00000001024676a4 postgres`PortalRunSelect(portal=0x00007f9883044438, forward='\x01', count=0, dest=0x00007f988304ac40) + 308 at pquery.c:942 frame #25: 0x0000000102467087 postgres`PortalRun(portal=0x00007f9883044438, count=9223372036854775807, isTopLevel='\x01', dest=0x00007f988304ac40, altdest=0x00007f988304ac40, completionTag="") + 679 at pquery.c:786 frame #26: 0x0000000102462947 postgres`exec_simple_query(query_string="with\n params as (\n select\n 11 :: float as sidewalk_offset,\n 1 :: float as epsilon\n ),\n road as (\n\n select 'SRID=3857;LINESTRING(10 0, 0 0, 0 10)' :: geometry as geom\n ),\n sidewalks as (\n select ST_Collect(\n ST_OffsetCurve(geom, sidewalk_offset),\n ST_OffsetCurve(geom, -sidewalk_offset)\n ) geom\n from road, params\n )\nselect\n ST_Intersects(road.geom, sidewalks.geom),\n\n ST_Intersects(ST_Buffer(road.geom, sidewalk_offset + epsilon), sidewalks.geom) \nfrom road, sidewalks, params;") + 1239 at postgres.c:1072 frame #27: 0x0000000102461cb8 postgres`PostgresMain(argc=1, argv=0x00007f98820060d8, dbname="postgis23", username="pramsey") + 2856 at postgres.c:4079 frame #28: 0x00000001023ca585 postgres`BackendRun(port=0x00007f9881f00c80) + 693 at postmaster.c:4285 frame #29: 0x00000001023c97c8 postgres`BackendStartup(port=0x00007f9881f00c80) + 408 at postmaster.c:3948 frame #30: 0x00000001023c8985 postgres`ServerLoop + 597 at postmaster.c:1679 frame #31: 0x00000001023c6271 postgres`PostmasterMain(argc=3, argv=0x00007f9881c07220) + 5409 at postmaster.c:1287 frame #32: 0x0000000102305daa postgres`main(argc=3, argv=0x00007f9881c07220) + 746 at main.c:233 frame #33: 0x00007fff8454b5ad libdyld.dylib`start + 1
comment:10 by , 8 years ago
Based on the example provided, here's the minimal crasher, which could be tested in GEOS.
select st_intersects( 'LINESTRING(10 0, 0 0, 0 10)'::geometry, 'MULTILINESTRING((10 -1,-1 10),EMPTY)'::geometry )
Just having the collection-with-empty structure was not enough to induce a crash, the geometries had to overlap so that the overlay code was started up. Then things went boom.
Fixed in 2.2 at r14956