Ticket #86 (closed defect: fixed)

Opened 6 years ago

Last modified 3 years ago

Possible memory leaks caused by LineString constructor

Reported by: mloskot Owned by: strk
Priority: critical Milestone: 3.2.0
Component: Core Version: 2.2.3
Severity: Significant Keywords: imported,phpbugtracker
Cc:

Description (last modified by mloskot) (diff)

There is a high possibility that constructor of LineString? class will cause memory leaks.

Here is small snipped with current version of this ctor:

LineString::LineString(CoordinateSequence* newCoords, const GeometryFactory *factory)
   : Geometry(factory)
{
   if (newCoords==NULL) {
      points=factory->getCoordinateSequenceFactory()->create(NULL);
      return;
   }

   if (newCoords->getSize()==1) {
      throw util::IllegalArgumentException("point array must contain 0 or >1 elementsn");
   }

   // 'points' WILL LEAK WHEN EXCEPTION ABOVE IS THROWN
   points=newCoords; // <--- 1
}

Now, the small piece of code with how I create LineString? object in one of my test. This test tries to create one-point linestring intentionaly.

void test()
{
   // Single-element sequence of coordiantes
   CoordinateArraySequence* pseq = new CoordinateArraySequence();
   pseq->add(geos::geom::Coordinate(0, 0, 0));

   try
   {
      // Create incomplete linstring
      // 'ls' IS ASSUMED TO TAKE OWNERSHIP OF 'pseq' SEQUENCE
      geos::geom::LineString ls(pseq, &amp;factory_); // <--- [2]

      // WE EXPECT THE EXCEPTION
   }
   catch (geos::util::IllegalArgumentException const&amp; e)
   {
      // [3] <--- BUM! BUM! BUM!

      // [4] <--- REQUIRED TO AVOID BUM!
      delete pseq;

      std::cout << e.what() << std::endl;
   }
}

Now, the explanation:

1. New coordiante sequence is created with only one point

2. New linestringis created with one-point sequence that is expected to be invalid

3. LineString? ctor recognizes this sequence as invalid and throws IllegalArgumentException?

4. At this moment, the line 1 is not called, so the sequence previously created does not become a part of LineString? object and LineString::points member is left as null

5. When exception is thrown in line 3, the LineString? destructor is called but 'points' is null, so the sequence is not deallocated (BUM!)

6. Finally, sequnce 'pseq' leaks

7. To avoid the memory leaks, temporary solution is to deallocate it on the client side, when exception is catched, in line 4.

The main problem is that LineString? ctor does not promises (prepares LineString? object well) that all resources LineString? is responsible for will be deallocated by dctor in case of problems.

The simplest possible solution is to move line 1: points=newCoords; // <--- 1

to the beginning of the LineString::LineString?(). This won't be a problem if newCoords is null pointer, because further checks will do the job well. If newCoords is not a null pointer, then the sequence will be assigned to points member and in case of exception, LineString? destructor will deallocated it properly.

Change History

Changed 6 years ago by strk@…

  • resolution changed from none to fixed
Fixed using your suggested solution

Changed 6 years ago by mateusz@…

  • resolution changed from fixed to deferred
Unfortunately my simple solution does not solve the problem. LineString will still leak when coordinates sequence is of size = 1. This is because when ctor throws exception, destructor is never called, so 'points' sequence is not deallocated.

I'm preparing some deeper explanation with solution proposal. I'll send it on the mailing list first, subject "Exception-safety". So, please, refer to this post.

I changed status of this Bug Report to Reopened + Deferred.

Changed 5 years ago by

  • resolution changed from deferred to not a bug
  • version changed from 3.0.0 to 2.2.1
  • component changed from Core to SWIG
  • severity changed from Significant to Critical

Changed 5 years ago by

  • resolution changed from not a bug to duplicate
  • version changed from 2.2.1 to 1.1.1
  • component changed from SWIG to loader/dumper

Changed 5 years ago by pramsey@…

  • severity changed from Critical to Unassigned

Changed 5 years ago by

  • resolution changed from duplicate to none
  • version changed from 1.1.1 to 1.1.7
  • component changed from loader/dumper to build scripts

Changed 5 years ago by

  • resolution changed from none to not a bug
  • version changed from 1.1.7 to 3.0.0
  • component changed from build scripts to SWIG
  • severity changed from Unassigned to Significant

Changed 5 years ago by

  • resolution changed from not a bug to duplicate
  • version changed from 3.0.0 to 1.0.3
  • component changed from SWIG to Core
  • severity changed from Significant to Content

Changed 5 years ago by mateusz@…

I cleaned this bug from some spam. Looks like we're experiencing frequent spam attacks.

Changed 5 years ago by

  • version changed from 1.0.3 to 1.1.6
  • resolution changed from duplicate to not a bug

Changed 5 years ago by

  • resolution changed from not a bug to won't fix
  • version changed from 1.1.6 to 1.1.2
  • component changed from Core to loader/dumper

Changed 5 years ago by

  • resolution changed from won't fix to not a bug
  • version changed from 1.1.2 to 1.0.5
  • component changed from loader/dumper to Core
  • severity changed from Content to Feature Request

Changed 5 years ago by

  • version changed from 1.0.5 to 1.1.4
  • resolution changed from not a bug to duplicate
  • severity changed from Feature Request to Significant

Changed 5 years ago by

  • component changed from Core to loader/dumper

Changed 5 years ago by

  • version changed from 1.1.4 to 1.0.2
  • severity changed from Significant to Critical

Changed 5 years ago by

  • resolution changed from duplicate to not a bug
  • version changed from 1.0.2 to 1.2.1
  • component changed from loader/dumper to Core
  • severity changed from Critical to Idea

Changed 5 years ago by

  • version changed from 1.2.1 to 1.1.7
  • resolution changed from not a bug to fixed
  • severity changed from Idea to Significant

Changed 5 years ago by

  • version changed from 1.1.7 to head
  • resolution changed from fixed to works for me
  • severity changed from Significant to Annoyance

Changed 5 years ago by

  • resolution changed from works for me to none
  • version changed from head to 1.2.0
  • component changed from Core to build scripts
  • severity changed from Annoyance to Unassigned

Changed 4 years ago by mateusz@…

  • version changed from 1.2.0 to 2.2.3
  • component changed from build scripts to Build scripts
Removed spam from the comment.

Changed 4 years ago by mloskot

  • description modified (diff)
  • reporter changed from mateusz@… to mloskot

Changed 4 years ago by mloskot

  • description modified (diff)

Changed 4 years ago by mloskot

  • milestone imported deleted

Changed 4 years ago by mloskot

  • priority changed from 1 to critical
  • component changed from Build scripts to Core
  • severity changed from Unassigned to Significant

Changed 3 years ago by pramsey

  • milestone set to 3.2.0

Changed 3 years ago by pramsey

  • owner changed from to strk

Still an issue?

Changed 3 years ago by strk

  • status changed from new to assigned

Ever been ? Mat: do you have a testcase exploiting the leak ?

Changed 3 years ago by mloskot

I believe there is no need for a test case. The code I outline quoted clearly shows there is lack of use of RAII.

Changed 3 years ago by strk

I'm asking because I did try to create a LineString? with a CoordinateSequece? of size 1 and valgrind didn't give me the CoordinateSequence? as leaking. Instead it gave me some std::string leaks which seems unrelated (the message passed to the exception thrown)

Changed 3 years ago by mloskot

OK

Changed 3 years ago by strk

  • status changed from assigned to closed
  • resolution set to fixed

Well, I couldn't handle to reproduce and so I'll take for fixed.

Note: See TracTickets for help on using tickets.