From 051670160b187544248187d34d3467fb3f5f3678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Mon, 5 Jun 2017 10:58:14 +0200 Subject: [PATCH 01/11] Some fixes as hinted by Coverity (#3558) --- rtengine/array2D.h | 4 ++-- rtengine/color.cc | 33 +++++++++++++++++---------------- rtengine/dcrop.cc | 12 ++++-------- rtengine/ipretinex.cc | 9 +++------ rtengine/ipwavelet.cc | 3 ++- rtengine/lcp.cc | 6 +++--- rtengine/simpleprocess.cc | 34 +++++++++++++++------------------- rtgui/main-cli.cc | 8 ++++---- rtgui/main.cc | 8 ++++---- 9 files changed, 54 insertions(+), 63 deletions(-) diff --git a/rtengine/array2D.h b/rtengine/array2D.h index c05c739dc..9645a3a6e 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -113,7 +113,7 @@ public: // use as empty declaration, resize before use! // very useful as a member object array2D() : - x(0), y(0), owner(0), flags(0), ptr(nullptr), data(nullptr), lock(0) + x(0), y(0), owner(0), flags(0), ptr(nullptr), data(nullptr), lock(false) { //printf("got empty array2D init\n"); } @@ -143,7 +143,7 @@ public: { flags = flgs; //if (lock) { printf("array2D attempt to overwrite data\n");raise(SIGSEGV);} - lock |= flags & ARRAY2D_LOCK_DATA; + lock = flags & ARRAY2D_LOCK_DATA; // when by reference // TODO: improve this code with ar_realloc() owner = (flags & ARRAY2D_BYREFERENCE) ? 0 : 1; diff --git a/rtengine/color.cc b/rtengine/color.cc index f045a84d9..0da74d1c0 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -773,37 +773,38 @@ void Color::hsl2rgb01 (float h, float s, float l, float &r, float &g, float &b) void Color::rgb2hsv(float r, float g, float b, float &h, float &s, float &v) { - double var_R = r / 65535.0; - double var_G = g / 65535.0; - double var_B = b / 65535.0; + const double var_R = r / 65535.0; + const double var_G = g / 65535.0; + const double var_B = b / 65535.0; - double var_Min = min(var_R, var_G, var_B); - double var_Max = max(var_R, var_G, var_B); - double del_Max = var_Max - var_Min; + const double var_Min = min(var_R, var_G, var_B); + const double var_Max = max(var_R, var_G, var_B); + const double del_Max = var_Max - var_Min; + + h = 0.f; v = var_Max; if (del_Max < 0.00001 && del_Max > -0.00001) { // no fabs, slow! - h = 0; - s = 0; + s = 0.f; } else { s = del_Max / var_Max; - if ( var_R == var_Max ) { + if (var_R == var_Max) { h = (var_G - var_B) / del_Max; - } else if ( var_G == var_Max ) { + } else if (var_G == var_Max) { h = 2.0 + (var_B - var_R) / del_Max; - } else if ( var_B == var_Max ) { + } else if (var_B == var_Max) { h = 4.0 + (var_R - var_G) / del_Max; } - h /= 6.0; + h /= 6.f; - if ( h < 0 ) { - h += 1; + if (h < 0.f) { + h += 1.f; } - if ( h > 1 ) { - h -= 1; + if (h > 1.f) { + h -= 1.f; } } } diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 351ce1f08..4b725ea8f 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -397,12 +397,8 @@ void Crop::update (int todo) MyTime t1aue, t2aue; t1aue.set(); - int crW, crH; - - if(settings->leveldnv == 0) { - crW = 100; - crH = 100; - } + int crW = 100; // settings->leveldnv == 0 + int crH = 100; // settings->leveldnv == 0 if(settings->leveldnv == 1) { crW = 250; @@ -1143,7 +1139,7 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte ProcParams& params = parent->params; parent->ipf.transCoord (parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh); - + if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, parent->params)) { // TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise int dW = int(double(parent->fw) * 0.15 / (2 * skip)); @@ -1173,7 +1169,7 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte orw = min(x2 - x1, parent->fw - orx); orh = min(y2 - y1, parent->fh - ory); } - + PreviewProps cp (orx, ory, orw, orh, skip); int orW, orH; diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 321298349..24567205f 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -273,8 +273,9 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } - float varx = 0.f; - float limdx, ilimdx; + float varx = vart; + float limdx = limD; + float ilimdx = ilimD; if(gradvart != 0) { if(gradvart == 1) { @@ -294,10 +295,6 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e limdx = limD * (0.4f * it + 0.6f); ilimdx = 1.f / limdx; } - } else { - varx = vart; - limdx = limD; - ilimdx = ilimD; } scal = round(sc); diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 5d899617b..d981c803d 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -1253,7 +1253,8 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int delete [] meanN; delete [] sigma; delete [] sigmaN; - + delete [] MaxP; + delete [] MaxN; } #ifdef _RT_NESTED_OPENMP omp_set_nested(oldNested); diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 821194afe..0e7bcd0ed 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -737,7 +737,7 @@ void XMLCALL LCPProfile::XmlTextHandler(void *pLCPProfile, const XML_Char *s, in if (!pProf->inCamProfiles || pProf->inAlternateLensID || pProf->inAlternateLensNames || *pProf->inInvalidTag) { return; } - + for (int i = 0; i < len; ++i) { pProf->textbuf << s[i]; } @@ -746,8 +746,6 @@ void XMLCALL LCPProfile::XmlTextHandler(void *pLCPProfile, const XML_Char *s, in void LCPProfile::handle_text(std::string text) { - const char *raw = text.c_str(); - // Check if it contains non-whitespaces (there are several calls to this for one tag unfortunately) bool onlyWhiteSpace = true; for (size_t i = 0; i < text.size(); ++i) { @@ -766,6 +764,8 @@ void LCPProfile::handle_text(std::string text) // convert to null terminated char* tag = pProf->lastTag; + const char* raw = text.c_str(); + // Common data section if (!pProf->firstLIDone) { // Generic tags are the same for all diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index efbba78d1..2e1c60ff8 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -43,7 +43,7 @@ void adjust_radius(const T &default_param, double scale_factor, T ¶m) const double delta = (param - default_param) * scale_factor; param = default_param + delta; } - + class ImageProcessor { public: @@ -91,7 +91,7 @@ private: } pl = nullptr; - + if (!stage_init()) { return nullptr; } @@ -267,12 +267,8 @@ private: if(settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PON") { MyTime t1pone, t2pone; t1pone.set(); - int crW, crH; - - if(settings->leveldnv == 0) { - crW = 100; - crH = 100; - } + int crW = 100; // settings->leveldnv == 0 + int crH = 100; // settings->leveldnv == 0 if(settings->leveldnv == 1) { crW = 250; @@ -540,7 +536,7 @@ private: PreviewProps ppP (coordW[wcr] , coordH[hcr], crW, crH, 1); imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); - + // we only need image reduced to 1/4 here for(int ii = 0; ii < crH; ii += 2) { @@ -713,7 +709,7 @@ private: hlcompr = params.toneCurve.hlcompr; hlcomprthresh = params.toneCurve.hlcomprthresh; - + if (params.toneCurve.autoexp) { LUTu aehist; int aehistcompr; @@ -737,7 +733,7 @@ private: procparams::ProcParams& params = job->pparams; //ImProcFunctions ipf (¶ms, true); ImProcFunctions &ipf = *(ipf_p.get()); - + // perform luma/chroma denoise // CieImage *cieView; // NoisCurve noiseLCurve; @@ -801,7 +797,7 @@ private: { procparams::ProcParams& params = job->pparams; //ImProcFunctions ipf (¶ms, true); - ImProcFunctions &ipf = *(ipf_p.get()); + ImProcFunctions &ipf = *(ipf_p.get()); imgsrc->convertColorSpace(baseImg, params.icm, currWB); @@ -809,7 +805,7 @@ private: hist16 (65536); ipf.firstAnalysis (baseImg, params, hist16); - + // perform transform (excepted resizing) if (ipf.needsTransform()) { Imagefloat* trImg = new Imagefloat (fw, fh); @@ -824,7 +820,7 @@ private: { procparams::ProcParams& params = job->pparams; //ImProcFunctions ipf (¶ms, true); - ImProcFunctions &ipf = *(ipf_p.get()); + ImProcFunctions &ipf = *(ipf_p.get()); if (params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { const int W = baseImg->getWidth(); @@ -1350,8 +1346,8 @@ private: { procparams::ProcParams& params = job->pparams; //ImProcFunctions ipf (¶ms, true); - ImProcFunctions &ipf = *(ipf_p.get()); - + ImProcFunctions &ipf = *(ipf_p.get()); + int imw, imh; double scale_factor = ipf.resizeScale(¶ms, fw, fh, imw, imh); @@ -1387,7 +1383,7 @@ private: } adjust_procparams(scale_factor); - + fw = imw; fh = imh; @@ -1437,7 +1433,7 @@ private: } } } - + params.epd.scale *= scale_factor; //params.epd.edgeStopping *= scale_factor; @@ -1528,7 +1524,7 @@ private: LUTf gCurve; LUTf bCurve; LUTu dummy; - + ToneCurve customToneCurve1, customToneCurve2; ColorGradientCurve ctColorCurve; OpacityCurve ctOpacityCurve; diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 2a2afca63..f6df47119 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -115,12 +115,12 @@ int main(int argc, char **argv) // get the path where the rawtherapee executable is stored #ifdef WIN32 WCHAR exnameU[512] = {0}; - GetModuleFileNameW (NULL, exnameU, 512); - WideCharToMultiByte(CP_UTF8, 0, exnameU, -1, exname, 512, 0, 0 ); + GetModuleFileNameW (NULL, exnameU, 511); + WideCharToMultiByte(CP_UTF8, 0, exnameU, -1, exname, 511, 0, 0 ); #else - if (readlink("/proc/self/exe", exname, 512) < 0) { - strncpy(exname, argv[0], 512); + if (readlink("/proc/self/exe", exname, 511) < 0) { + strncpy(exname, argv[0], 511); } #endif diff --git a/rtgui/main.cc b/rtgui/main.cc index 495374f50..0f4a96c8a 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -137,12 +137,12 @@ int main(int argc, char **argv) // get the path where the rawtherapee executable is stored #ifdef WIN32 WCHAR exnameU[512] = {0}; - GetModuleFileNameW (NULL, exnameU, 512); - WideCharToMultiByte(CP_UTF8, 0, exnameU, -1, exname, 512, 0, 0 ); + GetModuleFileNameW (NULL, exnameU, 511); + WideCharToMultiByte(CP_UTF8, 0, exnameU, -1, exname, 511, 0, 0 ); #else - if (readlink("/proc/self/exe", exname, 512) < 0) { - strncpy(exname, argv[0], 512); + if (readlink("/proc/self/exe", exname, 511) < 0) { + strncpy(exname, argv[0], 511); } #endif From 9e5ce9a99b6c5a596c4ab7cbf59b6c828a858408 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 5 Jun 2017 14:12:34 +0200 Subject: [PATCH 02/11] Some Coverity fixes (#3558) --- rtengine/EdgePreservingDecomposition.cc | 23 ++++++----------------- rtengine/EdgePreservingDecomposition.h | 2 +- rtengine/camconst.cc | 1 + rtengine/improcfun.cc | 4 ++-- rtengine/ipwavelet.cc | 2 +- rtengine/procparams.cc | 6 ++++++ rtengine/procparams.h | 1 + rtgui/editorpanel.cc | 4 +++- rtgui/previewloader.cc | 5 +++++ rtgui/previewloader.h | 1 + rtgui/thumbimageupdater.cc | 5 +++++ rtgui/thumbimageupdater.h | 1 + 12 files changed, 33 insertions(+), 22 deletions(-) diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 8c1ca56a7..0a92d41cd 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -6,7 +6,7 @@ #endif #include "sleef.c" #include "opthelper.h" - +#include #define pow_F(a,b) (xexpf(b*xlogf(a))) #define DIAGONALS 5 @@ -883,7 +883,7 @@ float *EdgePreservingDecomposition::CreateIteratedBlur(float *Source, float Scal return Blur; } -SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Source, float Scale, float EdgeStopping, float CompressionExponent, float DetailBoost, int Iterates, int Reweightings, float *Compressed) +SSEFUNCTION void EdgePreservingDecomposition::CompressDynamicRange(float *Source, float Scale, float EdgeStopping, float CompressionExponent, float DetailBoost, int Iterates, int Reweightings) { if(w < 300 && h < 300) { // set number of Reweightings to zero for small images (thumbnails). We could try to find a better solution here. Reweightings = 0; @@ -926,12 +926,7 @@ SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Sour //Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation). float *u = CreateIteratedBlur(Source, Scale, EdgeStopping, Iterates, Reweightings); - if(Compressed == nullptr) { - Compressed = u; - } - //Apply compression, detail boost, unlogging. Compression is done on the logged data and detail boost on unlogged. -// float temp = CompressionExponent - 1.0f; float temp; if(DetailBoost > 0.f) { @@ -958,8 +953,7 @@ SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Sour cev = xexpf(LVFU(Source[i]) + LVFU(u[i]) * (tempv)) - epsv; uev = xexpf(LVFU(u[i])) - epsv; sourcev = xexpf(LVFU(Source[i])) - epsv; - _mm_storeu_ps( &Source[i], sourcev); - _mm_storeu_ps( &Compressed[i], cev + DetailBoostv * (sourcev - uev) ); + _mm_storeu_ps( &Source[i], cev + DetailBoostv * (sourcev - uev) ); } } @@ -967,7 +961,7 @@ SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Sour float ce = xexpf(Source[i] + u[i] * (temp)) - eps; float ue = xexpf(u[i]) - eps; Source[i] = xexpf(Source[i]) - eps; - Compressed[i] = ce + DetailBoost * (Source[i] - ue); + Source[i] = ce + DetailBoost * (Source[i] - ue); } #else @@ -979,16 +973,11 @@ SSEFUNCTION float *EdgePreservingDecomposition::CompressDynamicRange(float *Sour float ce = xexpf(Source[i] + u[i] * (temp)) - eps; float ue = xexpf(u[i]) - eps; Source[i] = xexpf(Source[i]) - eps; - Compressed[i] = ce + DetailBoost * (Source[i] - ue); + Source[i] = ce + DetailBoost * (Source[i] - ue); } #endif - if(Compressed != u) { - delete[] u; - } - - return Compressed; - + delete[] u; } diff --git a/rtengine/EdgePreservingDecomposition.h b/rtengine/EdgePreservingDecomposition.h index bf567f103..1eca7b2c8 100644 --- a/rtengine/EdgePreservingDecomposition.h +++ b/rtengine/EdgePreservingDecomposition.h @@ -152,7 +152,7 @@ public: the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm. In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */ - float *CompressDynamicRange(float *Source, float Scale = 1.0f, float EdgeStopping = 1.4f, float CompressionExponent = 0.8f, float DetailBoost = 0.1f, int Iterates = 20, int Reweightings = 0, float *Compressed = nullptr); + void CompressDynamicRange(float *Source, float Scale = 1.0f, float EdgeStopping = 1.4f, float CompressionExponent = 0.8f, float DetailBoost = 0.1f, int Iterates = 20, int Reweightings = 0); private: MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner. diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 2449a1cd1..40e13d8e8 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -317,6 +317,7 @@ CameraConst::parseEntry(void *cJSON_, const char *make_model) return cc; parse_error: + delete cc; return nullptr; } diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 5c96aa6fd..95c3848ba 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -6438,7 +6438,7 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, float //Jacques Desmis : always Iterates=5 for compatibility images between preview and output - epd.CompressDynamicRange (Qpr, (float)sca / skip, (float)edgest, Compression, DetailBoost, Iterates, rew, Qpr); + epd.CompressDynamicRange (Qpr, (float)sca / skip, (float)edgest, Compression, DetailBoost, Iterates, rew); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. float s = (1.0f + 38.7889f) * powf (Compression, 1.5856f) / (1.0f + 38.7889f * powf (Compression, 1.5856f)); @@ -6585,7 +6585,7 @@ void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip fwrite(L, N, sizeof(float), f); fclose(f);*/ - epd.CompressDynamicRange (L, sca / float (skip), edgest, Compression, DetailBoost, Iterates, rew, L); + epd.CompressDynamicRange (L, sca / float (skip), edgest, Compression, DetailBoost, Iterates, rew); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. float s = (1.0f + 38.7889f) * powf (Compression, 1.5856f) / (1.0f + 38.7889f * powf (Compression, 1.5856f)); diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index d981c803d..cbde6aef1 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -1654,7 +1654,7 @@ void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterat } - epd2.CompressDynamicRange(WavCoeffs_L0, (float)sca / skip, edgest, Compression, DetailBoost, Iterates, rew, WavCoeffs_L0); + epd2.CompressDynamicRange(WavCoeffs_L0, (float)sca / skip, edgest, Compression, DetailBoost, Iterates, rew); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. #ifdef _RT_NESTED_OPENMP diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d64288c21..51e0bebf9 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -8502,6 +8502,12 @@ PartialProfile::PartialProfile(const ProcParams* pp, const ParamsEdited* pe) } } +PartialProfile::~PartialProfile() +{ + delete pparams; + delete pedited; +} + int PartialProfile::load (const Glib::ustring &fName) { if (!pparams) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 973986d85..5b2b2ebc4 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1435,6 +1435,7 @@ public: PartialProfile (bool createInstance = false, bool paramsEditedValue = false); PartialProfile (ProcParams* pp, ParamsEdited* pe = nullptr, bool fullCopy = false); PartialProfile (const ProcParams* pp, const ParamsEdited* pe = nullptr); + ~PartialProfile (); void deleteInstance (); void clearGeneral (); int load (const Glib::ustring &fName); diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 459abbe5b..b67fef8bd 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -451,7 +451,7 @@ public: }; EditorPanel::EditorPanel (FilePanel* filePanel) - : catalogPane(nullptr), realized(false), iHistoryShow(nullptr), iHistoryHide(nullptr), iTopPanel_1_Show(nullptr), iTopPanel_1_Hide(nullptr), iRightPanel_1_Show(nullptr), iRightPanel_1_Hide(nullptr), iBeforeLockON(nullptr), iBeforeLockOFF(nullptr), beforePreviewHandler(nullptr), beforeIarea(nullptr), beforeBox(nullptr), afterBox(nullptr), afterHeaderBox(nullptr), parent(nullptr), openThm(nullptr), ipc(nullptr), beforeIpc(nullptr), isProcessing(false) + : catalogPane(nullptr), realized(false), tbBeforeLock(nullptr), iHistoryShow(nullptr), iHistoryHide(nullptr), iTopPanel_1_Show(nullptr), iTopPanel_1_Hide(nullptr), iRightPanel_1_Show(nullptr), iRightPanel_1_Hide(nullptr), iBeforeLockON(nullptr), iBeforeLockOFF(nullptr), previewHandler(nullptr), beforePreviewHandler(nullptr), beforeIarea(nullptr), beforeBox(nullptr), afterBox(nullptr), beforeLabel(nullptr), afterLabel(nullptr), beforeHeaderBox(nullptr), afterHeaderBox(nullptr), parent(nullptr), openThm(nullptr), isrc(nullptr), ipc(nullptr), beforeIpc(nullptr), err(0), isProcessing(false) { epih = new EditorPanelIdleHelper; @@ -1689,6 +1689,8 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, Gl else if (sf.format == "jpg") ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp), sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf)); + else + delete ld; } else { Glib::ustring msg_ = Glib::ustring ("") + fname + ": Error during image processing\n"; Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); diff --git a/rtgui/previewloader.cc b/rtgui/previewloader.cc index 0c0ecf9f6..a43c47d2e 100644 --- a/rtgui/previewloader.cc +++ b/rtgui/previewloader.cc @@ -168,6 +168,11 @@ PreviewLoader::PreviewLoader(): { } +PreviewLoader::~PreviewLoader() +{ + delete impl_; +} + PreviewLoader* PreviewLoader::getInstance() { static PreviewLoader instance_; diff --git a/rtgui/previewloader.h b/rtgui/previewloader.h index d5207cd44..d2f21b013 100644 --- a/rtgui/previewloader.h +++ b/rtgui/previewloader.h @@ -88,6 +88,7 @@ public: private: PreviewLoader(); + ~PreviewLoader(); class Impl; Impl* impl_; diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index 95618d5ab..b30047c2f 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -184,6 +184,11 @@ ThumbImageUpdater::ThumbImageUpdater(): { } +ThumbImageUpdater::~ThumbImageUpdater() +{ + delete impl_; +} + void ThumbImageUpdater::add(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, ThumbImageUpdateListener* l) { diff --git a/rtgui/thumbimageupdater.h b/rtgui/thumbimageupdater.h index 3b34c9456..0ac92a31a 100644 --- a/rtgui/thumbimageupdater.h +++ b/rtgui/thumbimageupdater.h @@ -93,6 +93,7 @@ public: private: ThumbImageUpdater(); + ~ThumbImageUpdater(); class Impl; Impl* impl_; From 48bcf8b0774af82a39dc7dcff5e39eeca688f9ec Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 5 Jun 2017 14:14:14 +0200 Subject: [PATCH 03/11] Removed #include --- rtengine/EdgePreservingDecomposition.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 0a92d41cd..5e91eae9d 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -6,7 +6,6 @@ #endif #include "sleef.c" #include "opthelper.h" -#include #define pow_F(a,b) (xexpf(b*xlogf(a))) #define DIAGONALS 5 From 2aaa7526b38806bc703e930b470d2785051dc72e Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 5 Jun 2017 21:04:01 +0200 Subject: [PATCH 04/11] Hopefully better fix for memory leak in PartialProfiles --- rtengine/procparams.cc | 12 ++++++++++-- rtengine/procparams.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 51e0bebf9..e200ba610 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -8470,20 +8470,25 @@ PartialProfile::PartialProfile(bool createInstance, bool paramsEditedValue) pparams = nullptr; pedited = nullptr; } + ownsPparams = ownsPedited = true; } PartialProfile::PartialProfile(ProcParams* pp, ParamsEdited* pe, bool fullCopy) { if (fullCopy && pp) { pparams = new ProcParams(*pp); + ownsPparams = true; } else { pparams = pp; + ownsPparams = false; } if (fullCopy && pe) { pedited = new ParamsEdited(*pe); + ownsPedited = true; } else { pedited = pe; + ownsPedited = false; } } @@ -8500,12 +8505,15 @@ PartialProfile::PartialProfile(const ProcParams* pp, const ParamsEdited* pe) } else { pedited = nullptr; } + ownsPparams = ownsPedited = true; } PartialProfile::~PartialProfile() { - delete pparams; - delete pedited; + if(ownsPparams) + delete pparams; + if(ownsPedited) + delete pedited; } int PartialProfile::load (const Glib::ustring &fName) diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 5b2b2ebc4..817a4e011 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1441,6 +1441,9 @@ public: int load (const Glib::ustring &fName); void set (bool v); const void applyTo (ProcParams *destParams) const ; +private: + bool ownsPparams; + bool ownsPedited; }; /** From 9515f46f97977bc80caa67d931a2ec8f910b7456 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 6 Jun 2017 21:05:51 +0200 Subject: [PATCH 05/11] Fix oob access when using detail window --- rtgui/cropwindow.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 25311b97b..d7a2f5740 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -1026,6 +1026,12 @@ void CropWindow::pointerMoved (int bstate, int x, int y) cropHandler.cimg.lock (); int vx = x - xpos - imgX; int vy = y - ypos - imgY; + + if(decorated) { + vx -= sideBorderWidth; + vy -= (titleHeight + upperBorderWidth + sepWidth); + } + // guint8* pix = cropHandler.cropPixbuf->get_pixels() + vy*cropHandler.cropPixbuf->get_rowstride() + vx*3; // if (vx < cropHandler.cropPixbuf->get_width() && vy < cropHandler.cropPixbuf->get_height()) // pmlistener->pointerMoved (true, mx, my, pix[0], pix[1], pix[2]); From b3956a3fda05ef2323e37534ddd8adf6d7a3517f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 6 Jun 2017 21:06:19 +0200 Subject: [PATCH 06/11] Fix oob access when selecting more than 1 file in filebrowser --- rtgui/options.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index df68d0ac9..1f29264b8 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -576,22 +576,26 @@ void Options::setDefaults () 0, // ADDSET_DIRPYREQ_THRESHOLD 0, // ADDSET_DIRPYREQ_SKINPROTECT 0, // ADDSET_COLORTONING_SPLIT + 0, // ADDSET_COLORTONING_SATTHRESHOLD + 0, // ADDSET_COLORTONING_SATOPACITY + 0, // ADDSET_COLORTONING_BALANCE + 0, // ADDSET_COLORTONING_STRENGTH 0, // ADDSET_DIRPYRDN_PASSES 0, // ADDSET_RAWFFCLIPCONTROL 0, // ADDSET_FILMSIMULATION_STRENGTH 0, // ADDSET_WA + 0, // ADDSET_WA_SKINPROTECT + 0, // ADDSET_WA_THRESHOLD2 + 0, // ADDSET_WA_THRR + 0, // ADDSET_WA_THRRH 0, // ADDSET_WA_THRESHOLD 0, // ADDSET_WA_THRESHOLD2 - 0, // ADDSET_WA_THRES 0, // ADDSET_WA_CHRO 0, // ADDSET_WA_CHROMA 0, // ADDSET_WA_CONTRAST - 0, // ADDSET_WA_SKINPROTECT - 0, // ADDSET_WA_RESCHRO 0, // ADDSET_WA_RESCON 0, // ADDSET_WA_RESCONH - 0, // ADDSET_WA_THRR - 0, // ADDSET_WA_THRRH + 0, // ADDSET_WA_RESCHRO 0, // ADDSET_WA_SKYPROTECT 0, // ADDSET_WA_EDGRAD 0, // ADDSET_WA_EDGVAL From 2edd677d1a4f1fa68e42024c200848eb91009ae4 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 7 Jun 2017 10:36:28 +0200 Subject: [PATCH 07/11] Fixed various memory leaks as reported by AddressSanitizer --- rtengine/camconst.cc | 11 ++++++++--- rtengine/camconst.h | 2 +- rtengine/dcp.cc | 9 +++++++++ rtengine/dcp.h | 1 + rtengine/iccstore.cc | 14 +++++++++++++ rtengine/lcp.cc | 31 +++++++++++++++++++++++++---- rtengine/lcp.h | 2 ++ rtgui/filebrowser.cc | 47 +++++++++++--------------------------------- rtgui/filebrowser.h | 10 +++------- rtgui/filecatalog.cc | 1 + 10 files changed, 78 insertions(+), 50 deletions(-) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 2449a1cd1..0609b3699 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -27,9 +27,6 @@ CameraConst::CameraConst() white_max = 0; } -CameraConst::~CameraConst() -{ -} bool CameraConst::parseApertureScaling(CameraConst *cc, void *ji_) @@ -709,6 +706,14 @@ CameraConstantsStore::CameraConstantsStore() { } + +CameraConstantsStore::~CameraConstantsStore() +{ + for (auto &p : mCameraConstants) { + delete p.second; + } +} + void CameraConstantsStore::init(Glib::ustring baseDir, Glib::ustring userSettingsDir) { parse_camera_constants_file(Glib::build_filename(baseDir, "camconst.json")); diff --git a/rtengine/camconst.h b/rtengine/camconst.h index 713936bf8..31b65f3e8 100644 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -26,7 +26,6 @@ private: std::map mApertureScaling; CameraConst(); - ~CameraConst(); static bool parseLevels(CameraConst *cc, int bw, void *ji); static bool parseApertureScaling(CameraConst *cc, void *ji); bool get_Levels(struct camera_const_levels & lvl, int bw, int iso, float fnumber); @@ -55,6 +54,7 @@ private: bool parse_camera_constants_file(Glib::ustring filename); public: + ~CameraConstantsStore(); void init(Glib::ustring baseDir, Glib::ustring userSettingsDir); static CameraConstantsStore *getInstance(void); CameraConst *get(const char make[], const char model[]); diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index ad0621ce0..62765f812 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1701,6 +1701,15 @@ DCPStore* DCPStore::getInstance() return &instance; } + +DCPStore::~DCPStore() +{ + for (auto &p : profile_cache) { + delete p.second; + } +} + + void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) { MyMutex::MyLock lock(mutex); diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 5a6858099..10bbf8f7e 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -152,6 +152,7 @@ class DCPStore final : public NonCopyable { public: + ~DCPStore(); static DCPStore* getInstance(); void init(const Glib::ustring& rt_profile_dir, bool loadAll = true); diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 3bcc8515e..9dbeba00e 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -276,6 +276,20 @@ public: } } + ~Implementation() + { + for (auto &p : wProfiles) { + if (p.second) { + cmsCloseProfile(p.second); + } + } + for (auto &p : wProfilesGamma) { + if (p.second) { + cmsCloseProfile(p.second); + } + } + } + void init(const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir, bool loadAll) { // Reads all profiles from the given profiles dir diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 821194afe..1c5f12fb4 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -361,6 +361,11 @@ SSEFUNCTION void LCPMapper::processVignetteLine3Channels(int width, int y, float LCPProfile::LCPProfile(const Glib::ustring &fname) { + for (int i = 0; i < MaxPersModelCount; i++) { + aPersModel[i] = nullptr; + } + pCurPersModel = nullptr; + const int BufferSize = 8192; char buf[BufferSize]; @@ -378,10 +383,6 @@ LCPProfile::LCPProfile(const Glib::ustring &fname) isFisheye = inCamProfiles = firstLIDone = inPerspect = inAlternateLensID = inAlternateLensNames = false; sensorFormatFactor = 1; - for (int i = 0; i < MaxPersModelCount; i++) { - aPersModel[i] = nullptr; - } - persModelCount = 0; *inInvalidTag = 0; @@ -412,6 +413,19 @@ LCPProfile::LCPProfile(const Glib::ustring &fname) filterBadFrames(1.5, 100); } + +LCPProfile::~LCPProfile() +{ + if (pCurPersModel) { + delete pCurPersModel; + } + for (int i = 0; i < MaxPersModelCount; i++) { + if (aPersModel[i]) { + delete aPersModel[i]; + } + } +} + // from all frames not marked as bad already, take average and filter out frames with higher deviation than this if there are enough values int LCPProfile::filterBadFrames(double maxAvgDevFac, int minFramesLeft) { @@ -886,6 +900,15 @@ LCPStore* LCPStore::getInstance() return &instance_; } + +LCPStore::~LCPStore() +{ + for (auto &p : profileCache) { + delete p.second; + } +} + + LCPProfile* LCPStore::getProfile (Glib::ustring filename) { if (filename.length() == 0 || !isValidLCPFileName(filename)) { diff --git a/rtengine/lcp.h b/rtengine/lcp.h index 8cfcd5694..f7164117f 100644 --- a/rtengine/lcp.h +++ b/rtengine/lcp.h @@ -110,6 +110,7 @@ public: LCPPersModel* aPersModel[MaxPersModelCount]; // Do NOT use std::list or something, it's buggy in GCC! explicit LCPProfile(const Glib::ustring &fname); + ~LCPProfile(); void calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const; // Interpolates between the persModels frames @@ -124,6 +125,7 @@ class LCPStore std::map profileCache; public: + ~LCPStore(); Glib::ustring getDefaultCommonDirectory() const; bool isValidLCPFileName(Glib::ustring filename) const; LCPProfile* getProfile(Glib::ustring filename); diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index dd37a740b..b4238f011 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -128,11 +128,7 @@ void findOriginalEntries (const std::vector& entries) FileBrowser::FileBrowser () : tbl(nullptr), numFiltered(0) { - - fbih = new FileBrowserIdleHelper; - fbih->fbrowser = this; - fbih->destroyed = false; - fbih->pending = 0; + session_id_ = 0; ProfileStore::getInstance()->addListener(this); @@ -546,37 +542,27 @@ void FileBrowser::doubleClicked (ThumbBrowserEntryBase* entry) void FileBrowser::addEntry (FileBrowserEntry* entry) { struct addparams { - FileBrowserIdleHelper* fbih; - FileBrowserEntry* entry; + FileBrowser *browser; + FileBrowserEntry *entry; + unsigned int session_id; }; - fbih->pending++; - entry->setParent (this); addparams* const ap = new addparams; - ap->fbih = fbih; + entry->setParent (this); + ap->browser = this; ap->entry = entry; + ap->session_id = session_id(); const auto func = [](gpointer data) -> gboolean { addparams* const ap = static_cast(data); - FileBrowserIdleHelper* fbih = ap->fbih; - - if (fbih->destroyed) { - if (fbih->pending == 1) { - delete fbih; - } else { - fbih->pending--; - } - + if (ap->session_id != ap->browser->session_id()) { delete ap->entry; delete ap; - - return 0; + } else { + ap->browser->addEntry_(ap->entry); + delete ap; } - ap->fbih->fbrowser->addEntry_ (ap->entry); - delete ap; - fbih->pending--; - return FALSE; }; @@ -653,16 +639,7 @@ FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) void FileBrowser::close () { - if (fbih->pending) { - fbih->destroyed = true; - } else { - delete fbih; - } - - fbih = new FileBrowserIdleHelper; - fbih->fbrowser = this; - fbih->destroyed = false; - fbih->pending = 0; + ++session_id_; { MYWRITERLOCK(l, entryRW); diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 4bad832eb..4efdb7219 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -53,12 +53,6 @@ public: } }; -struct FileBrowserIdleHelper { - FileBrowser* fbrowser; - bool destroyed; - int pending; -}; - /* * Class handling actions common to all thumbnails of the file browser */ @@ -71,6 +65,7 @@ private: typedef sigc::signal type_trash_changed; IdleRegister idle_register; + unsigned int session_id_; protected: Gtk::MenuItem* rank[6]; @@ -129,7 +124,6 @@ protected: FileBrowserListener* tbl; BrowserFilter filter; int numFiltered; - FileBrowserIdleHelper* fbih; void toTrashRequested (std::vector tbe); void fromTrashRequested (std::vector tbe); @@ -152,6 +146,8 @@ public: FileBrowserEntry* delEntry (const Glib::ustring& fname); // return the entry if found here return NULL otherwise void close (); + unsigned int session_id() const { return session_id_; } + void setBatchPParamsChangeListener (BatchPParamsChangeListener* l) { bppcl = l; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 4ac1e0a3d..710450d90 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -720,6 +720,7 @@ void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) { if ( dir_id != selectedDirectoryId ) { + delete fdn; return; } From 5e22addc5425baf77aa9917610f0f27dcb2afcf6 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 7 Jun 2017 20:39:44 +0200 Subject: [PATCH 08/11] Fix memory leak in iccstore --- rtengine/iccstore.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 9dbeba00e..58c05665f 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -288,6 +288,11 @@ public: cmsCloseProfile(p.second); } } + for (auto &p : fileProfiles) { + if(p.second) { + cmsCloseProfile(p.second); + } + } } void init(const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir, bool loadAll) From 5e5affa585d80131363604959d97e60d5a5c1114 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 7 Jun 2017 21:32:28 +0200 Subject: [PATCH 09/11] Fix some memory leaks --- rtengine/iccstore.cc | 6 ++++++ rtengine/profilestore.cc | 2 ++ 2 files changed, 8 insertions(+) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 58c05665f..47bfadd80 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -293,6 +293,12 @@ public: cmsCloseProfile(p.second); } } + if(srgb) { + cmsCloseProfile(srgb); + } + if(xyz) { + cmsCloseProfile(xyz); + } } void init(const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir, bool loadAll) diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index 12c1cca5c..75e916808 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -248,6 +248,8 @@ bool ProfileStore::parseDir (Glib::ustring& realPath, Glib::ustring& virtualPath if (!fileFound && (level > 0 || displayLevel0)) { // no files found in this level, we delete the subdirectory entry folders.pop_back(); + + delete entries.back(); entries.pop_back(); } From a64421fb9106994c7d59715f3a63eaab47806a82 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 7 Jun 2017 23:11:06 +0200 Subject: [PATCH 10/11] Fix small memory leak --- rtgui/profilepanel.cc | 5 +++-- rtgui/profilepanel.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index 06768cf56..7738e5ded 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -39,7 +39,7 @@ void ProfilePanel::cleanup () delete partialProfileDlg; } -ProfilePanel::ProfilePanel () : storedPProfile(nullptr), lastFilename(""), imagePath("") +ProfilePanel::ProfilePanel () : storedPProfile(nullptr), lastFilename(""), imagePath(""), lastSavedPSE(nullptr) { tpc = nullptr; @@ -128,6 +128,7 @@ ProfilePanel::~ProfilePanel () delete profileFillModeOnImage; delete profileFillModeOffImage; + delete lastSavedPSE; } bool ProfilePanel::isCustomSelected() @@ -171,7 +172,7 @@ Gtk::TreeIter ProfilePanel::addCustomRow() Gtk::TreeIter ProfilePanel::addLastSavedRow() { - const ProfileStoreEntry *lastSavedPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")"), PSET_FILE, 0, 0); + lastSavedPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")"), PSET_FILE, 0, 0); Gtk::TreeIter newEntry = profiles->addRow(lastSavedPSE); return newEntry; } diff --git a/rtgui/profilepanel.h b/rtgui/profilepanel.h index 72c9db36b..fb3fa0a18 100644 --- a/rtgui/profilepanel.h +++ b/rtgui/profilepanel.h @@ -42,6 +42,7 @@ private: RTImage *profileFillModeOffImage; Gtk::ToggleButton* fillMode; Gtk::TreeIter currRow; + ProfileStoreEntry *lastSavedPSE; void profileFillModeToggled (); bool isCustomSelected (); From a24e8475f65c93d8b23e53c4571aed5d20d13811 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 7 Jun 2017 23:40:03 +0200 Subject: [PATCH 11/11] Fixes small memory leaks --- rtgui/profilepanel.cc | 15 +++++++++++++-- rtgui/profilepanel.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index 7738e5ded..8fe546546 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -39,7 +39,7 @@ void ProfilePanel::cleanup () delete partialProfileDlg; } -ProfilePanel::ProfilePanel () : storedPProfile(nullptr), lastFilename(""), imagePath(""), lastSavedPSE(nullptr) +ProfilePanel::ProfilePanel () : storedPProfile(nullptr), lastFilename(""), imagePath(""), lastSavedPSE(nullptr), customPSE(nullptr) { tpc = nullptr; @@ -129,6 +129,7 @@ ProfilePanel::~ProfilePanel () delete profileFillModeOnImage; delete profileFillModeOffImage; delete lastSavedPSE; + delete customPSE; } bool ProfilePanel::isCustomSelected() @@ -165,13 +166,23 @@ Gtk::TreeIter ProfilePanel::getLastSavedRow() Gtk::TreeIter ProfilePanel::addCustomRow() { - const ProfileStoreEntry *customPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")"), PSET_FILE, 0, 0); + if(customPSE) { + delete customPSE; + customPSE = nullptr; + } + + customPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PCUSTOM") + ")"), PSET_FILE, 0, 0); Gtk::TreeIter newEntry = profiles->addRow(customPSE); return newEntry; } Gtk::TreeIter ProfilePanel::addLastSavedRow() { + if(lastSavedPSE) { + delete lastSavedPSE; + lastSavedPSE = nullptr; + } + lastSavedPSE = new ProfileStoreEntry(Glib::ustring ("(" + M("PROFILEPANEL_PLASTSAVED") + ")"), PSET_FILE, 0, 0); Gtk::TreeIter newEntry = profiles->addRow(lastSavedPSE); return newEntry; diff --git a/rtgui/profilepanel.h b/rtgui/profilepanel.h index fb3fa0a18..ddd7133ca 100644 --- a/rtgui/profilepanel.h +++ b/rtgui/profilepanel.h @@ -43,6 +43,7 @@ private: Gtk::ToggleButton* fillMode; Gtk::TreeIter currRow; ProfileStoreEntry *lastSavedPSE; + ProfileStoreEntry *customPSE; void profileFillModeToggled (); bool isCustomSelected ();