commit ba26711a10a2a2626612ee2043a116517faaf200
parent d262ea878ccf23df24ca7a361d068a8125476c34
Author: Johannes Lorenz <j.git@lorenz-ho.me>
Date: Sun, 28 May 2023 22:16:40 +0200
MW: Fix multiple memleaks
* `MiddleWareImpl::saveParams`: delete synth - trivial
* `MiddleWareImpl`: Handle all `/free` messages on destruction,
instead of ignoring all. For tests which do not handle `bToU`
at all, we provide a function to do this on a regular basis.
Diffstat:
3 files changed, 105 insertions(+), 82 deletions(-)
diff --git a/src/Misc/MiddleWare.cpp b/src/Misc/MiddleWare.cpp
@@ -577,6 +577,7 @@ public:
MiddleWareImpl(MiddleWare *mw, SYNTH_T synth, Config* config,
int preferred_port);
~MiddleWareImpl(void);
+ void discardAllbToUButHandleFree();
void recreateMinimalMaster();
//Check offline vs online mode in plugins
@@ -755,103 +756,106 @@ public:
zyn::Config config;
config.cfg.SaveFullXml = master->SaveFullXml;
- zyn::SYNTH_T* synth = new zyn::SYNTH_T;
- synth->buffersize = master->synth.buffersize;
- synth->samplerate = master->synth.samplerate;
- synth->alias();
+ zyn::SYNTH_T* synth2 = new zyn::SYNTH_T;
+ synth2->buffersize = master->synth.buffersize;
+ synth2->samplerate = master->synth.samplerate;
+ synth2->alias();
- zyn::Master master2(*synth, &config);
- master->copyMasterCbTo(&master2);
- master2.frozenState = true;
-
- std::set<std::string> alreadyWritten;
- rtosc_version m_version =
- {
- (unsigned char) version.get_major(),
- (unsigned char) version.get_minor(),
- (unsigned char) version.get_revision()
- };
- savefile = rtosc::save_to_file(getNonRtParamPorts(), this, "ZynAddSubFX", m_version, alreadyWritten, {});
- savefile += '\n';
-
- doReadOnlyOp([this,filename,&dispatcher,&master2,&savefile,&res,&alreadyWritten]()
{
- savefile = master->saveOSC(savefile, alreadyWritten);
-#if 1
- // load the savefile string into another master to compare the results
- // between the original and the savefile-loaded master
- // this requires a temporary master switch
- Master* old_master = master;
- dispatcher.updateMaster(&master2);
- while(old_master->isMasterSwitchUpcoming()) { os_usleep(50000); }
-
- res = master2.loadOSCFromStr(savefile.c_str(), &dispatcher);
- // TODO: compare MiddleWare, too?
-
- // The above call is done by this thread (i.e. the MiddleWare thread), but
- // it sends messages to master2 in order to load the values
- // We need to wait until savefile has been loaded into master2
- int i;
- for(i = 0; i < 20 && master2.uToB->hasNext(); ++i)
- os_usleep(50000);
- if(i >= 20) // >= 1 second?
- {
- // Master failed to fetch its messages
- res = -1;
- }
- printf("Saved in less than %d ms.\n", 50*i);
+ zyn::Master master2(*synth2, &config);
+ master->copyMasterCbTo(&master2);
+ master2.frozenState = true;
- dispatcher.updateMaster(old_master);
- while(master2.isMasterSwitchUpcoming()) { os_usleep(50000); }
-#endif
- if(res < 0)
+ std::set<std::string> alreadyWritten;
+ rtosc_version m_version =
{
- std::cerr << "invalid savefile (or a backend error)!" << std::endl;
- std::cerr << "complete savefile:" << std::endl;
- std::cerr << savefile << std::endl;
- std::cerr << "first entry that could not be parsed:" << std::endl;
+ (unsigned char) version.get_major(),
+ (unsigned char) version.get_minor(),
+ (unsigned char) version.get_revision()
+ };
+ savefile = rtosc::save_to_file(getNonRtParamPorts(), this, "ZynAddSubFX", m_version, alreadyWritten, {});
+ savefile += '\n';
- for(int i = -res + 1; savefile[i]; ++i)
- if(savefile[i] == '\n')
+ doReadOnlyOp([this,filename,&dispatcher,&master2,&savefile,&res,&alreadyWritten]()
+ {
+ savefile = master->saveOSC(savefile, alreadyWritten);
+#if 1
+ // load the savefile string into another master to compare the results
+ // between the original and the savefile-loaded master
+ // this requires a temporary master switch
+ Master* old_master = master;
+ dispatcher.updateMaster(&master2);
+ while(old_master->isMasterSwitchUpcoming()) { os_usleep(50000); }
+
+ res = master2.loadOSCFromStr(savefile.c_str(), &dispatcher);
+ // TODO: compare MiddleWare, too?
+
+ // The above call is done by this thread (i.e. the MiddleWare thread), but
+ // it sends messages to master2 in order to load the values
+ // We need to wait until savefile has been loaded into master2
+ int i;
+ for(i = 0; i < 20 && master2.uToB->hasNext(); ++i)
+ os_usleep(50000);
+ if(i >= 20) // >= 1 second?
{
- savefile.resize(i);
- break;
+ // Master failed to fetch its messages
+ res = -1;
}
- std::cerr << (savefile.c_str() - res) << std::endl;
+ printf("Saved in less than %d ms.\n", 50*i);
- res = -1;
- }
- else
- {
- char* xml = master->getXMLData(),
- * xml2 = master2.getXMLData();
- // TODO: below here can be moved out of read only op
-
- res = strcmp(xml, xml2) ? -1 : 0;
-
- if(res == 0)
+ dispatcher.updateMaster(old_master);
+ while(master2.isMasterSwitchUpcoming()) { os_usleep(50000); }
+#endif
+ if(res < 0)
{
- if(filename && *filename)
+ std::cerr << "invalid savefile (or a backend error)!" << std::endl;
+ std::cerr << "complete savefile:" << std::endl;
+ std::cerr << savefile << std::endl;
+ std::cerr << "first entry that could not be parsed:" << std::endl;
+
+ for(int i = -res + 1; savefile[i]; ++i)
+ if(savefile[i] == '\n')
{
- std::ofstream ofs(filename);
- ofs << savefile;
+ savefile.resize(i);
+ break;
}
+ std::cerr << (savefile.c_str() - res) << std::endl;
+
+ res = -1;
}
else
{
- std::cout << savefile << std::endl;
- std::cerr << "Cannot write OSC savefile!! (see tmp1.txt and tmp2.txt)"
- << std::endl;
- std::ofstream tmp1("tmp1.txt"), tmp2("tmp2.txt");
- tmp1 << xml;
- tmp2 << xml2;
- res = -1;
- }
+ char* xml = master->getXMLData(),
+ * xml2 = master2.getXMLData();
+ // TODO: below here can be moved out of read only op
- free(xml);
- free(xml2);
- }
- });
+ res = strcmp(xml, xml2) ? -1 : 0;
+
+ if(res == 0)
+ {
+ if(filename && *filename)
+ {
+ std::ofstream ofs(filename);
+ ofs << savefile;
+ }
+ }
+ else
+ {
+ std::cout << savefile << std::endl;
+ std::cerr << "Cannot write OSC savefile!! (see tmp1.txt and tmp2.txt)"
+ << std::endl;
+ std::ofstream tmp1("tmp1.txt"), tmp2("tmp2.txt");
+ tmp1 << xml;
+ tmp2 << xml2;
+ res = -1;
+ }
+
+ free(xml);
+ free(xml2);
+ }
+ });
+ }
+ delete synth2;
}
else // xml format
{
@@ -2024,8 +2028,18 @@ MiddleWareImpl::MiddleWareImpl(MiddleWare *mw, SYNTH_T synth_,
offline = false;
}
+void MiddleWareImpl::discardAllbToUButHandleFree()
+{
+ while(bToU->hasNext()) {
+ const char *rtmsg = bToU->read();
+ if(!strcmp(rtmsg, "/free"))
+ bToUhandle(rtmsg);
+ }
+}
+
MiddleWareImpl::~MiddleWareImpl(void)
{
+ discardAllbToUButHandleFree();
if(server)
lo_server_free(server);
@@ -2685,4 +2699,9 @@ void MiddleWare::switchMaster(Master* new_master)
}
}
+void MiddleWare::discardAllbToUButHandleFree()
+{
+ impl->discardAllbToUButHandleFree();
+}
+
}
diff --git a/src/Misc/MiddleWare.h b/src/Misc/MiddleWare.h
@@ -101,6 +101,8 @@ class MiddleWare
//!@warning use with care, and only in frozen state
void switchMaster(Master* new_master);
+ void discardAllbToUButHandleFree();
+
static const rtosc::MergePorts& getAllPorts();
private:
diff --git a/src/Tests/SaveOSC.cpp b/src/Tests/SaveOSC.cpp
@@ -244,6 +244,7 @@ class SaveOSCTest
fprintf(stderr, "Loading XMZ file %s...\n", filename.c_str());
load_ok = timeOutOperation("/load_xmz", filename.c_str(), 1000);
}
+ mw->discardAllbToUButHandleFree();
if(load_ok)
{
@@ -256,6 +257,7 @@ class SaveOSCTest
? EXIT_SUCCESS
: EXIT_FAILURE;
wait_for_message();
+ mw->discardAllbToUButHandleFree();
dump_savefile(rval);
}
else