Sign in Join

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

Mailing lists / fpc-devel / 2011-12

Misterious error

16 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

José Mejuto

Hello FPC,

I'm now running:

Lazarus 0.9.31 r34428
FPC 2.7.1 i386-win32-win32/win64 r19895

With this setup something strange is happening in a project of mine, when I close the project a SIGSEGV happends in the win32callback.inc of LCL without callback stack trace and with all local variables using a base pointer of nil (gdb messages like 'window unable to read address 0x8').

This seems to have nothing in relation with fpc itself, but as soon as I do any string operation inside the procedure everything starts to work as it should. In my first test I wrote a simple "writeln(integer(@window))" before the line that crashes everything, but before the crash, the value of @window is normal.

Then I try to write 2 values so use "writeln(strtoint(window)+' '+strtoint(msg))' and suddenly everything starts to work.

I know that such operation can change the code generation and hide an error, so I simple declare a "var" section like:

var
  s: string;
begin

and remove the writeln so the only change to the code is the variable declaration and now it works.

Does anybody have an idea how can I debug this problem ? Assembler code looks the same in both cases.

To me it looks like the code is trying to free some strings or interfaces but at a point where the manager of automated types has been "disabled" so the declaration of a new ansistring "reconnects" it. Maybe it is a crazy idea but is the only one that I have now.

Best regards, José

Reply by email

Jonas Maebe
to José Mejuto
José Mejuto wrote
To me it looks like the code is trying to free some strings or interfaces but at a point where the manager of automated types has been "disabled" so the declaration of a new ansistring "reconnects" it. Maybe it is a crazy idea but is the only one that I have now.

The most likely problem is memory corruption by your program. Compiling the program with range checking (-Cr) and dynamic class type checking (-CR) can help with finding the cause. You can try using heaptrc or Dr Memory (http://dynamorio.org/drmemory.html -- in case you use this one, adding the cmem unit to your program may give more accurate diagnostics).

Jonas

Reply by email

José Mejuto
to Jonas Maebe

Hello Jonas,

you wrote
> To me it looks like the code is trying to free some strings or > interfaces but at a point where the manager of automated types has > been "disabled" so the declaration of a new ansistring "reconnects" > it. Maybe it is a crazy idea but is the only one that I have now.

JM> The most likely problem is memory corruption by your program. JM> Compiling the program with range checking (-Cr) and dynamic class JM> type checking (-CR) can help with finding the cause. You can try JM> using heaptrc or Dr Memory (http://dynamorio.org/drmemory.html -- JM> in case you use this one, adding the cmem unit to your program may JM> give more accurate diagnostics).

I had done all the tests and in fact many more, and start to manually bisect fpc to find the revision that breaks my code as 2.4.2, 2.4.4 and 2.6.0rc1 work fine.

After 2 days and around 40 fpc and LCL clean compiles :) I had found that the revision 19668 breaks the code. I was unable to synthesize a test case that shows the problem, so only my code is raising the problem constantly after that revision.

When exception is raised ebp is equal to zero and as r19668 is related to exceptions handling it makes me think again in wrongly handled automated types in some situations, in my case I suspect in interfaces.

To compile 19667 and 19668 I had to manually apply revisions 19699 and 19670 which only affects fpdoc compilation.

How can I help more to catch the problem ?

Best regards, José

Reply by email

José Mejuto
to Jonas Maebe: The most likely problem is memory corruption by your program. Compiling the program with…

Hello Jonas,

Wednesday, December 28, 2011, 2:43:16 PM, you wrote:

JM> The most likely problem is memory corruption by your program. [...]
JM> give more accurate diagnostics).

A bit more information:

Environment is win32.

The line that raises the exception is in win32callback.inc 2474:

-------------------------------------------
if (Msg=WM_CHAR) and (WParam=VK_RETURN) and
((lWinControl is TCustomCombobox) or
((lWinControl is TCustomEdit) and not (lWinControl is TCustomMemo )) )
then

      // this thing will beep, don't call defaultWindowProc
    else
      PLMsg^.Result := CallDefaultWindowProc(Window, Msg, WParam, LParam);

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

The CallDefaultWindowProc.

If I change the line to:

      try
      PLMsg^.Result := CallDefaultWindowProc(Window, Msg, WParam, LParam);
      finally
      end;

The problem dissapears.

* In the same function, if I declare an ansistring type, just the declare only, it works.

* If the "CallDefaultWindowProc" declaration is changed to stdcall it also works fine.

Best regards, José

Reply by email

Sergei Gorelkin
to José Mejuto

31.12.2011 16:58, José Mejuto пишет:

Show quoted text 39 lines
Hello Jonas, Wednesday, December 28, 2011, 2:43:16 PM, you wrote: JM> The most likely problem is memory corruption by your program. [...] JM> give more accurate diagnostics). A bit more information: Environment is win32. The line that raises the exception is in win32callback.inc 2474: ------------------------------------------- if (Msg=WM_CHAR) and (WParam=VK_RETURN) and ((lWinControl is TCustomCombobox) or ((lWinControl is TCustomEdit) and not (lWinControl is TCustomMemo )) ) then // this thing will beep, don't call defaultWindowProc else PLMsg^.Result := CallDefaultWindowProc(Window, Msg, WParam, LParam); ------------------------------------------- The CallDefaultWindowProc. If I change the line to: try PLMsg^.Result := CallDefaultWindowProc(Window, Msg, WParam, LParam); finally end; The problem dissapears. * In the same function, if I declare an ansistring type, just the declare only, it works.

When you do either of the above, it effectively disables optimizations, forcing a ebp-based stack frame and putting all variables to memory. The same effect should be achievable by compiling with -O- or -O1 switches.

* If the "CallDefaultWindowProc" declaration is changed to stdcall it also works fine.

Don't know what's actually changed in this case.

r19668 affects codegeneration of constructors and custom enumerators, and fixes http://bugs.freepascal.org/view.php?id=20827
The reported location of crash in your case is likely unrelated to the actual location of problem. At least, function WindowProc from win32callback.inc is not affected by r19668, as it isn't a constructor and doesn't involve exception handling in unmodified form. If your code contains constructors which use interfaces, I'd suggest them as the place to look at or try to modify.

Regards,
Sergei

Reply by email

José Mejuto
to Sergei Gorelkin

Hello FPC,

Saturday, December 31, 2011, 3:39:59 PM, you wrote:

SG> r19668 affects codegeneration of constructors and custom enumerators, and fixes SG> http://bugs.freepascal.org/view.php?id=20827
SG> The reported location of crash in your case is likely SG> unrelated to the actual location of problem.
SG> At least, function WindowProc from win32callback.inc is not SG> affected by r19668, as it isn't a
SG> constructor and doesn't involve exception handling in unmodified form. SG> If your code contains constructors which use interfaces, I'd SG> suggest them as the place to look at or
SG> try to modify.

Reverting this change in r19668, line 700:

          begin
            { Constructors need the destroy-on-exception code even if they don't
              use managed variables/temps. }
            //if (cs_implicit_exceptions in current_settings.moduleswitches) and
            //   (is_class(procdef.struct) and (procdef.proctypeoption=potype_constructor)) then
            //  maybe_add_constructor_wrapper(code,true)
            //else
              maybe_add_constructor_wrapper(code,false);
            addstatement(newstatement,loadpara_asmnode);

Makes everything work fine again. The if..else was added by you in
19668. Maybe a forgotten situation to generate stackframe ?

Best regards, José

Reply by email

Sergei Gorelkin
to José Mejuto

31.12.2011 18:52, José Mejuto пишет:

Show quoted text 30 lines
Hello FPC, Saturday, December 31, 2011, 3:39:59 PM, you wrote: SG> r19668 affects codegeneration of constructors and custom enumerators, and fixes SG> http://bugs.freepascal.org/view.php?id=20827 SG> The reported location of crash in your case is likely SG> unrelated to the actual location of problem. SG> At least, function WindowProc from win32callback.inc is not SG> affected by r19668, as it isn't a SG> constructor and doesn't involve exception handling in unmodified form. SG> If your code contains constructors which use interfaces, I'd SG> suggest them as the place to look at or SG> try to modify. Reverting this change in r19668, line 700: begin { Constructors need the destroy-on-exception code even if they don't use managed variables/temps. } //if (cs_implicit_exceptions in current_settings.moduleswitches) and // (is_class(procdef.struct) and (procdef.proctypeoption=potype_constructor)) then // maybe_add_constructor_wrapper(code,true) //else maybe_add_constructor_wrapper(code,false); addstatement(newstatement,loadpara_asmnode); Makes everything work fine again. The if..else was added by you in 19668. Maybe a forgotten situation to generate stackframe ?

Plain removal of this if..else breaks a couple of tests in the testsuite. But the information you provided gives some pointers to look at. At least, adding a check that constructor without pi_needs_implicit_finally flag doesn't have any implicit finalization code either will help detecting the actual place of trouble.
I'll review it.

Regards,
Sergei

Reply by email

José Mejuto
to Sergei Gorelkin

Hello FPC,

you wrote 10 lines
> //if (cs_implicit_exceptions in > current_settings.moduleswitches) and > // (is_class(procdef.struct) and > (procdef.proctypeoption=potype_constructor)) then > // maybe_add_constructor_wrapper(code,true) > //else > maybe_add_constructor_wrapper(code,false); > Makes everything work fine again. The if..else was added by you in > 19668. Maybe a forgotten situation to generate stackframe ? >

SG> Plain removal of this if..else breaks a couple of tests in SG> the testsuite. But the information you
SG> provided gives some pointers to look at. At least, adding a SG> check that constructor without
SG> pi_needs_implicit_finally flag doesn't have any implicit SG> finalization code either will help
SG> detecting the actual place of trouble.
SG> I'll review it.

I'll be very happy in test any change you may want to try before commit to SVN. This kind of problems seems to be very difficult to catch, so I'll try to not change my codebase while you investigate in order to be able to raise the error as needed.

Another hint, my problem appears at close time and only if a debugger is present. If no debugger the operative system eats the error and nothing is reported.

Happy 2012.

Best regards, José

Reply by email

Sergei Gorelkin
to José Mejuto

31.12.2011 23:17, José Mejuto пишет:

Show quoted text 17 lines
SG> Plain removal of this if..else breaks a couple of tests in SG> the testsuite. But the information you SG> provided gives some pointers to look at. At least, adding a SG> check that constructor without SG> pi_needs_implicit_finally flag doesn't have any implicit SG> finalization code either will help SG> detecting the actual place of trouble. SG> I'll review it. I'll be very happy in test any change you may want to try before commit to SVN. This kind of problems seems to be very difficult to catch, so I'll try to not change my codebase while you investigate in order to be able to raise the error as needed. Another hint, my problem appears at close time and only if a debugger is present. If no debugger the operative system eats the error and nothing is reported.

The problem appears to be that the implicit finally block in constructors does not only finalize managed variables and temps, but also reposition the exit label so 'exit' statements do not jump over the AfterConstruction call. Removing this implicit finally block, as well as compiling with {$implicitexceptions off}, breaks the correct behavior. For now, I reverted part of r19668 in r19948, so implicit finally blocks are not optimized, and added a test.
The solution to optimize the unnecessary finally blocks without breaking exit behavior is still to be found.

Regards,
Sergei

Reply by email

Sergei Gorelkin
to Sergei Gorelkin

02.01.2012 14:16, Sergei Gorelkin пишет:

Show quoted text 20 lines
31.12.2011 23:17, José Mejuto пишет: > I'll be very happy in test any change you may want to try before > commit to SVN. This kind of problems seems to be very difficult to > catch, so I'll try to not change my codebase while you investigate in > order to be able to raise the error as needed. > > Another hint, my problem appears at close time and only if a debugger > is present. If no debugger the operative system eats the error and > nothing is reported. The problem appears to be that the implicit finally block in constructors does not only finalize managed variables and temps, but also reposition the exit label so 'exit' statements do not jump over the AfterConstruction call. Removing this implicit finally block, as well as compiling with {$implicitexceptions off}, breaks the correct behavior. For now, I reverted part of r19668 in r19948, so implicit finally blocks are not optimized, and added a test. The solution to optimize the unnecessary finally blocks without breaking exit behavior is still to be found.

More sophisticated patch applied in r19955. If you can test your project with it, that would be just great.

Regards,
Sergei

Reply by email

José Mejuto
to Sergei Gorelkin

Hello FPC,

you wrote
> The solution to optimize the unnecessary finally blocks without > breaking exit behavior is still to > be found.

SG> More sophisticated patch applied in r19955. If you can test SG> your project with it, that would be just
SG> great.

I had updated to 19958 and it still fails with the same SIGSEGV. Again adding the try..finally..end in the function cures the problem.

[Updating to 19959 to test as my code uses Variants...Done]

No sorry, still the same SIGSEGV :(

Do you know which kind of code I must look for to isolate the problem ?

Best regards, José

Reply by email

Sergei Gorelkin
to José Mejuto

03.01.2012 23:54, José Mejuto пишет:

Show quoted text 21 lines
Hello FPC, Monday, January 2, 2012, 9:27:50 PM, you wrote: >> The solution to optimize the unnecessary finally blocks without >> breaking exit behavior is still to >> be found. SG> More sophisticated patch applied in r19955. If you can test SG> your project with it, that would be just SG> great. I had updated to 19958 and it still fails with the same SIGSEGV. Again adding the try..finally..end in the function cures the problem. [Updating to 19959 to test as my code uses Variants...Done] No sorry, still the same SIGSEGV :( Do you know which kind of code I must look for to isolate the problem ?

I'd suggest looking at the constructors containing an 'exit' statement, but I'm not entirely sure.

Does restoring removed line 287 of psub.pas remove the segfault? (The line was:
include(current_procinfo.flags,pi_needs_implicit_finally); )

Regards,
Sergei

Reply by email

José Mejuto
to Sergei Gorelkin

Hello FPC,

you wrote
> Do you know which kind of code I must look for to isolate the problem > ?

SG> I'd suggest looking at the constructors containing an 'exit' statement, SG> but I'm not entirely sure.
SG> Does restoring removed line 287 of psub.pas remove the segfault? SG> (The line was:
SG> include(current_procinfo.flags,pi_needs_implicit_finally); )

No, it does not :( The problem seems to happend in a destroy process, but as it only happends on close window, and in the close process a lot of objects and interfaces are destroyed I can not track each one :(

I'll try to create a minimun project that fails, it would need a firebird and zeoslib.

Best regards, José

Reply by email

Sergei Gorelkin
to José Mejuto

04.01.2012 15:58, José Mejuto пишет:

Show quoted text 17 lines
Hello FPC, Tuesday, January 3, 2012, 10:01:54 PM, you wrote: >> Do you know which kind of code I must look for to isolate the problem >> ? SG> I'd suggest looking at the constructors containing an 'exit' statement, SG> but I'm not entirely sure. SG> Does restoring removed line 287 of psub.pas remove the segfault? SG> (The line was: SG> include(current_procinfo.flags,pi_needs_implicit_finally); ) No, it does not :( The problem seems to happend in a destroy process, but as it only happends on close window, and in the close process a lot of objects and interfaces are destroyed I can not track each one :(

I was hoping otherwise... Actually it is very strange that reverting changes at line 700 (which you mentioned earlier) removes the crash, while reverting line 287 does not, because removing pi_needs_implicit_finally flag is the condition under which code at line 700 could ever execute.

I'll try to create a minimun project that fails, it would need a firebird and zeoslib.

This is of course the best thing to do.

However, you can as well try the attached simple patch. It prevents temps referenced from 'finally' blocks from being placed to registers.

Regards,
Sergei

Reply by email

Jonas Maebe
to Sergei Gorelkin
Sergei Gorelkin wrote
However, you can as well try the attached simple patch. It prevents temps referenced from 'finally' blocks from being placed to registers.

While I'm not immediately certain how that would be done in the easiest way, it would be best if that were only done for temps that are also used outside the finally block. Temps that are created and destroyed inside the finally block can remain regable without any problems.

Jonas

Reply by email

José Mejuto
to Sergei Gorelkin: 04.01.2012 15:58, José Mejuto пишет: I was hoping otherwise... Actually it is very…

Hello FPC,

Wednesday, January 4, 2012, 3:12:55 PM, you wrote:

SG> I was hoping otherwise... Actually it is very strange that SG> reverting changes at line 700 (which you
SG> mentioned earlier) removes the crash, while reverting line SG> 287 does not, because removing
SG> pi_needs_implicit_finally flag is the condition under which SG> code at line 700 could ever execute.

I'll retest everything again with clear compiles to be sure...

SG> This is of course the best thing to do.
SG> However, you can as well try the attached simple patch. It SG> prevents temps referenced from 'finally'
SG> blocks from being placed to registers.

If it still crashes I'll apply the patch and retest again.

Best regards, José

Reply by email