Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#4031 closed defect (fixed)

ST_CurveToLine with small tolerance sometimes causes invalid memory alloc request size

Reported by: kkgeodk Owned by: strk
Priority: medium Milestone: PostGIS 2.4.5
Component: postgis Version: 2.4.x
Keywords: ST_CurveToLine Cc:

Description

ST_CurveToLine([geometry], 0.01, 1, 1) causes ERROR: invalid memory alloc request size 1073741824

Same ERROR with:

ST_CurveToLine([geometry], 0.05, 1, 1)
ST_CurveToLine([geometry], 0.1, 1, 1)
ST_CurveToLine([geometry], 1, 1, 1)


With ST_CurveToLine([geometry], 32, 0, 1), this ERROR cannot be reproduced.

Shared memory segment in bytes has been increased. This did not solve our issue:

# Maximum size of a single shared memory segment in bytes
#kernel.shmmax = 33554432
kernel.shmmax = 3055017984


Find test data attached. object t_id= 1727145 seems to be the issue.

System:

Ubuntu 14.04.5 LTS
PostgreSQL 9.3
PostGIS 2.2 with ST_CurveToLine backport from https://github.com/strk/postgis/tree/svn-2.2-curve-to-line-extended

Attachments (2)

npl_export (5.8 KB ) - added by kkgeodk 6 years ago.
curve.png (10.9 KB ) - added by strk 6 years ago.

Download all attachments as: .zip

Change History (17)

by kkgeodk, 6 years ago

Attachment: npl_export added

comment:1 by strk, 6 years ago

The smaller error tolerance, the higher number of segments will be required to approximate the line. It may of course be too many. How do you suggest to deal with this ? Similar issue exists with ST_Segmentize (for example).

comment:2 by kkgeodk, 6 years ago

Setting ST_CurveToLine([geometry], 0.01, 1, 1) ist needed due to accuracy requirements of data (cadastral surveying). Optimizations / Fixes in memory allocation possible?

comment:3 by strk, 6 years ago

Possibly, you could look at the code and see if there's any over-aggressive memory allocation going on

comment:4 by robe, 6 years ago

Milestone: PostGIS 2.4.4PostGIS 2.5.0

comment:5 by strk, 6 years ago

So the input geometry is a CompoundCurve composed by 39 elements being alternating LineString and CircularString objects. Total length of CompoundCurve is about 180 units. Curves has mostly 3 control points and linestrings 2, with 2 exceptions being a LineString and a CircularString of 13 vertices each.

I confirm running ST_CurveToLine([geometry], 1, 1, 1) as of r16530 fails about invalid memory alloc.

The problem seems to be with the 15th arc, for which PostGIS seems to be unable to compute an angle:

DEBUG:  [lwstroke.c:lwarc_linearize:218] lwarc_linearize: maxDiff:1, radius:0.191861, halfAngle:nan, increment:nan (nan degrees)

comment:6 by strk, 6 years ago

Reduced testcase:

select ST_CurveToLine('CIRCULARSTRING
(2730145.49367034 1278364.50230843,
 2730145.54567269 1278364.69930594,
 2730145.59567509 1278364.89730345,
 2730145.59567514 1278364.90030341,
 2730145.59667517 1278364.90330337,
 2730145.64567761 1278365.10230086,
 2730145.6916793 1278365.30129822
)'::geometry, 1, 1, 1);

NOT requesting symmetric output quickly returns a result.

comment:7 by strk, 6 years ago

It looks like ST_CurveToLine is uninterruptible too, which is something we should look at (maybe in a separate ticket).

Smallest reduction (single-arc):

select ST_CurveToLine('CIRCULARSTRING
(
 2730145.59567509 1278364.89730345,
 2730145.59567514 1278364.90030341,
 2730145.59667517 1278364.90330337
)'::geometry, 1, 1, 1);

by strk, 6 years ago

Attachment: curve.png added

comment:8 by strk, 6 years ago

The innocent-looking arc…

comment:9 by strk, 6 years ago

Ok I know what's happening here. The arc radius is 0.191861, so the sagitta (max distance between arc and cord) can be at most .383722. We're doing the computation using a distance of 1 instead (the tolerance) which results in 1-tolerance/radius to give an invalid input value for acos. This should be fixed by limiting the used value to always be at most the max possible error (arc diameter).

comment:10 by strk, 6 years ago

In 16553:

Survive to big max deviation values passed to ST_CurveToLine

When using "max-deviation" tolerance type, passing a tolerance
bigger than twice the radius of any arc resulted in entering
an infinite loop, only limited by availability of RAM.

This commit fixes the bug by being careful in what's fed to
acos()…

Includes a unit test.
References #4031 for trunk (2.5.0dev) - to be backported

comment:11 by strk, 6 years ago

@kkgeodk can you confirm r16553 fixes the problem for you ? In the specific case you reported even 0.01 tolerance was too big for that specific arc in the set of curves (there was a very tiny curve in the set). The patch in r16553 would allow you to still use 0.01 (or even 1) as a max deviance w/out that ever being a problem against smaller curves.

Once confirmed, the patch should be backported to all supported branches.

comment:12 by strk, 6 years ago

by the way, the unguarded code was ported from QGIS, so this bug should still be present there. In case anyone wants to verify and file a ticket on that side too…

comment:13 by kkgeodk, 6 years ago

@kkgeodk can you confirm r16553 fixes the problem for you ?

Thank you, I was not able to reproduce the ERROR invalid memory alloc request size with r16553.

comment:14 by strk, 6 years ago

Resolution: fixed
Status: assignedclosed

In 16577:

Survive to big max deviation values passed to ST_CurveToLine

When using "max-deviation" tolerance type, passing a tolerance
bigger than twice the radius of any arc resulted in entering
an infinite loop, only limited by availability of RAM.

This commit fixes the bug by being careful in what's fed to
acos()…

Includes a unit test.
Closes #4031 in 2.4 branch (2.4.5dev)

comment:15 by strk, 6 years ago

Milestone: PostGIS 2.5.0PostGIS 2.4.5
Version: 2.2.x2.4.x

Thanks for testing, backported now to 2.4 branch too

Note: See TracTickets for help on using tickets.