Recent

Author Topic: Debugger Tip  (Read 3782 times)

JimKueneman

  • Full Member
  • ***
  • Posts: 246
Debugger Tip
« on: November 02, 2013, 02:16:17 pm »
I am usually very good at finding bugs in my applications but this one has me stumped on how to even use the debugger to find it.  The app will run in XP all day long but compile and run in OSX it will crash in the first 10 seconds.  When it crashes it has a dialog:

Quote
Error
Project OPstackTest raised exception class 'External: SIGPIPE'.
At address 9575E917

It has stopped in the assembly window "GetIntlCAcheData"

If I "Show Execution Point" it has stopped here:

Code: [Select]
{------------------------------------------------------------------------------
  Method:  TCarbonControlWithEdit.SetText
  Params:  S - New text
  Returns: If the function succeeds

  Sets the text of edit control
 ------------------------------------------------------------------------------}
function TCarbonControlWithEdit.SetText(const S: String): Boolean;

...
    if OSError(
      SetControlData(ControlRef(Widget), GetEditPart, kControlEditTextCFStringTag,
        SizeOf(CFStringRef), @CFString),
      Self, SSetText, SSetData) then Exit; 

The one thing I have noticed is in this app I am trying to develop a library for a micro controller (using mikroPascal) so I am writing and testing it in Lazarus since it is easier. What this means is that I can't use pascal style strings in the library as that compiler does not support them in a Pascal way, it uses more of a C null terminated approach so I am manipulating all the strings as array of characters.  I am then assigning them into strings to show in the UI for testing.  I have noticed a few crashes over the last few days in that area of the code.  Could the compiler not be handling this correctly on OSX?  How can I tell? Anyone have any hints for what I could do?

Thanks,
Jim

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Debugger Tip
« Reply #1 on: November 02, 2013, 02:32:50 pm »
First a none debugger hint
Code: [Select]
function TCarbonControlWithEdit.SetText(const S: String): Boolean;

"const S: string" (can be dangerous, but may be harmless...>)

Look up the fpc doc. This prevents internal ref counting.

There is one case in which this can backfire (because you may without knowing it, break the documented requirements).
IF, and ONLY IF (which I do not know), this code can trigger an event, and IF in this event, you modify the variable that was passed to become "s", then s may be destroyed (because it has no refcount)
e.g.
Code: [Select]
SetText(GlobalVar); // or field in object
....
// In Event
GlobalVar := 'abc';
When the event returns, and the code is back in SetText, then "s" points to random memory.

-------------------

Debugging:

I dont know that code, so I cant give you specific tips


Check the thread and stack window. The error may be higher up in the stack (in the OS) but since there is no debug info, it will show this line in the editor.

Disable inlining, when compiling, recompile the IDE and LCL with -O-1

Set a breakpoint, soit will stop before the exception. That means you can see the data, before it happens.
If it is hin a lot, then either:
- use none stopping breakpoints and history snapshots
- find an outer stackframe, and use a 2nd breakpoint to enable the inner one

See breakpointproperties and debug-window history

you get there with F1:
http://wiki.lazarus.freepascal.org/IDE_Window:_Break_Points#Breakpoint_properties

JimKueneman

  • Full Member
  • ***
  • Posts: 246
Re: Debugger Tip
« Reply #2 on: November 02, 2013, 04:06:46 pm »
I will give it a try.  Here is a block of code where I have seen problems I can't explain:

Code: [Select]

  MAX_GRID_CONNECT_LEN = 29;

type
  TGridConnectString = array[0..MAX_GRID_CONNECT_LEN-1] of char;
  PGridConnectString = ^TGridConnectString;

// Global variable
var
  ReceiveGridConnectBuffer: TGridConnectString;                                // Needs to persist between receptions     


// *****************************************************************************
//  procedure GridConnectToMessage
//     Parameters: Message that contains the information in the GridConnect String
//                 GridConnectBuffer: array of characters to convert to a Message
//     Returns: Pointer to a GridConnectString if a complete one is available, else
//              nil.  The caller must use or copy the string before calling the
//              function again as the contents will be corrupted after that
//     Description: Takes a single character at a time and tries to create a
//                  GridConnect string from it in a statemachine
// *****************************************************************************
function GridConnectDecodeMachine(NextChar: Char): PGridConnectString;
begin
 Result := nil;
 case GridConnectReceiveState of
      GRIDCONNECT_STATE_SYNC_START :     
……
     GRIDCONNECT_STATE_SYNC_FIND_DATA :
        begin
           if NextChar = ';'then
           begin
             if (ReceiveGridConnectBufferIndex + 1) mod 2 = 0 then              // 0 index, add 1 for the actual character count, if not true the result is broken
             begin
               ReceiveGridConnectBuffer[ReceiveGridConnectBufferIndex] := ';';
               ReceiveGridConnectBuffer[ReceiveGridConnectBufferIndex + 1] := #0;
               Result := @ReceiveGridConnectBuffer;   <<<<<<<<<<<<<<<<<<<<<<Return a pointer to the global array of char <<<<<<<<<<<<<
             end;
             GridConnectReceiveState := GRIDCONNECT_STATE_SYNC_START            // Done
           end else     
     …...
end;

procedure TOPStackTestConnectionInput.Synchronizer;
var
  GridConnectStr: PGridConnectString;
  Str: string;
  i, StringLen: Integer;
begin
  for i := 1 to Length(ReceiveStr) do
  begin
    GridConnectStr := GridConnectDecodeMachine(ReceiveStr[i]); // Decode one char at a time
    if GridConnectStr <> nil then
    begin
      GridConnectStrToIncomingMessageCallback(GridConnectStr);
      StringLen := strlen(GridConnectStr^);  <<<<<<<<<  Crashed here at one point
      SetLength(Str, StringLen); <<<<<<<<<  or Crashed here at one point
      Str := GridConnectStr^; <<<<<<<<<  or Crashed here at one point
      if Assigned(Callback) then
        Callback('Received: '+GridConnectStr^+LF)
    end
  end;
end; 

 

TinyPortal © 2005-2018