Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2011-05

Access violation in SYSGETMEM_FIXED - memory corruption?

5 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

cobines

Hello.

I have been experiencing weird behaviour, usually my program crashes with a backtrace printed, sometimes simply just quits. In GDB I always catch SIGSEGV. The prevalent thing is that always at the top of the backtrace there is SYSGETMEM_FIXED:

TApplication.HandleException Access violation
Stack trace:
$0040DE82 SYSGETMEM_FIXED, line 925 of F:/devel/fpc/2.5.1/rtl/inc/heap.inc $00421F07 TFRMFILEASSOC__EDTICONFILENAMECHANGE, line 63 of ffileassoc.pas $0050B54E TCUSTOMEDIT__CHANGE, line 512 of ./include/customedit.inc $0050B4E0 TCUSTOMEDIT__TEXTCHANGED, line 505 of ./include/customedit.inc $004D780A TCONTROL__CMTEXTCHANGED, line 754 of ./include/control.inc $0040AD96 TOBJECT__DISPATCH, line 592 of
F:/devel/fpc/2.5.1/rtl/inc/objpas.inc
$004CF8BF TWINCONTROL__WNDPROC, line 5241 of ./include/wincontrol.inc $004D8128 TCONTROL__PERFORM, line 1083 of ./include/control.inc $004DDE86 TCONTROL__REALSETTEXT, line 4152 of ./include/control.inc $004D4CC2 TWINCONTROL__REALSETTEXT, line 8002 of ./include/wincontrol.inc $0050B337 TCUSTOMEDIT__REALSETTEXT, line 468 of ./include/customedit.inc $004DDFA9 TCONTROL__SETTEXT, line 4177 of ./include/control.inc $00421EB0 TFRMFILEASSOC__BTNADDNEWTYPECLICK, line 58 of ffileassoc.pas $004D9E46 TCONTROL__CLICK, line 2288 of ./include/control.inc $0050D42F TBUTTONCONTROL__CLICK, line 62 of ./include/buttoncontrol.inc $0050DA56 TCUSTOMBUTTON__CLICK, line 174 of ./include/buttons.inc $0050DFA1 TBUTTON__CLICK, line 341 of ./include/buttons.inc $0050D9D3 TCUSTOMBUTTON__EXECUTEDEFAULTACTION, line 149 of ./include/buttons.inc
$00420835 TAPPLICATION__DORETURNKEY, line 2039 of ./include/application.inc $004201B5 TAPPLICATION__CONTROLKEYUP, line 1650 of ./include/application.inc $004D0B02 TWINCONTROL__CONTROLKEYUP, line 5889 of ./include/wincontrol.inc $0050D81D TCUSTOMBUTTON__CONTROLKEYUP, line 73 of ./include/buttons.inc $004D0838 TWINCONTROL__DOREMAININGKEYUP, line 5786 of ./include/wincontrol.inc
$004D2BE7 TWINCONTROL__WMKEYUP, line 7151 of ./include/wincontrol.inc $0040AD96 TOBJECT__DISPATCH, line 592 of
F:/devel/fpc/2.5.1/rtl/inc/objpas.inc
$004CF8BF TWINCONTROL__WNDPROC, line 5241 of ./include/wincontrol.inc $00522197 DELIVERMESSAGE, line 110 of lclmessageglue.pas $004F0A9B WINDOWPROC, line 2556 of win32callback.inc $0051F44B BUTTONWNDPROC, line 1575 of win32wsstdctrls.pp $7E368734
$7E368816
$7E3689CD
$7E368A10
$004F3415 TWIN32WIDGETSET__APPPROCESSMESSAGES, line 383 of win32object.inc $0041F309 TAPPLICATION__HANDLEMESSAGE, line 1229 of ./include/application.inc $0041F72F TAPPLICATION__RUNLOOP, line 1362 of ./include/application.inc $00422163 TWIDGETSET__APPRUN, line 49 of ./include/interfacebase.inc $0041F6E5 TAPPLICATION__RUN, line 1350 of ./include/application.inc $00402B0A main, line 16 of project1.lpr

If I use ShortString instead of AnsiString (remove {$H+}) there is no crash, which leads me to believe there is something wrong with memory allocation of strings.

I have shortened the program and now it is so simple I can't find anything wrong with it.

These crashes happen on Windows XP SP3 i386. On Linux i386 no crashes. I ran with Valgrind memcheck and it didn't detect anything wrong. However when I include "cmem" unit I get this:

*** glibc detected *** ./project1: double free or corruption (fasttop): 0x09829d18 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6(+0x6aaa1)[0xb7325aa1]
/lib/i686/cmov/libc.so.6(+0x6c308)[0xb7327308]
/lib/i686/cmov/libc.so.6(cfree+0x6d)[0xb732a3bd]
./project1[0x807cdbf] <CREALLOCMEM+79>: 0x8908c483 ./project1[0x8071cd8] <REALLOCMEM+8>: 0x26b48dc3
./project1[0x808fad7] <EDTICONFILENAMECHANGE+71>: 0xe8cc458b ./project1[0x81e8f3c] <TCUSTOMEDIT__CHANGE+44>: 0xf689c3c9 ./project1[0x81e8ec7] <TCUSTOMEDIT__TEXTCHANGED+391>: 0xe85254e8 ./project1[0x819c7ba] <TCONTROL__CMTEXTCHANGED+26>: 0x748dc3c9 ./project1[0x806d3b6] <TOBJECT__DISPATCH+150>: 0xf73926eb ./project1[0x81949ce] <TWINCONTROL__WNDPROC+814>: 0xc9e05d8b ./project1[0x819d056] <TCONTROL__PERFORM+70>: 0x89ec458b ./project1[0x81a2fe2] <TCONTROL__REALSETTEXT+146>: 0xecb139e8 ./project1[0x8199cee]
./project1[0x81e8d27]
./project1[0x81a3104]
./project1[0x808fa80]
./project1[0x819ee77]
./project1[0x81ebdef]
./project1[0x81ec4cf]
./project1[0x81ec9f1]
./project1[0x81ec44f]
./project1[0x808ce2c]
./project1[0x808bf51]
./project1[0x8195b82]
./project1[0x81ec2cd]
./project1[0x81958e8]
./project1[0x8197d67]
./project1[0x806d3b6]
./project1[0x81949ce]
./project1[0x82260b9] <TQTWIDGET__DELIVERMESSAGE+121>: 0x8bfc458b ./project1[0x8222c10] <TQTWIDGET__SLOTKEY+640>: 0x0875c085 ./project1[0x8221dbc] <TQTWIDGET__EVENTFILTER+940>: 0x840cc483 /usr/local/lib/libQt4Pas.so.5(_ZN12QObject_hook11eventFilterEP7QObjectP6QEvent+0x2b)[0xb76d4ebb] /usr/lib/libQtCore.so.4(_ZN23QCoreApplicationPrivate29sendThroughObjectEventFiltersEP7QObjectP6QEvent+0x96)[0xb50af116]

So far I tried:
- Lazarus trunk + FPC trunk
- Lazarus trunk + FPC 2.4.2
- Lazarus fixes_0_9_30 + FPC 2.4.2

I have already scanned memory with memtest86 - no errors.

Could someone try it on their system?
I have attached the application. Run it and press "Add" button a few times.

Thanks.

cobines -------------- next part -------------- A non-text attachment was scrubbed... Name: fileassoc_crash.zip Type: application/zip Size: 2625 bytes Desc: not available URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110526/a0934c03/attachment-0001.zip>

Reply by email

cobines
to cobines

I have added some debugging text in two functions that set text to a control: TWinControl.RealSetText and widgetset specific TWin32WSWinControl.SetText (like in attached diff).

This is a log from execution of a program when it crashes:

TWin32WSWinControl.SetText before 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText after 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText before 00066D10 refcount=3 size=3 TWin32WSWinControl.SetText after 00066D10 refcount=3 size=3 TWinControl.RealSetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText before 0007F8A0 refcount=1 size=55 TWin32WSWinControl.SetText before 0007F8A0 refcount=1 size=55 TWin32WSWinControl.SetText after 0007F8A0 refcount=522612 size=0 TWinControl.RealSetText after 0007F8A0 refcount=522612 size=0 TWinControl.RealSetText before 00056A80 refcount=1 size=17 TWin32WSWinControl.SetText before 00056A80 refcount=1 size=17 TWin32WSWinControl.SetText after 00056A80 refcount=355076 size=0 TWinControl.RealSetText after 00056A80 refcount=355076 size=354980

In TWin32WSWinControl.SetText there is corruption of the string record (but the contents are fine).

Now, if I change
  procedure TControl.SetText(const Value: TCaption);
to
  procedure TControl.SetText(Value: TCaption);

everything is fine:

TWin32WSWinControl.SetText before 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText after 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText before 00066D10 refcount=3 size=3 TWin32WSWinControl.SetText after 00066D10 refcount=3 size=3 TWinControl.RealSetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText before 0007F8A0 refcount=2 size=55 TWin32WSWinControl.SetText before 0007F8A0 refcount=2 size=55 TWin32WSWinControl.SetText after 0007F8A0 refcount=1 size=55 TWinControl.RealSetText after 0007F8A0 refcount=1 size=55 TWinControl.RealSetText before 0007F910 refcount=2 size=53 TWin32WSWinControl.SetText before 0007F910 refcount=2 size=53 TWin32WSWinControl.SetText after 0007F910 refcount=1 size=53 TWinControl.RealSetText after 0007F910 refcount=1 size=53

cobines -------------- next part -------------- A non-text attachment was scrubbed... Name: settext_debug.diff Type: application/octet-stream Size: 1780 bytes Desc: not available URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110526/f252da44/attachment.obj>

Reply by email

Martin
to cobines

Here is what happens

procedure TfrmFileAssoc.btnAddNewTypeClick(Sender: TObject);
begin
   edtIconFileName.Text:= TExtAction(Exts.Items[0]).Icon;
end;
procedure TfrmFileAssoc.edtIconFileNameChange(Sender: TObject);
begin
   TExtAction(Exts.Items[0]).Icon := GenName; //DateTimeToStr(Now);
end;

1) btnAddNewTypeClick.
Takes the string from ExtAction(Exts.Items[0]).Icon; This string has a ref-count of 1 (not sure why it shows 2 in your debug)

2) SetText(const AValue: String)
because AValue is constant, it is not expected to change. The compiler optimizes the code, the ref-count is not increased. This does save the need to insert a hidden try-finally block, which otherwhis would be requiredm, to ensure that the refcout was decreased at the end of SetText (even if an exception occurred). Those implicit tr-finally blocks have a noticeable effect on speed.

3) Going through RealSetText, but then calling you event handler: edtIconFileNameChange

4) edtIconFileNameChange
Releases the string referred to by ExtAction(Exts.Items[0]).Icon; => memory is freed
AValue now points to freed memory => it didn't expect that the value was changed.

Since AValue points to freed memory, it will crash on the next attempt to use it.

----
This is actually part of the definition of "const" for parameters.

const does mean that you as programmer (or in this case the person who wrote it) declares that no code anywhere will change the value of this variable (which includes calling code)

As a side effect, if using code, the compiler will give you an error, if you try to modify it inside that procedure. Because the compiler can detect that, and because you promised the compiler not to do it. But the compiler expects that promise to be kept outside the given procedure too.

You code does not keep the promise, which some one else made.... Ouch.

Obviously it could be argued, the LCL should not make such promises. It's a decision to be made (and probably to be reviewed now)

cobines wrote 59 lines
I have added some debugging text in two functions that set text to a control: TWinControl.RealSetText and widgetset specific TWin32WSWinControl.SetText (like in attached diff). This is a log from execution of a program when it crashes: TWin32WSWinControl.SetText before 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText after 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText before 00066D10 refcount=3 size=3 TWin32WSWinControl.SetText after 00066D10 refcount=3 size=3 TWinControl.RealSetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText before 0007F8A0 refcount=1 size=55 TWin32WSWinControl.SetText before 0007F8A0 refcount=1 size=55 TWin32WSWinControl.SetText after 0007F8A0 refcount=522612 size=0 TWinControl.RealSetText after 0007F8A0 refcount=522612 size=0 TWinControl.RealSetText before 00056A80 refcount=1 size=17 TWin32WSWinControl.SetText before 00056A80 refcount=1 size=17 TWin32WSWinControl.SetText after 00056A80 refcount=355076 size=0 TWinControl.RealSetText after 00056A80 refcount=355076 size=354980 In TWin32WSWinControl.SetText there is corruption of the string record (but the contents are fine). Now, if I change procedure TControl.SetText(const Value: TCaption); to procedure TControl.SetText(Value: TCaption); everything is fine: TWin32WSWinControl.SetText before 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText after 0005FBD8 refcount=2 size=17 TWin32WSWinControl.SetText before 00066D10 refcount=3 size=3 TWin32WSWinControl.SetText after 00066D10 refcount=3 size=3 TWinControl.RealSetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText before 00526F18 refcount=-1 size=15 TWin32WSWinControl.SetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText after 00526F18 refcount=-1 size=15 TWinControl.RealSetText before 0007F8A0 refcount=2 size=55 TWin32WSWinControl.SetText before 0007F8A0 refcount=2 size=55 TWin32WSWinControl.SetText after 0007F8A0 refcount=1 size=55 TWinControl.RealSetText after 0007F8A0 refcount=1 size=55 TWinControl.RealSetText before 0007F910 refcount=2 size=53 TWin32WSWinControl.SetText before 0007F910 refcount=2 size=53 TWin32WSWinControl.SetText after 0007F910 refcount=1 size=53 TWinControl.RealSetText after 0007F910 refcount=1 size=53 -- cobines -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110526/750e0df4/attachment.html>

Reply by email

cobines
to Martin

2011/5/26 Martin :

Here is what happens ...

Ah, now I see. Thanks for explaining.

If I think of
edtIconFileName.Text
as

  edtIconFileName.SetText(const s);

it becomes more visible that in the trigger edtIconFileNameChange I cannot change what I am assigning.

So, from what you're saying it is enough to temporarily increase reference count before assigning to edtIconFileName.Text. If I modify the code to be like this:

procedure TfrmFileAssoc.btnAddNewTypeClick(Sender: TObject);
var
  s: String;
begin
  s := TExtAction(Exts.Items[0]).Icon;
  edtIconFileName.Text:= s;
end;

there is no crash and refcount is 2 when SetText is called. And 's' is finalized after assignment to Text.

cobines

Reply by email

Martin
to cobines
cobines wrote 11 lines
2011/5/26 Martin: > Here is what happens > ... Ah, now I see. Thanks for explaining. If I think of edtIconFileName.Text as edtIconFileName.SetText(const s); it becomes more visible that in the trigger edtIconFileNameChange I cannot change what I am assigning.

At the moment: yes.

I don't csay this is correct. That depends if this "const" was placed there knowing and intending this (side) effect. Or if it was by accident. (IMHO I assume the 2nd)

Show quoted text 14 lines
So, from what you're saying it is enough to temporarily increase reference count before assigning to edtIconFileName.Text. If I modify the code to be like this: procedure TfrmFileAssoc.btnAddNewTypeClick(Sender: TObject); var s: String; begin s := TExtAction(Exts.Items[0]).Icon; edtIconFileName.Text:= s; end; there is no crash and refcount is 2 when SetText is called. And 's' is finalized after assignment to Text.

but be aware, if you switch the optimizer on, it may optimize this away...

Reply by email