Page 2 of 2 FirstFirst 12
Results 21 to 26 of 26

Thread: Preventing a Slot to be called again before it has finished running

  1. #21
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by ChrisW67 View Post
    Random thought: could this be the result of calling the DLL function using the wrong parameter passing arrangement, i.e. stdcall vs. cdecl ? If the called function clears the stack (and shouldn't) then the caller clears the stack again...
    http://stackoverflow.com/questions/3...call-and-cdecl
    This could explain the mess on the stack more than very well! In particular I had to link the dll explicitly. When you link a DLL implicitly i.e with a .lib, mixing the calling convention is not possible, but when it's linked explicitly, you have to pay attention to the calling convention. cdecl does not require the function to clear the stack, but requires the calling function to clear the stack. For stdcall the called fonction clears the stack instead not the calling function. Many user said you can mix the conventions, but I don't think it's true. Mixing them means the stack is either cleared twice (cdecl -> stdcall) or not at all (stdcall -> cdecl) which could in turn develop such a weird behavior without automatically crashing.. this is exactly what we seem to have. I'll change the calling conv. and see what it does!

  2. #22
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    I'll change the calling conv. and see what it does!
    Please report your results. It would be interesting to know if this was the source of all the problems.

  3. #23
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by ChrisW67 View Post
    Random thought: could this be the result of calling the DLL function using the wrong parameter passing arrangement, i.e. stdcall vs. cdecl ? If the called function clears the stack (and shouldn't) then the caller clears the stack again...
    http://stackoverflow.com/questions/3...call-and-cdecl
    Quote Originally Posted by d_stranz View Post
    Please report your results. It would be interesting to know if this was the source of all the problems.
    Hi d_stranz, absolutely, I answer to all the suggestions, by respect for those suggesting the issues and for the community.

    So, the code currently uses the _stdcall call convention (or __stdcall with two "_" depending on the compiler). I tried to import the dll function as _cdecl instead. It works but this doesn't do any difference, the slot is still recalled before it has "finished" exactly as before.

    So

    extern int (_stdcall * vc_operate_command)(int Handle,char * Command,char * Answer,const int TimeOut);

    was changed to

    extern int (_cdecl * vc_operate_command)(int Handle,char * Command,char * Answer,const int TimeOut);

    btw: I have seen a few posts stating you can mix cdecl vs stdcall and vice versa, like the page you gave for reference for example. Although it's true it didn't crash when I changed _sdtcall for _cdecl on the caller side, I doubt very much you can mix them up. To support this, I have read a user mixing the 2 calling conventions by error there http://cboard.cprogramming.com/c-pro...trol-loop.html this may confirm this may not crash immediately but it ends up making a great mess, so it's not true cdecl and sdtcall can be mixed up. Anyway the idea here was not to mix them but only to change the calling convention of the caller in case it was not matching the one of the callee (dll) before.

    I also tried the _fastcall convention, that is less common but we never know. This time the caller crashed immediately...

    In conclusion, the calling convention issue is a very nice idea as a cause of this trouble, supporting the idea of a messed stack, but the calling convention is apparently not the reason of the "re-entered" slot.

    PS: I say "re-entered" because it's not really re-entered or the call stack would show it, it's more subtle than that. I feel like the slot is forced to return as the dll runs it's function. So the event scheduler thinks the slot has finished running. This is perfectly possible, in assembly at least. At a much later time, the dll continue running where it stop and is like able to recover where it forced the slot return - This would mean the dll saved the whole context and stack - thus giving the impression of a re-entered slot. Just a speculation. I gotta check this now by carefully running it step by step as suggested by wysota.

    Gotta test wysota and then d_stranz suggestions now.

    Thanks!

  4. #24
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    extern int (_cdecl * vc_operate_command)(int Handle,char * Command,char * Answer,const int TimeOut);
    This looks like a possible source of stack corruption. From the names, it would appear that "Answer" is a buffer into which the DLL is going to place some reply to the command. From the calling convention, it would appear that you must allocate this buffer yourself and pass is a pointer to it. What does the documentation say about how big this buffer must be? (Or does it say anything at all?) What do the contents look like after the call? Are you sure it is a char * and not a wchar *? Do you need to clear it and set the first character to NULL ('\0') before the call? What about "Command"? Does the DLL expect this to be a NULL-terminated string?

    I'd start with the "Answer" :-) and go from there.

  5. The following user says thank you to d_stranz for this useful post:

    MattK (27th April 2012)

  6. #25
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by wysota View Post
    If you do get a double call then the only explanation I can see is that the DLL corrupts the stack somehow. I suggest you place a breakpoint on the dll function and step through execution of the code to see if it ends up calling the slot again.
    Results are very interesting:

    Qt Code:
    1. void SelectSource::updateFocusLabel() // this is a slot connected the qSlider
    2. {
    3. qDebug() << "enter";
    4. if (idx)
    5. {
    6. ; // for break point purposes...
    7. }
    8. idx++;
    9. QString cmd;
    10. cmd = QString(":focsteps %1,120").arg(qSliderFocus->value());
    11. sendCommandToCam.msg(&vc->Vcam, cmd);
    12. queue.idx--;
    13. qDebug() << "exit";
    14. }
    15.  
    16.  
    17. QString SendCommandToCam::msg(VC *Vcam, QString command) const
    18. {
    19.  
    20. int result;
    21. char answer[MAXCHAR_ANS];
    22. *answer = NULL; // clear the string
    23.  
    24. char *cmd = NULL;
    25. QByteArray cmdArr;
    26.  
    27. cmdArr = command.toAscii();
    28. cmd = (char*)cmdArr.constData();
    29. result = vc_operate_command(Vcam->Handle, cmd, answer, TIMEOUT_ANS);
    30. if (result != VC_RES_OK)
    31. { .... }
    32. ....
    33. }
    To copy to clipboard, switch view to plain text mode 

    BR @ lines: 8,11,12 + 28,29,30

    8; // now idx == 1
    (continue)
    11;
    (continue)
    28;
    (continue)
    29; // DLL call
    (continue)
    8; //now idx == 2. Note after 29, we did NOT reach 30.
    (continue)
    11;
    (continue)
    28;
    (continue)
    29;
    (continue)
    30; // now we reach 30, probably because 29 is already running and returns asap.
    (continue)
    12; // All good. Now idx == 1 again
    (continue)
    30; // note: after 12 we did NOT reach 28,29.
    (continue)
    12; // now idx is 0.

    qDebug shows:

    enter
    enter
    exit
    exit

    The trace show that the dll acts as a super return as it runs, and probably force a return for all the calls on the stack (it returns at least SendCommandToCam::msg() and then SelectSource::updateFocusLabel(), so I guess it forces a returns on the upper functions as well). This is why Qt thinks we have returned from the slot. In fact we have returned and this is also why we don't see any imbrication or recursive calls on the stack. So Qt is probably starting a new cycle on the event loop.

    Whats interesting here is the way the DLL is able force a return (that could be a bug, for example if you clear the stack and readjust the program counter so it points to a base address from which the prog can restart smoothly). But then, the DLL forces a passage from line 12 to 30 without passing by 28, 29 like to continue where it stopped before.

    A way to do that for the dll would be to run in another thread and conrol the stack of the working thread, and then clear the program counter (PC), save the Stack (eg save the stack pointer on the stack and restart a new stack from here) the first time, and then reverse everything at some point.


    Added after 24 minutes:


    Quote Originally Posted by d_stranz View Post
    This looks like a possible source of stack corruption. From the names, it would appear that "Answer" is a buffer into which the DLL is going to place some reply to the command. From the calling convention, it would appear that you must allocate this buffer yourself and pass is a pointer to it. What does the documentation say about how big this buffer must be? (Or does it say anything at all?) What do the contents look like after the call? Are you sure it is a char * and not a wchar *? Do you need to clear it and set the first character to NULL ('\0') before the call? What about "Command"? Does the DLL expect this to be a NULL-terminated string?

    I'd start with the "Answer" :-) and go from there.
    Like you and I wysota I tend to believe the dll is messing up the stack, either because of a bug or on purpose.
    So yes as shown in the previous code I posted the char*answer must be allocated. The SDK says:

    Command: The character string containing the command
    Answer: Accepts the answer from camera. The length of the answer is to be defined corresponding to the expected maximum answer length.
    "expected maximum answer length" How informative lol. So I allocated 5K by default, knowing by experience that the answer never seems longer than say 50 chars. To be sure, I allocated 500KBytes. Same behavior.

    >What do the contents look like after the call?
    I always display the content on a console after the call. It looks like a normal 20 chars string, null char terminated, that returns the command entered. It's a form of ack.

    >Are you sure it is a char * and not a wchar *?
    From the dll's SDK it's a char. From a dll analyzer, it's a char as well, so no wchar.

    >Do you need to clear it and set the first character to NULL ('\0') before the call?
    yes, always did as shown in code above.

    >What about "Command"? Does the DLL expect this to be a NULL-terminated string?
    The only info I have is the one cited above. As it's a very basic and low level dll, I assume it is a null terminated string as returned by QByteArray::constData(); To be noticed that ::constData() returns a const, hence the cast I did as "cmd = (char*)cmdArr.constData();".
    Last edited by MattK; 27th April 2012 at 23:23. Reason: changed "probably because 30 is already running" to 29

  7. #26
    Join Date
    Nov 2012
    Posts
    1
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Hello all,
    I don't know if this thread is still active, but i'd like to give some random ideas regarding such strange behaviours:

    - I often experienced kinda reentrance of slot calls if somewhere in my code is called QApplication:rocessEvents(), even if this code has no connection to the said slot. That sound logical because processEvents() should apply to the overall application event processing. The strange part is that calling processEvents() disrupts slot calls that way. Maybe you should check if such slot reentrancy does coincide with a processEvents() call.

    - regarding the dll function call, maybe you could try passing your char * argument finished with two trailing \0 ("some text\0\0") as I remember having such stack corruption on some Microsoft function which was expecting string lists packed into char* (each string being terminated by an \0 plus an additional \0 at the end of it all).

    - given the version of QT you link to, the event processing may behave differently (at least under windows). The whole event processing under windows has been refounded between Qt 4.5 and 4.6, and some annoying related issues had been fixed in Qt 4.8. It would be interesting to see if your symptom is different when linking against different Qt versions.

    I would be happy to know if someone has a final word to this strange behaviour.

    PS. forgive my English and my outrageous accent, I'm French.

Similar Threads

  1. Replies: 2
    Last Post: 26th August 2011, 08:51
  2. Replies: 3
    Last Post: 13th July 2011, 08:24
  3. Replies: 3
    Last Post: 7th April 2011, 11:09
  4. QProcess finished slot not firing
    By doggrant in forum Qt Programming
    Replies: 0
    Last Post: 10th November 2010, 13:09
  5. Replies: 0
    Last Post: 24th May 2010, 08:11

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.