Commit 69603179 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix PVS-Studio warning: possible memory leaks in production code

Most of the leaks are hardly reproducible in normal circumstances. But
the one in PNG converter is huge. PNG converter also had an invalid null
pointer access, which didn't crash Krita only by a happy coincidence.

CCBUG:393431
parent 7be37e4a
......@@ -665,7 +665,7 @@ bool SvgParser::parseSymbol(const KoXmlElement &e)
if (id.isEmpty()) return false;
KoSvgSymbol *svgSymbol = new KoSvgSymbol();
QScopedPointer<KoSvgSymbol> svgSymbol(new KoSvgSymbol());
// ensure that the clip path is loaded in local coordinates system
m_context.pushGraphicsContext(e, false);
......@@ -674,24 +674,23 @@ bool SvgParser::parseSymbol(const KoXmlElement &e)
QString title = e.firstChildElement("title").toElement().text();
KoShape *symbolShape = parseGroup(e);
QScopedPointer<KoShape> symbolShape(parseGroup(e));
m_context.popGraphicsContext();
if (!symbolShape) return false;
svgSymbol->shape = symbolShape;
svgSymbol->shape = symbolShape.take();
svgSymbol->title = title;
svgSymbol->id = id;
if (title.isEmpty()) svgSymbol->title = id;
if (svgSymbol->shape->boundingRect() == QRectF(0.0, 0.0, 0.0, 0.0)) {
debugFlake << "Symbol" << id << "seems to be empty, discarding";
delete svgSymbol;
return false;
}
m_symbols << svgSymbol;
m_symbols << svgSymbol.take();
return true;
}
......@@ -1259,8 +1258,7 @@ KoShape* SvgParser::parseUse(const KoXmlElement &e, DeferredUseStore* deferredUs
const bool gotDef = m_context.hasDefinition(key);
if (gotDef) {
return resolveUse(e, key);
}
if (!gotDef && deferredUseStore) {
} else if (deferredUseStore) {
deferredUseStore->add(&e, key);
return 0;
}
......
......@@ -419,8 +419,8 @@ void KisInputManager::Private::addWheelShortcut(KisAbstractInputAction* action,
const QList<Qt::Key> &modifiers,
KisShortcutConfiguration::MouseWheelMovement wheelAction)
{
KisSingleActionShortcut *keyShortcut =
new KisSingleActionShortcut(action, index);
QScopedPointer<KisSingleActionShortcut> keyShortcut(
new KisSingleActionShortcut(action, index));
KisSingleActionShortcut::WheelAction a;
switch(wheelAction) {
......@@ -444,7 +444,7 @@ void KisInputManager::Private::addWheelShortcut(KisAbstractInputAction* action,
}
keyShortcut->setWheel(QSet<Qt::Key>::fromList(modifiers), a);
matcher.addShortcut(keyShortcut);
matcher.addShortcut(keyShortcut.take());
}
void KisInputManager::Private::addTouchShortcut(KisAbstractInputAction* action, int index, KisShortcutConfiguration::GestureAction gesture)
......
......@@ -66,6 +66,7 @@
#include "dialogs/kis_dlg_png_import.h"
#include "kis_clipboard.h"
#include <kis_cursor_override_hijacker.h>
#include "kis_undo_stores.h"
namespace
{
......@@ -622,8 +623,8 @@ KisImageBuilder_Result KisPNGConverter::buildImage(QIODevice* iod)
// Creating the KisImageSP
if (m_image == 0) {
m_image = new KisImage(m_doc->createUndoStore(), width, height, cs, "built image");
Q_CHECK_PTR(m_image);
KisUndoStore *store = m_doc ? m_doc->createUndoStore() : new KisSurrogateUndoStore();
m_image = new KisImage(store, width, height, cs, "built image");
}
// Read resolution
......@@ -667,14 +668,13 @@ KisImageBuilder_Result KisPNGConverter::buildImage(QIODevice* iod)
}
}
}
// Read image data
KisPNGReaderAbstract* reader = 0;
QScopedPointer<KisPNGReaderAbstract> reader;
try {
if (interlace_type == PNG_INTERLACE_ADAM7) {
reader = new KisPNGReaderFullImage(png_ptr, info_ptr, width, height);
reader.reset(new KisPNGReaderFullImage(png_ptr, info_ptr, width, height));
} else {
reader = new KisPNGReaderLineByLine(png_ptr, info_ptr, width, height);
reader.reset(new KisPNGReaderLineByLine(png_ptr, info_ptr, width, height));
}
} catch (std::bad_alloc& e) {
// new png_byte[] may raise such an exception if the image
......@@ -796,8 +796,6 @@ KisImageBuilder_Result KisPNGConverter::buildImage(QIODevice* iod)
// Freeing memory
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
delete reader;
return KisImageBuilder_RESULT_OK;
}
......@@ -970,10 +968,10 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
Q_ASSERT(color_type > -1);
// Try to compute a table of color if the colorspace is RGB8f
png_colorp palette = 0;
QScopedArrayPointer<png_color> palette;
int num_palette = 0;
if (!options.alpha && options.tryToSaveAsIndexed && KoID(device->colorSpace()->id()) == KoID("RGBA")) { // png doesn't handle indexed images and alpha, and only have indexed for RGB8
palette = new png_color[255];
palette.reset(new png_color[255]);
KisSequentialIterator it(device, imageRect);
......@@ -1014,7 +1012,7 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
color_nb_bits = 8;
}
} else {
delete [] palette;
palette.reset();
}
}
......@@ -1038,9 +1036,14 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
/*if (!options.saveSRGBProfile && sRGB) {
png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
}*/
// we should ensure we don't access non-existing palette object
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(palette || color_type != PNG_COLOR_TYPE_PALETTE, KisImageBuilder_RESULT_FAILURE);
// set the palette
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
png_set_PLTE(png_ptr, info_ptr, palette.data(), num_palette);
}
// Save annotation
vKisAnnotationSP_it it = annotationsStart;
......@@ -1188,26 +1191,48 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
// Write the PNG
// png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
struct RowPointersStruct {
RowPointersStruct(const QSize &size, int pixelSize)
: numRows(size.height())
{
rows = new png_byte*[numRows];
for (int i = 0; i < numRows; i++) {
rows[i] = new png_byte[size.width() * pixelSize];
}
}
~RowPointersStruct() {
for (int i = 0; i < numRows; i++) {
delete[] rows[i];
}
delete[] rows;
}
const int numRows = 0;
png_byte** rows = 0;
};
// Fill the data structure
png_byte** row_pointers = new png_byte*[imageRect.height()];
RowPointersStruct rowPointers(imageRect.size(), device->pixelSize());
int row = 0;
for (int y = imageRect.y(); y < imageRect.y() + imageRect.height(); y++, row++) {
KisHLineConstIteratorSP it = device->createHLineConstIteratorNG(imageRect.x(), y, imageRect.width());
row_pointers[row] = new png_byte[imageRect.width() * device->pixelSize()];
switch (color_type) {
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_GRAY_ALPHA:
if (color_nb_bits == 16) {
quint16 *dst = reinterpret_cast<quint16 *>(row_pointers[row]);
quint16 *dst = reinterpret_cast<quint16 *>(rowPointers.rows[row]);
do {
const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
*(dst++) = d[0];
if (options.alpha) *(dst++) = d[1];
} while (it->nextPixel());
} else {
quint8 *dst = row_pointers[row];
quint8 *dst = rowPointers.rows[row];
do {
const quint8 *d = it->oldRawData();
*(dst++) = d[0];
......@@ -1218,7 +1243,7 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
if (color_nb_bits == 16) {
quint16 *dst = reinterpret_cast<quint16 *>(row_pointers[row]);
quint16 *dst = reinterpret_cast<quint16 *>(rowPointers.rows[row]);
do {
const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
*(dst++) = d[2];
......@@ -1227,7 +1252,7 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
if (options.alpha) *(dst++) = d[3];
} while (it->nextPixel());
} else {
quint8 *dst = row_pointers[row];
quint8 *dst = rowPointers.rows[row];
do {
const quint8 *d = it->oldRawData();
*(dst++) = d[2];
......@@ -1238,7 +1263,7 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
}
break;
case PNG_COLOR_TYPE_PALETTE: {
quint8 *dst = row_pointers[row];
quint8 *dst = rowPointers.rows[row];
KisPNGWriteStream writestream(dst, color_nb_bits);
do {
const quint8 *d = it->oldRawData();
......@@ -1255,26 +1280,17 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
}
break;
default:
delete[] row_pointers;
return KisImageBuilder_RESULT_UNSUPPORTED;
}
}
png_write_image(png_ptr, row_pointers);
png_write_image(png_ptr, rowPointers.rows);
// Writing is over
png_write_end(png_ptr, info_ptr);
// Free memory
png_destroy_write_struct(&png_ptr, &info_ptr);
for (int y = 0; y < imageRect.height(); y++) {
delete[] row_pointers[y];
}
delete[] row_pointers;
if (color_type == PNG_COLOR_TYPE_PALETTE) {
delete [] palette;
}
return KisImageBuilder_RESULT_OK;
}
......
......@@ -515,6 +515,10 @@ TextTool::TextTool(MockCanvas *canvas) // constructor for our unit tests;
TextTool::~TextTool()
{
delete m_toolSelection;
KIS_SAFE_ASSERT_RECOVER (!m_currentCommand) {
delete m_currentCommand;
}
}
void TextTool::showEditTip()
......@@ -2825,12 +2829,12 @@ void TextTool::createStyleFromCurrentBlockFormat(const QString &name)
void TextTool::createStyleFromCurrentCharFormat(const QString &name)
{
KoCharacterStyle blankStyle;
KoTextDocument document(m_textShapeData->document());
KoStyleManager *styleManager = document.styleManager();
KoCharacterStyle *originalCharStyle = styleManager->characterStyle(m_textEditor.data()->charFormat().intProperty(KoCharacterStyle::StyleId));
KoCharacterStyle *autoStyle;
if (!originalCharStyle) {
KoCharacterStyle blankStyle;
originalCharStyle = &blankStyle;
autoStyle = originalCharStyle->autoStyle(m_textEditor.data()->charFormat(), m_textEditor.data()->blockCharFormat());
autoStyle->setParentStyle(0);
......
......@@ -87,7 +87,8 @@ void BibliographyGenerator::generate()
cursor.setPosition(m_bibDocument->rootFrame()->firstPosition(), QTextCursor::KeepAnchor);
cursor.beginEditBlock();
KoStyleManager *styleManager = KoTextDocument(m_block.document()).styleManager();
KoTextDocument koDocument(m_block.document());
KoStyleManager *styleManager = koDocument.styleManager();
if (!m_bibInfo->m_indexTitleTemplate.text.isNull()) {
KoParagraphStyle *titleStyle = styleManager->paragraphStyle(m_bibInfo->m_indexTitleTemplate.styleId);
......@@ -106,13 +107,13 @@ void BibliographyGenerator::generate()
QTextCharFormat savedCharFormat = cursor.charFormat();
QList<KoInlineCite*> citeList;
if ( KoTextDocument(m_block.document()).styleManager()->bibliographyConfiguration()->sortByPosition() ) {
citeList = KoTextDocument(m_block.document())
.inlineTextObjectManager()->citationsSortedByPosition(false, m_block.document()->firstBlock());
if (styleManager->bibliographyConfiguration()->sortByPosition()) {
citeList = koDocument.inlineTextObjectManager()->
citationsSortedByPosition(false, m_block.document()->firstBlock());
} else {
KoTextDocument *doc = new KoTextDocument(m_block.document());
citeList = sort(doc->inlineTextObjectManager()->citationsSortedByPosition(false, m_block.document()->firstBlock()),
KoTextDocument(m_block.document()).styleManager()->bibliographyConfiguration()->sortKeys());
citeList = sort(koDocument.inlineTextObjectManager()->
citationsSortedByPosition(false, m_block.document()->firstBlock()),
koDocument.styleManager()->bibliographyConfiguration()->sortKeys());
}
foreach (KoInlineCite *cite, citeList)
......
......@@ -50,6 +50,7 @@ KoAnchorTextRange::KoAnchorTextRange(KoShapeAnchor *parent, const QTextCursor &c
KoAnchorTextRange::~KoAnchorTextRange()
{
delete d_ptr;
}
KoShapeAnchor *KoAnchorTextRange::anchor() const
......
......@@ -67,6 +67,7 @@ OdfTextTrackStyles::OdfTextTrackStyles(KoStyleManager *manager)
OdfTextTrackStyles::~OdfTextTrackStyles()
{
delete m_changeCommand;
}
void OdfTextTrackStyles::beginEdit()
......
......@@ -145,15 +145,13 @@ void KoTextWriter::write(const QTextDocument *document, int from, int to)
}
// save the whole list if all list-items are selected
if (currentList) {
int fromindex = currentList->itemNumber(fromblock);
int toindex = currentList->itemNumber(toblock);
if ((fromcursor.isNull() || fromcursor.currentList() != currentList) &&
(toCursor.isNull() || toCursor.currentList() != currentList) &&
fromindex <= 0 && (toindex < 0 || toindex == currentList->count()-1)
int fromindex = currentList->itemNumber(fromblock);
int toindex = currentList->itemNumber(toblock);
if ((fromcursor.isNull() || fromcursor.currentList() != currentList) &&
(toCursor.isNull() || toCursor.currentList() != currentList) &&
fromindex <= 0 && (toindex < 0 || toindex == currentList->count()-1)
) {
currentList = 0;
}
currentList = 0;
}
}
}
......
......@@ -47,6 +47,7 @@
#include <KoTableRowStyle.h>
#include <KoInlineTextObjectManager.h>
#include <KoVariable.h>
#include "kis_assert.h"
#include "TextDebug.h"
......@@ -77,15 +78,22 @@ KoTextWriter::Private::Private(KoShapeSavingContext &context)
, writer(0)
, context(context)
{
currentPairedInlineObjectsStack = new QStack<KoInlineObject*>();
currentPairedInlineObjectsStack.reset(new QStack<KoInlineObject*>());
writer = &context.xmlWriter();
}
void KoTextWriter::Private::writeBlocks(QTextDocument *document, int from, int to, QHash<QTextList *, QString> &listStyles, QTextTable *currentTable, QTextList *currentList)
KoTextWriter::Private::~Private()
{
pairedInlineObjectsStackStack.push(currentPairedInlineObjectsStack);
currentPairedInlineObjectsStack = new QStack<KoInlineObject*>();
QTextBlock block = document->findBlock(from);
KIS_SAFE_ASSERT_RECOVER (pairedInlineObjectsStackStack.isEmpty()) {
qDeleteAll(pairedInlineObjectsStackStack);
}
}
void KoTextWriter::Private::writeBlocks(QTextDocument *doc, int from, int to, QHash<QTextList *, QString> &listStyles, QTextTable *currentTable, QTextList *currentList)
{
pairedInlineObjectsStackStack.push(currentPairedInlineObjectsStack.take());
currentPairedInlineObjectsStack.reset(new QStack<KoInlineObject*>());
QTextBlock block = doc->findBlock(from);
// Here we are going to detect all sections that
// are positioned entirely inside selection.
......@@ -95,7 +103,7 @@ void KoTextWriter::Private::writeBlocks(QTextDocument *document, int from, int t
// the selection and finding open/close pairs.
QSet<QString> entireWithinSectionNames;
QStack<QString> sectionNamesStack;
QTextCursor cur(document);
QTextCursor cur(doc);
cur.setPosition(from);
while (to == -1 || cur.position() <= to) {
if (cur.block().position() >= from) { // Begin of the block is inside selection.
......@@ -143,12 +151,12 @@ void KoTextWriter::Private::writeBlocks(QTextDocument *document, int from, int t
continue;
}
if (format.hasProperty(KoParagraphStyle::TableOfContentsData)) {
saveTableOfContents(document, listStyles, block);
saveTableOfContents(doc, listStyles, block);
block = block.next();
continue;
}
if (format.hasProperty(KoParagraphStyle::BibliographyData)) {
saveBibliography(document, listStyles, block);
saveBibliography(doc, listStyles, block);
block = block.next();
continue;
}
......@@ -183,8 +191,7 @@ void KoTextWriter::Private::writeBlocks(QTextDocument *document, int from, int t
} // while
Q_ASSERT(!pairedInlineObjectsStackStack.isEmpty());
delete currentPairedInlineObjectsStack;
currentPairedInlineObjectsStack = pairedInlineObjectsStackStack.pop();
currentPairedInlineObjectsStack.reset(pairedInlineObjectsStackStack.pop());
}
......@@ -1080,7 +1087,7 @@ void KoTextWriter::Private::writeAttributes(QTextStream &, KoXmlElement &)
}
void KoTextWriter::Private::writeNode(QTextStream &outputXmlStream, KoXmlNode &node, bool writeOnlyChildren)
void KoTextWriter::Private::writeNode(QTextStream &outputXmlStream, const KoXmlNode &node, bool writeOnlyChildren)
{
if (node.isText()) {
outputXmlStream << node.toText().data();
......
......@@ -25,6 +25,7 @@
#include <QStack>
#include <QPair>
#include <QString>
#include <QScopedPointer>
#include <KoTextWriter.h>
#include <KoXmlReaderForward.h>
......@@ -101,7 +102,7 @@ public:
explicit Private(KoShapeSavingContext &context);
~Private() {}
~Private();
void writeBlocks(QTextDocument *document, int from, int to,
QHash<QTextList *, QString> &listStyles,
......@@ -145,7 +146,7 @@ private:
// Common methods
void writeAttributes(QTextStream &outputXmlStream, KoXmlElement &element);
void writeNode(QTextStream &outputXmlStream, KoXmlNode &node, bool writeOnlyChildren = false);
void writeNode(QTextStream &outputXmlStream, const KoXmlNode &node, bool writeOnlyChildren = false);
QString createXmlId();
......@@ -170,7 +171,7 @@ private:
// when their end markeris not included in the selection. However, when recursing into
// e.g. the QTextDocument of a table, we need have a clean slate. Hence, a stack of stacks.
QStack< QStack<KoInlineObject*> *> pairedInlineObjectsStackStack;
QStack<KoInlineObject*> *currentPairedInlineObjectsStack;
QScopedPointer<QStack<KoInlineObject*>> currentPairedInlineObjectsStack;
QMap<KoList *, QString> listXmlIds;
......
......@@ -236,11 +236,11 @@ KisImportExportFilter::ConversionStatus KisPPMImport::convert(KisDocument *docum
KisImageSP image = new KisImage(document->createUndoStore(), width, height, colorSpace, "built image");
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
KisPpmFlow* ppmFlow = 0;
QScopedPointer<KisPpmFlow> ppmFlow;
if (isAscii) {
ppmFlow = new KisAsciiPpmFlow(io);
ppmFlow.reset(new KisAsciiPpmFlow(io));
} else {
ppmFlow = new KisBinaryPpmFlow(io, pixelsize * width);
ppmFlow.reset(new KisBinaryPpmFlow(io, pixelsize * width));
}
for (int v = 0; v < height; ++v) {
......
......@@ -103,7 +103,7 @@ bool PSDLayerMaskSection::readLayerInfoImpl(QIODevice* io)
dbgFile << "Going to read layer" << i << "pos" << io->pos();
dbgFile << "== Enter PSDLayerRecord";
PSDLayerRecord *layerRecord = new PSDLayerRecord(m_header);
QScopedPointer<PSDLayerRecord> layerRecord(new PSDLayerRecord(m_header));
if (!layerRecord->read(io)) {
error = QString("Could not load layer %1: %2").arg(i).arg(layerRecord->error);
return false;
......@@ -112,7 +112,7 @@ bool PSDLayerMaskSection::readLayerInfoImpl(QIODevice* io)
dbgFile << "Finished reading layer" << i << layerRecord->layerName << "blending mode"
<< layerRecord->blendModeKey << io->pos()
<< "Number of channels:" << layerRecord->channelInfoRecords.size();
layers << layerRecord;
layers << layerRecord.take();
}
}
......@@ -581,9 +581,6 @@ void PSDLayerMaskSection::writeImpl(QIODevice* io, KisNodeSP rootLayer)
SAFE_WRITE_EX(io, globalMaskSize);
}
{
PsdAdditionalLayerInfoBlock globalInfoSection(m_header);
globalInfoSection.writePattBlockEx(io, mergedPatternsXmlDoc);
}
globalInfoSection.writePattBlockEx(io, mergedPatternsXmlDoc);
}
}
......@@ -124,10 +124,7 @@ FilterEffectResource *FilterEffectResource::fromFilterEffectStack(KoFilterEffect
KoFilterEffectStack *FilterEffectResource::toFilterStack() const
{
KoFilterEffectStack *filterStack = new KoFilterEffectStack();
if (!filterStack) {
return 0;
}
QScopedPointer<KoFilterEffectStack> filterStack(new KoFilterEffectStack());
QByteArray data = m_data.toByteArray();
KoXmlDocument doc;
......@@ -183,7 +180,7 @@ KoFilterEffectStack *FilterEffectResource::toFilterStack() const
filterStack->appendFilterEffect(filterEffect);
}
return filterStack;
return filterStack.take();
}
QByteArray FilterEffectResource::generateMD5() const
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment