WxWidgets Sizer Double Frees? - c++

I'm going to preface this question by saying that I am not entirely new to wxWidgets, though I would not consider myself all that experience either.
I'm having a problem which I have narrowed down through testing to be with the wxWidgets wxBoxSizer classes. From what I can tell, I don't think I'm doing anything wrong, and they work while the application is running; however, when the application closes and everything terminates, it seems that about a third of the time it will double-free something and seg fault. I'm writing and building on a linux system, and there doesn't seem to be any problems with anything but these sizers.
I did have many more windows within the HomeFrame class before I stripped it to search for bugs, but the code below still causes the double-free:
I've also looked around StackOverflow and other code forums to see if anyone was having a similar issue, but I couldn't find anything. I'm thinking that it may have something to do with the way I'm storing the sizer pointers in the class as members?
HomeFrame.h:
#pragma once
#include <wx/frame.h>
#include <wx/sizer.h>
namespace qzrgui
{
class HomeFrame: public wxFrame
{
public:
HomeFrame();
~HomeFrame();
private:
// Sizers
wxBoxSizer* _topSizer;
wxBoxSizer* _leftSizer;
wxBoxSizer* _rightSizer;
// Functions
void _setup();
void _createWindows();
};
}
HomeFrame.cpp:
#include "HomeFrame.h"
namespace qzrgui
{
HomeFrame::HomeFrame() :
wxFrame(nullptr, wxID_ANY, "Quizzer")
{
_setup();
}
HomeFrame::~HomeFrame()
{
}
void HomeFrame::_createWindows()
{
// Create sizers.
_topSizer = new wxBoxSizer(wxOrientation::wxHORIZONTAL);
_leftSizer = new wxBoxSizer(wxOrientation::wxVERTICAL);
_rightSizer = new wxBoxSizer(wxOrientation::wxVERTICAL);
}
void HomeFrame::_setup()
{
_createWindows();
}
}
Quizzer.h (wxApp base class):
#pragma once
#include <wx/app.h>
namespace qzrgui
{
class Quizzer : public wxApp
{
public:
virtual bool OnInit();
};
};
Quizzer.cpp:
#include "Quizzer.h"
wxIMPLEMENT_APP(qzrgui::Quizzer);
#include "frames/HomeFrame.h"
namespace qzrgui
{
bool Quizzer::OnInit()
{
wxFrame* frame = new HomeFrame();
frame->Show(true);
return true;
}
}

There is nothing in the code shown here which could result in a crash. You do definitely have (three) memory leak(s) in your code, as you create 3 sizers not associated with any window or another sizer and never delete them, but, while wrong, this can't result in a crash.
There is also not enough information to diagnose what you're seeing. As always with a crash, please build your code with debug information and run it under debugger to see what exactly happens. If you're under a Unix-like system (or even under MSW with the latest MSVS 2019 version), you should also compile with address sanitizer enabled to find the real problem before the crash happens.

Related

How can I allow singleton constructor re-entry/pass-over in VS2017?

I've been porting some c++ app from Visual Studio 2013 to Visual Studio 2017. Aside from the plethora of new warnings that I had to fix, the compilation and linking went okay.
However, when running the app, it 'stalled' when trying to re-enter the constructor of a singleton (when successive function calls form a loop back to the constructor). It seems that this behaviour was okay in VS2013, but is no longer valid in VS2017. There is no error message.
I'm aware of all the bad things related to singletons, and that there should at least not be loops. The question is not there.
Is there a way to tell the VS2017 compiler that I'd like to shoot myself in the foot, and allow the same behaviour that was there in VS2013?
I don't have access to the code that causes this behaviour because it comes from a third-party library, this is why I can't 'just fix it', unfortunately.
Here is an example which works in VS2013, but doesn't work in VS2017:
main.cpp
#include "Singleton.h";
int
main( void )
{
std::cout << "let's do this!" << std::endl;
int two = Singleton::GetReference().getTwo();
std::cout << "ok" << std::endl;
return 0;
}
Singleton.h
#pragma once
class Stuff;
class Singleton
{
public:
static Singleton& GetReference();
int getTwo() { return 2; }
private:
Singleton();
Stuff* stuff;
};
Singleton.cpp
#include "Singleton.h"
#include "Stuff.h"
Singleton&
Singleton::GetReference() {
static Singleton theInstance;
return theInstance;
}
Singleton::Singleton()
{
stuff = new Stuff();
}
Stuff.h
#pragma once
class Stuff
{
public:
Stuff();
private:
int two;
};
Stuff.cpp
#include "Stuff.h"
#include "Singleton.h"
Stuff::Stuff()
{
two = Singleton::GetReference().getTwo();
}
In the code above, when step-by-step debugging, the first time we get on the line static Singleton theInstance; will work as expected, but the second time, a F11 will go to the file thread_safe_statics.cpp, into the method extern "C" void __cdecl _Init_thread_header(int* const pOnce). A Shift+F11 will exit the method and the program will wait indefinitely at the line specified (observed when pausing the program from the debugger).
PS
This issue probably occurs in Visual Studio 2015 too, as the documentation linked from the accepted answer mentions VS2015.
/Zc:threadSafeInit-
The general "Conformance" page is MSDN: Conformance, which details which new features you can disable.
I needed the code for sizedDealloc, where my new compiler was creating a sized new operator for a library which broke older compiled expectations.
As this is a compile flag, at least some of the code would be in your control, and you should be able to unravel the beast.
The constructor Stuff::Stuff is calling a function on an incompletely constructed object.
That would create "Undefined behavior". If the value "2" is not set till the end of the constructor (for example).
Probably the Singleton needs to be split into 2, one which delivers the early static data (e.g. 2).
The second which delivers the held object Stuff. Stuff would only rely on the first, which would break the deadlock.
Alternatively, a second constructor to Stuff which told it which object to use, and was called from the Singleton::Singleton
The MSDN article to disable "Magic Statics" MSDN : disable threadsafe static initialization

Plugins using Pluma

Overview
I am trying to develop a C++ application which allows for user-created plugins.
I found a nice library called Pluma (http://pluma-framework.sourceforge.net/) which functionally seems to be exactly what I want.
After going through their tutorial, I was able to (with a bit of difficulty) convince the plugin to compile. However, it refuses to play nice and connect with the main program; returning various errors depending on how I try to implement them.
Problem
If I comment out the line labeled 'Main problem line' (in the last file, main.cpp), the plugin compiles successfully, and the main app can recognize it, but it says that "Nothing registered by plugin 'libRNCypher'", and none of the functions can be called.
If I compile that line, the main application instead says "Failed to load library 'Plugins/libRNCypher.so'. OS returned error: 'Plugins/libRNCypher.so: undefined symbol: _ZTIN5pluma8ProviderE".
My guess is that it has something to do with the way the plugin was compiled, as compiling it initially did not work and Code::Blocks told me to compile with "-fPIC" as a flag (doing so made it compile).
Code
Code below:
Main.cpp
#include "Pluma/Pluma.hpp"
#include "CryptoBase.h"
int main()
{
pluma::Pluma manager;
manager.acceptProviderType< CryptoBaseProvider >();
manager.loadFromFolder("Plugins", true);
std::vector<CryptoBaseProvider*> providers;
manager.getProviders(providers);
return 0;
}
CryptoBase.h
#ifndef CRYPTOBASE_H_INCLUDED
#define CRYPTOBASE_H_INCLUDED
#include "Pluma/Pluma.hpp"
#include <string>
#include <vector>
#include <bitset>
//Base class from which all crypto plug-ins will derive
class CryptoBase
{
public:
CryptoBase();
~CryptoBase();
virtual std::string GetCypherName() const = 0;
virtual std::vector<std::string> GetCryptoRecApps() const = 0;
virtual void HandleData(std::vector< std::bitset<8> > _data) const = 0;
};
PLUMA_PROVIDER_HEADER(CryptoBase)
#endif // CRYPTOBASE_H_INCLUDED
RNCypher.h (This is part of the plugin)
#ifndef RNCYPHER_H_INCLUDED
#define RNCYPHER_H_INCLUDED
#include <string>
#include <vector>
#include <bitset>
#include "../Encoder/Pluma/Pluma.hpp"
#include "../Encoder/CryptoBase.h"
class RNCypher : public CryptoBase
{
public:
std::string GetCypherName() const
{
return "RNCypher";
}
std::vector<std::string> GetCryptoRecApps() const
{
std::vector<std::string> vec;
vec.push_back("Storage");
return vec;
}
void HandleData(std::vector< std::bitset<8> > _data) const
{
char letter = 'v';
_data.clear();
_data.push_back(std::bitset<8>(letter));
return;
}
};
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase);
#endif // RNCYPHER_H_INCLUDED
main.cpp (This is part of the plugin)
#include "../Encoder/Pluma/Connector.hpp"
#include "RNCypher.h"
PLUMA_CONNECTOR
bool connect(pluma::Host& host)
{
host.add( new RNCypherProvider() ); //<- Main problem line
return true;
}
Additional Details
I'm compiling on Ubuntu 16.04, using Code::Blocks 16.01.
The second error message seems to not come from Pluma itself, but a file I also had to link, #include <dlfcn.h> (which might be a Linux file?).
I would prefer to use an existing library rather than write my own code as I would like this to be cross-platform. I am, however, open to any suggestions.
Sorry for all of the code, but I believe this is enough to reproduce the error that I am having.
Thank You
Thank you for taking the time to read this, and thank you in advance for your help!
All the best, and happy holidays!
I was not able to reproduce your problem, however looking at
http://pluma-framework.sourceforge.net/documentation/index.htm,
I've noticed that:
in your RNCypher.h file you miss something like
PLUMA_INHERIT_PROVIDER(RNCypher, CryptoBase)
it seems also that there's no file CryptoBase.cpp containing something like
#include "CryptoBase.h"
PLUMA_PROVIDER_SOURCE(CryptoBase, 1, 1);
finally, in CryptoBase.h I would declare a virtual destructor (see Why should I declare a virtual destructor for an abstract class in C++?) and provide a definition to it, while you should not declare a default constructor without providing a definition to it (see for instance Is it correct to use declaration only for empty private constructors in C++?); of course the last consideration is valid unless there's another file in which you have provided such definitions.

Change wxWidgets LogLevel

I'm failing to change the LogLevel of the wxLog functionalities.
What I would like to achieve: Log everything to a log-file.
In the following sample code logging basically works, but I see only messages with a LogLevel of Warning or Error. I thought that settting a logLevel using wxLog::SetLogLevel(wxLOG_Info); should be enough, but obviously I'm missing something. Any hints?
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/stdpaths.h>
class TestApp : public wxApp
{
public:
virtual bool OnInit();
private:
FILE* m_pLogFile;
};
bool TestApp::OnInit()
{
m_pLogFile = fopen("c:\\tmp\\foo.txt", "a+");
if (m_pLogFile == NULL)
{
return false;
}
wxLogStderr* pFileLogger = new wxLogStderr(m_pLogFile);
delete wxLog::SetActiveTarget(pFileLogger);
wxLog::SetLogLevel(wxLOG_Info);
wxLogError(L"Error");
wxLogWarning(L"Warning");
wxLogInfo(L"Info");
wxLogVerbose(L"Verbose");
wxLogDebug(L"Debug");
wxFrame* pFrame = new wxFrame(NULL, wxID_ANY, L"Title");
pFrame->Show();
return true;
}
wxIMPLEMENT_APP(TestApp);
Due to unfortunate historical reasons wxLogInfo() is actually exactly the same as wxLogVerbose() and for equally unfortunate backwards compatibility reasons, verbose logging must be enabled by explicitly calling wxLog::SetVerbose(true), so without it neither "Info" nor "Verbose" are logged (and with it both would be).
Actually we probably should finally fix this in wxWidgets 3.2, so hopefully it won't work like this in the next version. But for now you need to call SetVerbose() to enable these messages in addition to setting the log level.

Cocos2d-x 3.7 C++ CCLoad UIPageView crashing

This happens on all platforms but this description is for iPhone 5s 8.4 simulator, through the Xcode.
I have been working on the game using C++ and cocos2d-x version 3.6 and Cocostudio 2.3.1. All was fine until i updated to the official release of cocos 3.7. App started getting crashes. One of those is particularly interesting regarding UIPageView. So my header and cpp files are like that:
MKEpochSelectionScene.h
#include "cocos2d.h"
#include "cocos-ext.h"
#include <cocos/ui/CocosGUI.h>
class MKEpochSelectionScene : public cocos2d::Scene {
public:
bool init();
CREATE_FUNC(MKEpochSelectionScene);
private:
cocos2d::ui::PageView * mainPageView;
void previousEpoch(Ref* pSender, cocos2d::ui::Widget::TouchEventType eEventType);
void nextEpoch(Ref* pSender, cocos2d::ui::Widget::TouchEventType eEventType);
void showEpoch(Ref* pSender, cocos2d::ui::Widget::TouchEventType eEventType);
};
MKEpochSelectionScene.cpp
#include "MKEpochSelectionScene.h"
#include <editor-support/cocostudio/CocoStudio.h>
#include "MKGameScene.h"
#include "MKLevelSelectionScene.h"
USING_NS_CC;
bool MKEpochSelectionScene::init()
{
if(!Scene::init()) return false;
auto node = CSLoader::createNode("UI/Epoch/Layer.csb");
this->addChild(node);
auto buttonLeft = node->getChildByName<ui::Button *>("Button_Left");
CCASSERT(buttonLeft != nullptr, "Button left is null");
buttonLeft->addTouchEventListener(CC_CALLBACK_2(MKEpochSelectionScene::nextEpoch,this));
auto buttonRight = node->getChildByName<ui::Button *>("Button_Right");
CCASSERT(buttonRight != nullptr, "Button right is null");
buttonRight->addTouchEventListener(CC_CALLBACK_2(MKEpochSelectionScene::previousEpoch,this));
//******CRASHING LINE
mainPageView = (cocos2d::ui::PageView *)node->getChildByName("selectEpoch");
//******CRASHING LINE
CCASSERT(mainPageView != nullptr, "Main pageview is nil");
CCASSERT(mainPageView->getPages().size() > 0, "Page view has zero pages");
return true;
}
//Other methods
//....
}
Sooo.... The thing happens with the mainPageView. Crash occurs on the line where i reference UIPageView from the design file and assign it to the mainPageView ivar. Crash does not say anything, but crashes in the NavMesh file at the following:
So it crashes when i try to pushscene as to switch to this scene from mainMenu. There is one more thing... If i use local variable like: auto mainPageView instead of ivar in the init() method, it does not crash. And if i comment the UIPageView referencing at all e.g. crashing line - it does not crash.
What i have tried: Updated Cocostudio to 2.3.1.1 which is the latest. Republished all of the UI using that new version. Cleaned all caches and stuff of the build. Updates to the new cocos engine version by creating new project with the new version and copying over files from the old version and importing into the project. This is just to say that i have tried several things.
Any help would be appreciated. And i am sure this might be a silly mistake of mine...
Cheers!
I think you are triggering this bug:
https://github.com/cocos2d/cocos2d-x/issues/12962
It is going to fixed in v3.7.1

wxWidgets Seg fault on close

My files look something like so:
main.cpp
...
bool SyncApp::OnInit(){
SetTopWindow(new syncWindow(_("(S)FTP Automatic Sync")));
GetTopWindow()->Show(true);
return true;
}
...
syncwindow.h
#include <wx/wx.h>
class syncWindow : public wxFrame {
public:
syncWindow(wxString title) : wxFrame(NULL, -1, title) { initialize(); }
private:
void initialize();
wxTextCtrl * serverEntry;
};
syncwindow.cpp
void syncWindow::initialize(){
serverEntry = new wxTextCtrl(this, wxID_ANY);
this->AddChild(serverEntry);
}
For whatever reason whenever I close the window I get a segfault. If I don't add the serverEntry as a child to the window I don't get a segfault. I don't see why this is doing such a thing. I'm on CentOS 6, g++ 4.7 and wxGTK 2.8. Does anyone have any idea or a hint as to why this is happening?
Since you specified the parent window when constructing your child, the link is already present and calling this->AddChild(serverEntry); will cause double free or similar error when you close the window. http://docs.wxwidgets.org/2.8/wx_wxwindow.html#wxwindowaddchild
wxWindow::AddChild
Adds a child window. This is called automatically by window creation
functions so should not be required by the application programmer.
Notice that this function is mostly internal to wxWidgets and
shouldn't be called by the user code.