[wfs] Fix leak reading geometries

QgsWkbPtr does NOT take ownership of the data, port to QByteArray instead
This commit is contained in:
Nyall Dawson 2025-02-17 13:11:27 +10:00
parent 76c767fe15
commit 3a893ace97
No known key found for this signature in database
GPG Key ID: 4C61673F0BF197FC
2 changed files with 30 additions and 39 deletions

View File

@ -797,21 +797,21 @@ void QgsGmlStreamingParser::startElement( const XML_Char *el, const XML_Char **a
localNameLen == static_cast<int>( strlen( "Polygon" ) ) && memcmp( pszLocalName, "Polygon", localNameLen ) == 0 )
{
isGeom = true;
mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
mCurrentWKBFragments.push_back( QList<QByteArray>() );
}
else if ( !mAttributeValIsNested && isGMLNS && LOCALNAME_EQUALS( "MultiPoint" ) )
{
isGeom = true;
mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
//we need one nested list for intermediate WKB
mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
mCurrentWKBFragments.push_back( QList<QByteArray>() );
}
else if ( !mAttributeValIsNested && isGMLNS && ( LOCALNAME_EQUALS( "MultiLineString" ) || LOCALNAME_EQUALS( "MultiCurve" ) ) )
{
isGeom = true;
mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
//we need one nested list for intermediate WKB
mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
mCurrentWKBFragments.push_back( QList<QByteArray>() );
}
else if ( !mAttributeValIsNested && isGMLNS && ( LOCALNAME_EQUALS( "MultiPolygon" ) || LOCALNAME_EQUALS( "MultiSurface" ) ) )
{
@ -1241,9 +1241,9 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
if ( mCurrentWKB.size() > 0 )
{
QgsGeometry g;
g.fromWkb( mCurrentWKB, mCurrentWKB.size() );
g.fromWkb( mCurrentWKB );
mCurrentFeature->setGeometry( g );
mCurrentWKB = QgsWkbPtr( nullptr, 0 );
mCurrentWKB = QByteArray();
}
else if ( !mCurrentExtent.isEmpty() )
{
@ -1292,7 +1292,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
}
else //multipoint, add WKB as fragment
{
QgsWkbPtr wkbPtr( nullptr, 0 );
QByteArray wkbPtr;
if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
{
//error
@ -1304,7 +1304,6 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
else
{
QgsDebugError( QStringLiteral( "No wkb fragments" ) );
delete [] wkbPtr;
}
}
}
@ -1332,7 +1331,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
}
else //multiline, add WKB as fragment
{
QgsWkbPtr wkbPtr( nullptr, 0 );
QByteArray wkbPtr;
if ( getLineWKB( wkbPtr, pointList ) != 0 )
{
//error
@ -1344,7 +1343,6 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
else
{
QgsDebugError( QStringLiteral( "no wkb fragments" ) );
delete [] wkbPtr;
}
}
}
@ -1357,7 +1355,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
//error
}
QgsWkbPtr wkbPtr( nullptr, 0 );
QByteArray wkbPtr;
if ( getRingWKB( wkbPtr, pointList ) != 0 )
{
//error
@ -1369,7 +1367,6 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
}
else
{
delete[] wkbPtr;
QgsDebugError( QStringLiteral( "no wkb fragments" ) );
}
}
@ -1661,10 +1658,10 @@ int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points, const QS
return 1;
}
int QgsGmlStreamingParser::getPointWKB( QgsWkbPtr &wkbPtr, const QgsPointXY &point ) const
int QgsGmlStreamingParser::getPointWKB( QByteArray &wkbPtr, const QgsPointXY &point ) const
{
const int wkbSize = 1 + sizeof( int ) + 2 * sizeof( double );
wkbPtr = QgsWkbPtr( new unsigned char[wkbSize], wkbSize );
wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
QgsWkbPtr fillPtr( wkbPtr );
fillPtr << mEndian << Qgis::WkbType::Point << point.x() << point.y();
@ -1672,10 +1669,10 @@ int QgsGmlStreamingParser::getPointWKB( QgsWkbPtr &wkbPtr, const QgsPointXY &poi
return 0;
}
int QgsGmlStreamingParser::getLineWKB( QgsWkbPtr &wkbPtr, const QList<QgsPointXY> &lineCoordinates ) const
int QgsGmlStreamingParser::getLineWKB( QByteArray &wkbPtr, const QList<QgsPointXY> &lineCoordinates ) const
{
const int wkbSize = 1 + 2 * sizeof( int ) + lineCoordinates.size() * 2 * sizeof( double );
wkbPtr = QgsWkbPtr( new unsigned char[wkbSize], wkbSize );
wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
QgsWkbPtr fillPtr( wkbPtr );
@ -1690,10 +1687,10 @@ int QgsGmlStreamingParser::getLineWKB( QgsWkbPtr &wkbPtr, const QList<QgsPointXY
return 0;
}
int QgsGmlStreamingParser::getRingWKB( QgsWkbPtr &wkbPtr, const QList<QgsPointXY> &ringCoordinates ) const
int QgsGmlStreamingParser::getRingWKB( QByteArray &wkbPtr, const QList<QgsPointXY> &ringCoordinates ) const
{
const int wkbSize = sizeof( int ) + ringCoordinates.size() * 2 * sizeof( double );
wkbPtr = QgsWkbPtr( new unsigned char[wkbSize], wkbSize );
wkbPtr = QByteArray( wkbSize, Qt::Uninitialized );
QgsWkbPtr fillPtr( wkbPtr );
@ -1711,19 +1708,18 @@ int QgsGmlStreamingParser::getRingWKB( QgsWkbPtr &wkbPtr, const QList<QgsPointXY
int QgsGmlStreamingParser::createMultiLineFromFragments()
{
const int size = 1 + 2 * sizeof( int ) + totalWKBFragmentSize();
mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
mCurrentWKB = QByteArray( size, Qt::Uninitialized );
QgsWkbPtr wkbPtr( mCurrentWKB );
wkbPtr << mEndian << Qgis::WkbType::MultiLineString << mCurrentWKBFragments.constBegin()->size();
//copy (and delete) all the wkb fragments
QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
{
memcpy( wkbPtr, *wkbIt, wkbIt->size() );
wkbPtr += wkbIt->size();
delete[] *wkbIt;
}
mCurrentWKBFragments.clear();
@ -1734,17 +1730,16 @@ int QgsGmlStreamingParser::createMultiLineFromFragments()
int QgsGmlStreamingParser::createMultiPointFromFragments()
{
const int size = 1 + 2 * sizeof( int ) + totalWKBFragmentSize();
mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
mCurrentWKB = QByteArray( size, Qt::Uninitialized );
QgsWkbPtr wkbPtr( mCurrentWKB );
wkbPtr << mEndian << Qgis::WkbType::MultiPoint << mCurrentWKBFragments.constBegin()->size();
QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
{
memcpy( wkbPtr, *wkbIt, wkbIt->size() );
wkbPtr += wkbIt->size();
delete[] *wkbIt;
}
mCurrentWKBFragments.clear();
@ -1756,17 +1751,16 @@ int QgsGmlStreamingParser::createMultiPointFromFragments()
int QgsGmlStreamingParser::createPolygonFromFragments()
{
const int size = 1 + 2 * sizeof( int ) + totalWKBFragmentSize();
mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
mCurrentWKB = QByteArray( size, Qt::Uninitialized );
QgsWkbPtr wkbPtr( mCurrentWKB );
wkbPtr << mEndian << Qgis::WkbType::Polygon << mCurrentWKBFragments.constBegin()->size();
QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
auto wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
{
memcpy( wkbPtr, *wkbIt, wkbIt->size() );
wkbPtr += wkbIt->size();
delete[] *wkbIt;
}
mCurrentWKBFragments.clear();
@ -1781,25 +1775,24 @@ int QgsGmlStreamingParser::createMultiPolygonFromFragments()
size += totalWKBFragmentSize();
size += mCurrentWKBFragments.size() * ( 1 + 2 * sizeof( int ) ); //fragments are just the rings
mCurrentWKB = QgsWkbPtr( new unsigned char[size], size );
mCurrentWKB = QByteArray( size, Qt::Uninitialized );
QgsWkbPtr wkbPtr( mCurrentWKB );
wkbPtr << ( char ) mEndian << Qgis::WkbType::MultiPolygon << mCurrentWKBFragments.size();
//have outer and inner iterators
QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
auto outerWkbIt = mCurrentWKBFragments.constBegin();
for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
{
//new polygon
wkbPtr << ( char ) mEndian << Qgis::WkbType::Polygon << outerWkbIt->size();
QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
auto innerWkbIt = outerWkbIt->constBegin();
for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
{
memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
wkbPtr += innerWkbIt->size();
delete[] *innerWkbIt;
}
}
@ -1811,11 +1804,9 @@ int QgsGmlStreamingParser::createMultiPolygonFromFragments()
int QgsGmlStreamingParser::totalWKBFragmentSize() const
{
int result = 0;
const auto constMCurrentWKBFragments = mCurrentWKBFragments;
for ( const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
for ( const QList<QByteArray> &list : std::as_const( mCurrentWKBFragments ) )
{
const auto constList = list;
for ( const QgsWkbPtr &i : constList )
for ( const QByteArray &i : list )
{
result += i.size();
}

View File

@ -244,9 +244,9 @@ class CORE_EXPORT QgsGmlStreamingParser
int pointsFromPosListString( QList<QgsPointXY> &points, const QString &coordString, int dimension ) const;
int pointsFromString( QList<QgsPointXY> &points, const QString &coordString ) const;
int getPointWKB( QgsWkbPtr &wkbPtr, const QgsPointXY & ) const;
int getLineWKB( QgsWkbPtr &wkbPtr, const QList<QgsPointXY> &lineCoordinates ) const;
int getRingWKB( QgsWkbPtr &wkbPtr, const QList<QgsPointXY> &ringCoordinates ) const;
int getPointWKB( QByteArray &wkbPtr, const QgsPointXY & ) const;
int getLineWKB( QByteArray &wkbPtr, const QList<QgsPointXY> &lineCoordinates ) const;
int getRingWKB( QByteArray &wkbPtr, const QList<QgsPointXY> &ringCoordinates ) const;
/**
* Creates a multiline from the information in mCurrentWKBFragments and
@ -318,7 +318,7 @@ class CORE_EXPORT QgsGmlStreamingParser
QString mCurrentFeatureId;
int mFeatureCount;
//! The total WKB for a feature
QgsWkbPtr mCurrentWKB;
QByteArray mCurrentWKB;
QgsRectangle mCurrentExtent;
bool mBoundedByNullFound;
@ -328,7 +328,7 @@ class CORE_EXPORT QgsGmlStreamingParser
* polygons, only one nested list is used. For multipolygons, both nested lists
* are used
*/
QList< QList<QgsWkbPtr> > mCurrentWKBFragments;
QList< QList< QByteArray > > mCurrentWKBFragments;
QString mAttributeName;
int mAttributeDepth = -1;
bool mAttributeValIsNested = false;