I am trying to implement QSettings in an editor of mine. I am trying to implement it for font changes. However, whenever I start up my program it exits immediately.
Here's my code:
When I change the font in my font box.
void SquareIDE::on_fontBox_currentFontChanged(const QFont &f)
{
ui->fontBox->setFont(f);
ui->textEdit->setMarginsFont(f);
lexer1->setFont(f);
settings.setValue("font", f);
}
On start up when it loads the settings.
void SquareIDE::loadSettings()
{
dee = settings.value("dee", true).toBool();
autosave = settings.value("autosave", true).toBool();
font = settings.value("font", f).toString();
QFont font1 = font;
if (dee == true) {
ui->dee->setChecked(true);
}
if (autosave == true) {
ui->autosave->setChecked(true);
}
ui->fontBox->setCurrentFont(font1);
}
Debugger Output:
Function: _ZN9SquareIDE29on_fontBox_currentFontChangedERK5QFont
0x4099ce <+0x004e> add %al,(%rax)
0x4099d0 <+0x0050> mov 0x90(%rbx),%rdi
0x4099d7 <+0x0057> mov $0xffffffff,%edx
0x4099dc <+0x005c> mov %rbp,%rsi
0x4099df <+0x005f> mov (%rdi),%rax
0x4099e2 <+0x0062> callq *0x150(%rax)
0x4099e8 <+0x0068> mov %rbp,%rsi
0x4099eb <+0x006b> mov %r12,%rdi
0x4099ee <+0x006e> callq 0x406020 <_ZNK5QFontcv8QVariantEv#plt>
0x4099f3 <+0x0073> lea 0x8a7b(%rip),%rdi # 0x412475
0x4099fa <+0x007a> mov $0x4,%esi
0x4099ff <+0x007f> callq 0x405c70 <_ZN7QString16fromAscii_helperEPKci#plt>
0x409a04 <+0x0084> lea 0x98(%rbx),%rdi
0x409a0b <+0x008b> mov %r12,%rdx
0x409a0e <+0x008e> mov %rsp,%rsi
0x409a11 <+0x0091> mov %rax,(%rsp)
0x409a15 <+0x0095> mov %rsp,%rbp
0x409a18 <+0x0098> callq 0x406430 <_ZN9QSettings8setValueERK7QStringRK8QVariant#plt>
0x409a1d <+0x009d> mov (%rsp),%rdi
0x409a21 <+0x00a1> mov (%rdi),%eax
0x409a23 <+0x00a3> test %eax,%eax
0x409a25 <+0x00a5> jne 0x409a60 <_ZN9SquareIDE29on_fontBox_currentFontChangedERK5QFont+224>
0x409a27 <+0x00a7> mov $0x8,%edx
0x409a2c <+0x00ac> mov $0x2,%esi
0x409a31 <+0x00b1> callq 0x406250 <_ZN10QArrayData10deallocateEPS_mm#plt>
0x409a36 <+0x00b6> mov %r12,%rdi
0x409a39 <+0x00b9> callq 0x405cd0 <_ZN8QVariantD1Ev#plt>
0x409a3e <+0x00be> mov 0x28(%rsp),%rax
0x409a43 <+0x00c3> xor %fs:0x28,%rax
See when I comment out the new QSettings code:
void SquareIDE::loadSettings()
{
dee = settings.value("dee", true).toBool();
autosave = settings.value("autosave", true).toBool();
//font = settings.value("font", f).toString();
//QFont font1 = font;
if (dee == true) {
ui->dee->setChecked(true);
}
if (autosave == true) {
ui->autosave->setChecked(true);
}
//ui->fontBox->setCurrentFont(font1);
}
I compiles and runs fine.
QFont f can be used outside the function because it was also defined in squareide.h
private:
...
QFont f;
You seem to have infinite recursion - in your fontBox currentFontChanged slot, you change the font, which will cause the event to run again:
void SquareIDE::on_fontBox_currentFontChanged(const QFont &f)
{
ui->fontBox->setFont(f);
You don't need that line.
And your stack trace, almost useless as it is, shows the crash is occurring inside the currentFontChanged slot on the line
settings.setValue("font", a);
What is a? It is used in your code in several places but not declared in what you posted. Appears to be an invalid variant at the time of that setValue() call.
The program seemed to have a problem with this one line:
lexer1->setFont(f);
So, I figured I would make it so that way every time the lexer was changed I would make it so the lexer automatically sets its font to the font set in the font combo box like so:
void SquareIDE::on_comboBox_currentIndexChanged(QString i)
{
if (i=="JavaScript") {
QsciLexer *lexer1(new QsciLexerJavaScript);
lexer1->setFont(ui->fontBox->currentFont());
}
if (i=="HTML") {
QsciLexer *lexer1(new QsciLexerHTML);
lexer1->setFont(ui->fontBox->currentFont());
}
if (i=="SquareScript") {
QsciLexer *lexer1(new QsciLexerJavaScript);
lexer1->setFont(ui->fontBox->currentFont());
QsciAPIs *api = new QsciAPIs(lexer1);
api->add("clear");
api->add("canvas");
api->add("stroke");
api->add("fill");
api->add("noStroke");
api->add("noFill");
api->add("rect");
api->add("triangle");
api->add("circle");
api->add("arc");
api->add("font");
api->add("text");
api->add("h1");
api->add("h2");
api->add("h3");
api->add("h4");
api->add("h5");
api->add("h6");
api->add("p");
api->add("title");
api->add("video");
api->add("mute");
api->add("controls");
api->add("preload");
api->add("autoplay");
api->add("audio");
api->add("loop");
api->prepare();
ui->textEdit->setLexer(lexer1);
}
}
Then I was able to call this function on the font change:
void SquareIDE::on_fontBox_currentFontChanged(const QFont &f)
{
this->setFont(f);
ui->fontBox->setFont(f);
ui->textEdit->setMarginsFont(f);
settings.setValue("font", f);
on_comboBox_currentIndexChanged(ui->comboBox->currentText());
}
This completely solved my problem.
Related
I have a scenario where in some cases when opengl32.setPixelFormat is called it then call _wglDescribePixelFormat ( which is exported function ) which then calls further in the call stack ComputeBitsFromMasks and finally _MaskToBitsAndShift.
The _MaskToBitsAndShift function remains in the loop and never finishes, causing hanging the whole app. Callstack is
opengl32.dll!_MaskToBitsAndShift#12
opengl32.dll!ComputeBitsFromMasks
opengl32.dll!___wglGetBitfieldColorFormat#16
opengl32.dll!_InternalDescribePixelFormat#40
opengl32.dll!_wglDescribePixelFormat#16
opengl32.dll!_wglSetPixelFormat#12
gdi32full.dll!_SetPixelFormat#12
Unmanaged.dll!CGLContext::CreateOffScreenContext
Unmanaged.dll!Shared::Generate3DImages
Decoding the _MaskToBitsAndShift method from asm to c becomes like this.
Asm code
opengl32!MaskToBitsAndShift:
6da7d6f2 8bff mov edi,edi
6da7d6f4 55 push ebp
6da7d6f5 8bec mov ebp,esp
6da7d6f7 56 push esi
6da7d6f8 8b7508 mov esi,dword ptr [ebp+8]
6da7d6fb 33c0 xor eax,eax
6da7d6fd 40 inc eax – initialize eax to 1, used to find highest set bit in the mask
6da7d6fe c60200 mov byte ptr [edx],0
6da7d701 c60600 mov byte ptr [esi],0
6da7d704 84c8 test al,cl
6da7d706 7508 jne opengl32!MaskToBitsAndShift+0x1e (6da7d710)
6da7d708 03c0 add eax,eax – shifts eax (the bit) left
6da7d70a fe06 inc byte ptr [esi] – increases shift count
6da7d70c 85c1 test ecx,eax – ecx is the mask, first param to this function apparently
– and this is the problem. if ecx or mask is 0, test ecx,eax will never set the flag for je to fail, hence infinite loop
6da7d70e 74f8 je opengl32!MaskToBitsAndShift+0x16 (6da7d708)
6da7d710 5e pop esi
6da7d711 eb04 jmp opengl32!MaskToBitsAndShift+0x25 (6da7d717)
6da7d713 03c0 add eax,eax
6da7d715 fe02 inc byte ptr [edx]
6da7d717 85c1 test ecx,eax
6da7d719 75f8 jne opengl32!MaskToBitsAndShift+0x21 (6da7d713)
6da7d71b 5d pop ebp
6da7d71c c20400 ret 4
Equivalant c++ code
void stdcall MaskToBitsAndShift(DWORD mask, BYTE* shiftCount, BYTE* bitCount)
{
// literal translation from asm; could be safer using bittest intrinsics or counted bits but no big deal
DWORD bit = 1;
*shiftCount = 0;
*bitCount = 0;
while (!(mask & bit))
{ *shiftCount += 1; bit <<= 1; }
while (mask & bit)
{ *bitCount += 1; bit <<= 1; }
}
If we notice the mask if 0, the loop will never end.
I cannot hook this function because it is not exported.
Any idea about working around it ? or rewriting the _wglDescribePixelFormat method which is exported but I have no idea how to tranlate that.
The initial call to the setPixelFormat is
bool CGLContext::CreateOffScreenContext(int nWidth, int nHeight, CString* pstrLog /*=NULL*/)
{
if(pstrLog)
pstrLog->Append("Creating Off Screen Context\r\n");
m_eContextType = CONTEXT_TYPE_OFFSCREEN;
// Create a new Device Context
m_pDC = new CDC;
m_pDC->CreateCompatibleDC(NULL);
// Initialize all of the compenents used to select a pixel format
memset(&m_PixelFormatDescriptor, 0, sizeof(m_PixelFormatDescriptor));
m_PixelFormatDescriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
m_PixelFormatDescriptor.nVersion = 1;
m_PixelFormatDescriptor.dwFlags = PFD_DRAW_TO_BITMAP|PFD_SUPPORT_OPENGL|PFD_SUPPORT_GDI;
m_PixelFormatDescriptor.iPixelType = PFD_TYPE_RGBA;
m_PixelFormatDescriptor.cColorBits = 0;
m_PixelFormatDescriptor.cDepthBits = 0;
m_PixelFormatDescriptor.cAccumBits = 0;
m_PixelFormatDescriptor.cStencilBits = 0;
m_PixelFormatDescriptor.cAuxBuffers = 0;
m_PixelFormatDescriptor.iLayerType = PFD_MAIN_PLANE;
m_hDC = m_pDC->m_hDC;
int nPixelFormat = ChoosePixelFormat(m_hDC, &m_PixelFormatDescriptor);
if(nPixelFormat == 0) {
if(pstrLog)
{
CString str;
str.Format("Unable to Choose Pixel Format: %li\r\n", nPixelFormat);
pstrLog->Append(str);
pstrLog->Append(DescribePFD(m_PixelFormatDescriptor));
return false;
}
else
{
ThrowException("Unable to Choose Pixel Format");
}
}.....
I recently implemented a Builder class, but I wanted to avoid throwing exceptions. So I had an idea that I could parameterise the Builder with an array of bools representing which fields have been set. Each setter would return a new specialisation of the Builder with the corresponding field flag set. That way I could check that the right fields were set at compile time.
It turns out that complex data types as non-type template arguments is only available in C++ 20. But I experimented with it anyway.
It turns out it misbehaves in a strange way. As each new specialisation is returned, the "true" flags bunch up towards the start, as shown in this sample debug output:
- set field 4 old flags 00000 new flags 00001
- set field 2 old flags 10000 new flags 10100
- set field 0 old flags 11000 new flags 11000
- set field 3 old flags 11000 new flags 11010
- set field 1 old flags 11100 new flags 11100
Those are from the second of the two lines below. Removing the first fixes the problem, suggesting that the first instantiation is somehow affecting the second.
Fields fields1 = Builder().SetFirst(1).SetSecond(2).SetThird(3).SetFourth(4).SetFifth(5).Build();
Fields fields2 = Builder().SetFifth(5).SetThird(3).SetFirst(1).SetFourth(4).SetSecond(2).Build();
Is it supposed to do that? Is this just a subtlety of C++ 20 that I'm missing somehow, or is it a bug in gcc?
I checked this with gcc 9.3.0 and gcc 10.2.0. I also tried compiling from git, version 11.0.1 change a18ebd6c439. Command line was g++ -Wall --std=c++2a builder.cpp. They all behave the same way. I also searched in gcc's bugzilla, but couldn't find anything that looked similar.
Below are two code samples. First a version stripped back as far as I could to show the problem. The second shows more context on what I was trying to achieve. (There's a third, more realistic version, but it might be a problem to post that in public.)
#include <array>
#include <cassert>
using Flags = std::array<bool, 2>;
template<Flags flags = Flags{}>
class Builder
{
public:
Builder() {
}
auto SetFirst() {
constexpr auto new_flags = SetFieldFlag<0>();
Builder<new_flags> new_builder;
return new_builder;
}
auto SetSecond() {
constexpr auto new_flags = SetFieldFlag<1>();
Builder<new_flags> new_builder;
return new_builder;
}
Flags GetFlags() const {
return flags;
}
private:
template<int field>
static constexpr auto SetFieldFlag() {
auto new_flags = flags;
std::get<field>(new_flags) = true;
return new_flags;
}
};
int main()
{
auto flags1 = Builder().SetFirst().SetSecond().GetFlags();
assert(flags1[0]);
assert(flags1[1]);
auto flags2 = Builder().SetSecond().SetFirst().GetFlags();
assert(flags2[0]);
assert(flags2[1]);
return 0;
}
#include <iostream>
#include <array>
constexpr int NumFields = 5;
using Flags = std::array<bool, NumFields>;
using Fields = std::array<int, NumFields>;
std::ostream& operator<<(std::ostream& out, Flags flags) {
for (int i = 0; i < NumFields; ++i) {
out << flags[i];
}
return out;
}
std::ostream& operator<<(std::ostream& out, Fields fields) {
for (int i = 0; i < NumFields; ++i) {
out << (i ? ":" : "") << fields[i];
}
return out;
}
template<Flags flags = Flags{}>
class Builder
{
public:
Builder(Fields fields_in = Fields{})
: fields(fields_in) {
}
auto SetFirst(int value) {
fields.at(0) = value;
return BuilderWithField<0>();
}
auto SetSecond(int value) {
fields.at(1) = value;
return BuilderWithField<1>();
}
auto SetThird(int value) {
fields.at(2) = value;
return BuilderWithField<2>();
}
auto SetFourth(int value) {
fields.at(3) = value;
return BuilderWithField<3>();
}
auto SetFifth(int value) {
fields.at(4) = value;
return BuilderWithField<4>();
}
Fields Build() {
std::cout << " - build with flags " << flags << std::endl;
static_assert(std::get<0>(flags), "first field not set");
static_assert(std::get<1>(flags), "second field not set");
static_assert(std::get<2>(flags), "third field not set");
static_assert(std::get<3>(flags), "fourth field not set");
static_assert(std::get<4>(flags), "fifth field not set");
return fields;
}
private:
template<int field>
static constexpr auto SetFieldFlag() {
auto new_flags = flags;
std::get<field>(new_flags) = true;
return new_flags;
}
template<int field>
auto BuilderWithField() {
constexpr auto new_flags = SetFieldFlag<field>();
std::cout << " - set field " << field << " old flags " << flags << " new flags " << new_flags << std::endl;
Builder<new_flags> new_builder(fields);
return new_builder;
}
Fields fields;
};
int main()
{
Fields fields1 = Builder().SetFirst(1).SetSecond(2).SetThird(3).SetFourth(4).SetFifth(5).Build();
std::cout << fields1 << std::endl;
Fields fields2 = Builder().SetFifth(5).SetThird(3).SetFirst(1).SetFourth(4).SetSecond(2).Build();
std::cout << fields2 << std::endl;
return 0;
}
I have used https://godbolt.org/ to examine the generated code for multiple compilers and this is indeed a bug in gcc. Both clang and msvc produce correct results.
Here's the interesting part, the assembler generated for the method Builder<std::array<bool, 2ul>{}>::SetSecond() which causes the error in your shorter example. The actual code is not that important, the error can be seen by looking at the types:
Clang produces (correctly) this:
Builder<std::array<bool, 2ul>{}>::SetSecond(): # #Builder<std::array<bool, 2ul>{}>::SetSecond()
push rbp
mov rbp, rsp
sub rsp, 32
mov qword ptr [rbp - 8], rdi
mov ax, word ptr [.L__const.Builder<std::array<bool, 2ul>{}>::SetSecond().new_flags]
mov word ptr [rbp - 16], ax
lea rdi, [rbp - 24]
call Builder<std::array<bool, 2ul>{bool [2]{false, true}}>::Builder() [base object constructor]
add rsp, 32
pop rbp
ret
GCC produces (incorrectly) this:
Builder<std::array<bool, 2ul>{}>::SetSecond():
push rbp
mov rbp, rsp
push rbx
sub rsp, 40
mov QWORD PTR [rbp-40], rdi
mov WORD PTR [rbp-18], 0
mov BYTE PTR [rbp-17], 1
lea rax, [rbp-19]
mov rdi, rax
call Builder<std::array<bool, 2ul>{bool [2]{true}}>::Builder() [complete object constructor]
nop
mov eax, ebx
mov rbx, QWORD PTR [rbp-8]
leave
ret
If you compare the type of the function that gets called, you can clearly see that in gcc, SetSecond() did not set the second -- there's {true}, but should be {false, true}.
So, time to switch to clang?
My program was killed when the function "dbmSetIndex" was returned.
You can see the killed position below. (=> part)
Could you explain what happened?
(x86 intel)
0x0000000000420723 <+83>: mov rdi,r14
0x0000000000420726 <+86>: call 0x405260 <dbmSetIndex#plt>
0x000000000042072b <+91>: test eax,eax
0x000000000042072d <+93>: mov ebp,eax
=> 0x000000000042072f <+95>: mov DWORD PTR [r12],eax
0x0000000000420733 <+99>: jne 0x4207d0 <FnDBBase::SelectSecurity(s_oms_security*, char*)+256>
0x0000000000420739 <+105>: lea rsi,[rip+0x4197d] # 0x4620bd
Here is the dbmSetIndex code.
I can't find what part of this code caused this problem.
int dbmSetIndex ( dbmHandle* aHandle, const char* aTable, const char* aIndexName )
{
dbmInternalHandle* pHandle = NULL;
_TRY
{
pHandle = (dbmInternalHandle*)aHandle->mHandle;
// Water Mark가 다르면 걍 리턴해라.
if ( unlikely ( aHandle->mMark != DBM_HANDLE_MARK ) )
{
DBM_ERR ( "invalide magic number (%ld)", aHandle->mMark );
_THROW( ERR_DBM_INVALID_HANDLE );
}
if( pHandle->mRemote != NULL )
{
if( pHandle->mRemote->mSockFd > 0 )
{
_CALL( dbmRemoteSetIndex( aHandle, aTable, aIndexName ) );
_RETURN;
}
}
/****************************************
* DataObject 맵핑.
****************************************/
memset_s( &pHandle->mData, 0x00, sizeof( pHandle->mData ) );
memcpy_s ( pHandle->mData.mTableName, aTable, strlen_s ( aTable ) + 1 );
pHandle->mData.mTransType = DBM_SET_INDEX;
pHandle->mData.mUserData = (char*)aIndexName;
/****************************************
* mAct 호출.
****************************************/
_CALL( pHandle->mTrans->mAct ( pHandle ) );
}
_CATCH
{
_CATCH_ERR;
}
_FINALLY
_END
}
You provided a little bit of dissassembly which shows that the call to the function you provided returned already. The crash did not occur within the function, but afterwards:
Call of your function:
0x0000000000420726 <+86>: call 0x405260 <dbmSetIndex#plt>
Here you returned already:
0x000000000042072b <+91>: test eax,eax
The critical line is a memory access to the address stored in register r12 (write):
0x000000000042072f <+95>: mov DWORD PTR [r12],eax
Let your debugger show the registers and have a look at the content of r12. It is very likely that it is 0x0000000000000000 or a small value, thus a null pointer (or null reference), but it could contain, too, an invalid address (uninitialised pointer!).
There is little more left to tell from the information you provide, though. You will have to look at the code location where the function is called -- it must be within function FnDBBase::SelectSecurity(s_oms_security*, char*) because you jump (jne) to an offset within this function ([...] + 256). There should be an if involved (test + jne instructions) and probably some pointer assignment. Possibly something like this:
SomeClass* s = [...];
s->someMember = dbmSetIndex([...]); // (*)
if(*s->someMember)
(*): Failure location, error happened during assignment after the function completed already. Don't count 100% on finding such an assignment, it could be, too, a call to an inlined setter function.
And here we see, too, why r12 is not necessarily 0: it would contain the precalculated offset of someMember within SomeClass, i. e. &(s->someMember) which could well be, if s is 0, e. g. 16, 28, ... Precisely, the value contained then is equal to offsetof(SomeClass, somemember).
Here's the code below.
void SignalView::OnFilePrintPreview()
{
if(RcursorPosX-LcursorPosX<=0){
AfxMessageBox(_T("Please set cursor positions.\nYou can only print out the area between left and right cursors"));
return;
}
CScrollView::OnFilePrintPreview();
}
BOOL SignalView::OnPreparePrinting(CPrintInfo* pInfo)
{
if(RcursorPosX-LcursorPosX>100*4*2)
RcursorPosX = LcursorPosX+100*4*2; //800 = 100 cursor x 4(gridX) x 2(zoomX)
pInfo->SetMinPage(1);
pInfo->SetMaxPage(1);
return DoPreparePrinting(pInfo); //<===========
}
void SignalView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
PRINTDLG* pPrintDlg = new PRINTDLG;
AfxGetApp()->GetPrinterDeviceDefaults(pPrintDlg);
DEVMODE* lpDevMode = (DEVMODE*)::GlobalLock(pPrintDlg->hDevMode);
lpDevMode->dmOrientation = DMORIENT_LANDSCAPE;
while(!pDC->ResetDC(lpDevMode));
::GlobalUnlock(pPrintDlg->hDevMode);
delete pPrintDlg;
}
I'm trying to use print functions. But I remade it because I deleted it and made a new class again which is derived from CScrollView, so I don't use the original view that was made from the beginning.
And now, I achieved what I want but the problem is that an error happens when I try to call and close print event OnFilePrintPreview() around 30-40 times, then it would shut down with an error message 0xC0000005.
And it happens from the function DoPreparePrinting(pInfo), and then it goes to COMMDLG_AFXCTXFUNC(BOOL ,PrintDlgW,(LPPRINTDLGW unnamed1),(unnamed1)) in afxcomctl32.inl file and then it provokes an error message.
Why does this problem happen? And does the code seem to go the right direction?
P.S.
The error happens this part in disassembly mode.
COMMDLG_AFXCTXFUNC(BOOL ,PrintDlgW,(LPPRINTDLGW unnamed1),(unnamed1))
7824CD80 mov edi,edi
7824CD82 push ebp
7824CD83 mov ebp,esp
7824CD85 mov eax,dword ptr [unnamed1]
7824CD88 push eax
7824CD89 call AfxGetModuleState (780F3320h)
7824CD8E mov ecx,dword ptr [eax+94h]
7824CD94 mov ecx,dword ptr [ecx+4]
7824CD97 call CCommDlgWrapper::_PrintDlgW (7824CDB0h)
7824CD9C pop ebp //<======= it's stopped at this point.
7824CD9D ret 4
while(!pDC->ResetDC(lpDevMode));
::GlobalUnlock(pPrintDlg->hDevMode);
This looks like trouble. If loop condition is true the first time and the second time, then there is no guarantee that it will eventually stop.
The following may not be the cause of your error, but you should try to follow these procedures in general.
When declaring new variables set them to zero, so all structure members are zero:
PRINTDLG* pPrintDlg = new PRINTDLG;
memset(pPrintDlg, 0, sizeof(pPrintDlg));
Some structures require to know the size. This has to do with Microsoft version control:
pPrintDlg->lStructSize = sizeof(PRINTDLG);
In this case you don't need to use new to allocate pPrintDlg (but it won't cause problems if you do)
You should be able to intercept the request for printing (before printer device context is created) and change to landscape mode, so Print dialog box is shown in landscape mode.
void SignalView::OnFilePrint()
{
PRINTDLG printDlg = { 0 };
printDlg.lStructSize = sizeof(PRINTDLG);
if (AfxGetApp()->GetPrinterDeviceDefaults(&printDlg))
{
if (printDlg.hDevMode)
{
DEVMODE *dm = (DEVMODE*)::GlobalLock(printDlg.hDevMode);
if (dm)
{
dm->dmFields |= DM_ORIENTATION;
dm->dmOrientation = DMORIENT_LANDSCAPE;
::GlobalUnlock(printDlg.hDevMode);
}
}
}
CScrollView::OnFilePrint();
}
Message map should look like this:
BEGIN_MESSAGE_MAP(SignalView, CScrollView)
ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, OnFilePrint)
//**************************************************
ON_COMMAND(ID_FILE_PRINT_PREVIEW, OnFilePrintPreview)
//**************************************************
END_MESSAGE_MAP()
User can change the print mode back to portrait in print dialog box. You can repeat the same code in OnBeginPrinting if you want to force landscape.
I have a problem. I spend around 5 hours trying everything, but I was not even able to reproduce it properly so I include the simplified original source code. I apologize for the extent, but I wanted to include all the relevant information I found out so far. This is one of the few times I feel completely powerless and kindly request your help. Any ideas are welcome. Also any comments that can bring at least some light to the matter. The behaviour in this case is a complete mystery to me.
I am programming in QtCreator in Ubuntu. I am trying to develop a framework to solve mathematical problems using a Population of candidate solutions, which should evolve into the true solution.
There are 3 classes involved: Population, PopulationMember and Problem:
class PopulationMember
{
QVector<Number> x_;
QVector<Number> y_;
Population* population_; EDIT: Sorry, this is a pointer
void evaluate();
friend class Population;
};
class Population
{p
public:
QList<PopulationMember*> members_; // created on the heap
Problem* problem_; // created on the heap
const Problem* readProblem() const;p
void evaluate();
void report() const;
...
};
class Problem
{
public:
void evaluate(PopulationMember&)const;
};
Usually my program runs in loops, where the population calls its various methods. One of them is Population::evaluate(). My program ran great until I introduced some new methods of Population.
for (int i = 1; i != 101; ++i)
{
Population->evaluate();
Population->someMethod1();
Population temp = Population->clone();
temp->someMethod2();
Population->append(temp);
Population->someNewMethod();
Population->someSorting();
if (i % 10 == 0)
Population->report();
}
Then I get a segmentation error in the middle of program. The strangest thing is that it happens only after the 10 loops, after the population executed report(). Also after some experimentation, when I excluded all the operations which require dynamic allocation of some sort (strings) from the report() method, I do not get the error. Conversely when I disable the sorting method (uses either std::sort or qSort) the problem stops. Also when I leave the actions done by the temp Population, there is no problem. So I started to debug the program. I let it complete 10 loops and started to debug step by step. I went into Population->evaluate();
void Population::evaluate()
{
for (Iterator it = begin(); it != end(); ++it)
{
std::cout << problem_; // debug see bellow:
(*it) -> evaluate(); // If I change to problem_->evaluate(**it); the program works.
}
}
debug:
The addres printed out is 0xbffff628. This is same as the previous 10 * population_->members_.count() printouts.
I go inside the (*it) -> evaluate(); Here I switch to assembly code:
864 (*it) -> evaluate();
0x805380c <+122>: lea -0x10(%ebp),%eax
0x805380f <+125>: mov %eax,(%esp)
0x8053812 <+128>: call 0x8055d84 <QList<PopulationMember*>::iterator::operator*() const>
0x8053817 <+133>: mov (%eax),%eax
0x8053819 <+135>: mov %eax,(%esp)
0x805381c <+138>: call 0x805ae08 <PopulationMember::evaluate()>
I go inside the call of function at the last instruction. At the instant I do this, all the attributes in problem_ become not accessible according to my debugger.
At this point all is lost.
void PopulationMember::evaluate()
{
population_ -> readProblem() -> evaluate(*this);
}
135 {
0x805ae08 <+000>: push %ebp
0x805ae09 <+001>: mov %esp,%ebp
0x805ae0b <+003>: sub $0x18,%esp
136 population_ -> readProblem() -> evaluate(*this);
0x805ae0e <+006>: mov 0x8(%ebp),%eax
0x805ae11 <+009>: mov 0x4(%eax),%eax
0x805ae14 <+012>: mov %eax,(%esp)
0x805ae17 <+015>: call 0x8051bc4 <Population::readProblem() const>
0x805ae1c <+020>: mov 0x8(%ebp),%edx
0x805ae1f <+023>: mov %edx,0x4(%esp)
0x805ae23 <+027>: mov %eax,(%esp)
0x805ae26 <+030>: call 0x804e962 <Problem::evaluate(PopulationMember&) const>
137 }
0x805ae2b <+035>: leave
0x805ae2c <+036>: ret
0x805ae2d nop
const Problem* Population::readProblem() const
{
std::cout << problem_ << std::endl; // debug see bellow:
return problem_;
}
debug:
Finally the address the problem_ is pointing at becomes 0xbffff780 instead of 0xbffff628. An increment of 344
This happens always. The increment is 344. If I make some minor changes in the program, the address changes, but the difference between these two addresses remains 344. This is all the more puzzling, since the size of all my three classes is less than 100.
The program crashes inside the void Problem::evaluate(PopulationMember&)const; method as soon as some logic is involved.
EDIT:
Population Population::clone()
{
Population temp(*this);
return temp;
}
Population::Population(const Population& population)
{
this->setProblem(population.problem_);
Population::ConstIterator cit;
for (cit = population.constBegin(); cit != population.constEnd(); ++cit)
this->addCopy(*cit);
this->ownsMembers_ = true;
}
void Population::addCopy (PopulationMember* populationMember)
{
PopulationMember *temp = new PopulationMember(*populationMember); // Memberwise
temp -> population_ = this;
members_.push_back(populationMember);
}
Population::~Population()
{
if (ownsMembers_)
foreach (PopulationMember* X, members_)
delete X;
}
void Population::append(Population& population)
{
if (population.ownsMembers_)
{
members_.append(population.members_);
population.ownsMembers_ = false;
}
else
members_.append(population.members_);
}
Population Population::clone()
{
Population temp(*this);
return temp;
}
You are copying around Population-instances quite a bit: 1. you are returning a local copy by value, 2. copying again by assigning into another local with
Population temp = Population->clone();
All these instances get pointers to PopulationMember and ownsMembers_ is always set true - this looks quite a bit fishy and you might want to debug with breakpoints in your destructors/constructors to find out the lifecycle of each population and its members.
EDIT: append method
void Population::append(Population& population)
{
if (population.ownsMembers_)
{
members_.append(population.members_);
population.ownsMembers_ = false;
}
...
This means that the members to not point to the correct Population anymore! The value of Population& is stored on stack and gets deleted after the for loop ends, but the PopulationMembers still point to these Populations.
Edit: Fix
please try this:
void Population::append(Population& population)
{
if (population.ownsMembers_)
{
for (cit = population.constBegin(); cit != population.constEnd(); ++cit)
(*cit)-> population_ = this;
population.ownsMembers_ = false;
}
members_.append(population.members_);
}