Sign in Join

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

Mailing lists / fpc-devel / 2010-06

about bug 0016668 (-gt -O2)

14 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

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

Martin
It's caused by the broken x86 behaviour of "x shl 32 = x". It does not affect in any way the correctness of code generated with -gt though, except that some variables are indeed initialised with 0 instead of with the intended trashing value.

Yes, trashing with 0 does not corrupt the code => I am aware of that.

But as I pointed out, something else does (that something else may be Lazarus or FPC). So far I have no idea what this something else could be.

There is a slight change, that correct trashing, may change the location of the error in a way that will allow it, to track the problem. Of course, it may not, it's ju7st a hope.

There is also the fact that -gt (at least if used with -O2) in some cases initializes (or zero-trashes) edx, even if edx is not used at all in the procedure
movl $0,%edx
There may be a reason for this, which I don't know?

Martin

Reply by email

Martin
to Martin
Martin wrote 5 lines
> It's caused by the broken x86 behaviour of "x shl 32 = x". It does > not affect in any way the correctness of code generated with -gt > though, except that some variables are indeed initialised with 0 > instead of with the intended trashing value.

Also out of interest. Where does the shl happen? In the compiler? Because the generated code does not conatain any shl. The generated code uses movl $0, <reg>

Reply by email

Jonas Maebe
to Martin: Also out of interest. Where does the shl happen? In the compiler? Because the generated…
Martin wrote 7 lines
On 08/06/2010 15:35, Martin wrote: >> It's caused by the broken x86 behaviour of "x shl 32 = x". It does >> not affect in any way the correctness of code generated with -gt >> though, except that some variables are indeed initialised with 0 >> instead of with the intended trashing value. > Also out of interest. Where does the shl happen? In the compiler?

Yes. On non-x86 platforms, the variables are trashed correctly.

Jonas

Reply by email

Martin
to Jonas Maebe: It can be due to an unused local variable. Jonas
Jonas Maebe wrote 11 lines
On 08 Jun 2010, at 16:35, Martin wrote: > There is also the fact that -gt (at least if used with -O2) in some > cases initializes (or zero-trashes) edx, even if edx is not used at > all in the procedure > movl $0,%edx > There may be a reason for this, which I don't know? It can be due to an unused local variable.

Here is the example again (from lcl buttons.pp)

According to the comments on top, there is nothing in edx (and the " movl $0,%edx " is only present if compiled with -gt).

That is, of course the local var, that would have gone into edx, may have been optimized away:
- The part of the compiler writing the comments, may have been aware of that
- -gt may not have been aware of that

I don't know, if edx needs to be saved on the stack, if it is used by the method? I have seen that other registers are usually saved on the stack, before they get used?
In the case below edx does not get saved.

.section .text.n_buttons_getlcldefaultbtnglyph$tbitbtnkind$$tgraphic .balign 16,0x90
.balign 16,0x90
.globl BUTTONS_GETLCLDEFAULTBTNGLYPH$TBITBTNKIND$$TGRAPHIC BUTTONS_GETLCLDEFAULTBTNGLYPH$TBITBTNKIND$$TGRAPHIC: .Lc1:
# Temps allocated between esp+0 and esp+0
# Var Kind located in register eax
# Var $result located in register eax
# [buttons.pp]
# [452] begin
.Ll1:
movl $0,%edx
.Ll2:
# [453] Result := GetDefaultButtonIcon(BitBtnImages[Kind]); movl TC_BUTTONS_BITBTNIMAGES(,%eax,4),%eax
call BUTTONS_GETDEFAULTBUTTONICON$LONGINT$$TCUSTOMBITMAP .Ll3:
# [454] end;
ret

Reply by email

Martin
to Jonas Maebe: Yes. On non-x86 platforms, the variables are trashed correctly. Jonas
Jonas Maebe wrote 12 lines
On 08 Jun 2010, at 16:46, Martin wrote: > On 08/06/2010 15:35, Martin wrote: >>> It's caused by the broken x86 behaviour of "x shl 32 = x". It does >>> not affect in any way the correctness of code generated with -gt >>> though, except that some variables are indeed initialised with 0 >>> instead of with the intended trashing value. >> > Also out of interest. Where does the shl happen? In the compiler? Yes. On non-x86 platforms, the variables are trashed correctly.

I understand that fixing this in the compiler may have implications, needs tests and may end up to be a lot of work...

Is there a possibility / a patch, I could fix it on my installatuon => just in order to see, if it helps tracking down the other issue?

Martin

Reply by email

Jonas Maebe
to Martin: Here is the example again (from lcl buttons.pp) According to the comments on top, there…
Martin wrote
That is, of course the local var, that would have gone into edx, may have been optimized away: - The part of the compiler writing the comments, may have been aware of that - -gt may not have been aware of that

It's the function result variable. edx isn't reused because the function result is immediately overwritten with the result of the call. At that point, the register allocator in combination with SSA changes the register allocated to the function result from edx to eax, because that is the register in which the function result has to be returned.

See also http://bugs.freepascal.org/view.php?id=7552

I don't know, if edx needs to be saved on the stack, if it is used by the method? I have seen that other registers are usually saved on the stack, before they get used?

edx does not have to be saved (and neither do eax and ecx).

Jonas

Reply by email

Martin
to Jonas Maebe
Jonas Maebe wrote 8 lines
On 08 Jun 2010, at 17:06, Martin wrote: > I understand that fixing this in the compiler may have implications, needs tests and may end up to be a lot of work... > It's not a lot of work, but I don't have time to do it today.

Not a problem, and thanks for the amount of feedback in the other mails.

Martin

Reply by email

Jonas Maebe
to Martin: Yes, trashing with 0 does not corrupt the code => I am aware of that. But as I pointed…
Martin wrote 5 lines
Yes, trashing with 0 does not corrupt the code => I am aware of that. But as I pointed out, something else does (that something else may be Lazarus or FPC). So far I have no idea what this something else could be. There is a slight change, that correct trashing, may change the location of the error in a way that will allow it, to track the problem. Of course, it may not, it's ju7st a hope.

In case the problem is triggered by initialising with 0: you can make the compiler trash all local variables etc with 0 instead of with $55555555 by compiling with -gtttt instead of with -gt (and then you can try without -O2/-Ooregvar, which will make debugging easier). For completeness: -gtt uses $AAAAAAAA and -gttt uses $EFEFEFEF. Using more t's will just wrap around.

Jonas

Reply by email

Martin
to Jonas Maebe
Jonas Maebe wrote 11 lines
On 08 Jun 2010, at 16:35, Martin wrote: > Yes, trashing with 0 does not corrupt the code => I am aware of that. > > But as I pointed out, something else does (that something else may be Lazarus or FPC). So far I have no idea what this something else could be. > > There is a slight change, that correct trashing, may change the location of the error in a way that will allow it, to track the problem. Of course, it may not, it's ju7st a hope. > In case the problem is triggered by initialising with 0: you can make the compiler trash all local variables etc with 0 instead of with $55555555 by compiling with -gtttt instead of with -gt (and then you can try without -O2/-Ooregvar, which will make debugging easier). For completeness: -gtt uses $AAAAAAAA and -gttt uses $EFEFEFEF. Using more t's will just wrap around.

Thanks, unfortunately, it didn't change much to the other problem....

I am one tiny step forward..

The SigSegV happens in fpc_ReRaise; => but the actual error must have been introduced further up.

Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc;
var
   _ExceptAddrStack : PExceptAddr;
begin
{$ifdef excdebug}
   writeln ('In reraise');
{$endif}
   _ExceptAddrStack:=ExceptAddrStack;
   If _ExceptAddrStack=Nil then
     DoUnHandledException;
   ExceptObjectStack^.refcount := 0; // <<<<<<<<<<<<<<<<<
   longjmp(_ExceptAddrStack^.Buf^,FPC_Exception);
end;

This is RTL (and compiled with -O1 => it doesn't use regvar), so I should be able to trust variables here. (I also checked the assembler view, and memory/registers...)

- ExceptObjectStack is nil => So the line marked raises a SigSegV.
- ExceptAddrStack is not nil => so DoUnHandledException was not called

The question is, any hints where to concentrate looking, in order to find out, how this can end up with a nil pointer there?

Reply by email

Martin
to Martin
Martin wrote 30 lines
I am one tiny step forward.. The SigSegV happens in fpc_ReRaise; => but the actual error must have been introduced further up. Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc; var _ExceptAddrStack : PExceptAddr; begin {$ifdef excdebug} writeln ('In reraise'); {$endif} _ExceptAddrStack:=ExceptAddrStack; If _ExceptAddrStack=Nil then DoUnHandledException; ExceptObjectStack^.refcount := 0; // <<<<<<<<<<<<<<<<< longjmp(_ExceptAddrStack^.Buf^,FPC_Exception); end; This is RTL (and compiled with -O1 => it doesn't use regvar), so I should be able to trust variables here. (I also checked the assembler view, and memory/registers...) - ExceptObjectStack is nil => So the line marked raises a SigSegV. - ExceptAddrStack is not nil => so DoUnHandledException was not called The question is, any hints where to concentrate looking, in order to find out, how this can end up with a nil pointer there?

The content of ExceptAddrStack

record TEXCEPTADDR {
BUF = $a3ef728,
NEXT = $a3ef768,
FRAMETYPE = 1}

Reply by email

Martin
to Martin

Ok, unfortunately I haven't got instruction for reproductions.

The bug does no longer happen in todays lazarus svn code. => I'll try to work out a revision where it happens. (likely laz svn 25937)

I found the fo9llowing assembler (disassembled by gdb) was generated for

mov $0x55,%al
movl $0x55555555,(%ecx)
movl $0x55555555,(%eax)

function TThemeServices.GetStockImage(StockID: LongInt; out Image, Mask:
HBitmap): Boolean;
var
   img : TBitmap;
begin

if lazarus was compiled with
-gh -g -gl -gw -godwarfsets -CX -XX -Xs -gt -O2 -OpPENTIUMM

since "al" is trashed first, and then the content of the address pointed to by eax => eax is no longer correct => some random memory is trashed.

al seems to be the result, eax must be one of the params

svn rev 15398

Martin

Martin wrote 41 lines
On 09/06/2010 18:42, Martin wrote: > > I am one tiny step forward.. > > The SigSegV happens in fpc_ReRaise; => but the actual error must have > been introduced further up. > > Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc; > var > _ExceptAddrStack : PExceptAddr; > begin > {$ifdef excdebug} > writeln ('In reraise'); > {$endif} > _ExceptAddrStack:=ExceptAddrStack; > If _ExceptAddrStack=Nil then > DoUnHandledException; > ExceptObjectStack^.refcount := 0; // <<<<<<<<<<<<<<<<< > longjmp(_ExceptAddrStack^.Buf^,FPC_Exception); > end; > > > This is RTL (and compiled with -O1 => it doesn't use regvar), so I > should be able to trust variables here. (I also checked the assembler > view, and memory/registers...) > > - ExceptObjectStack is nil => So the line marked raises a SigSegV. > - ExceptAddrStack is not nil => so DoUnHandledException was not called > > The question is, any hints where to concentrate looking, in order to > find out, how this can end up with a nil pointer there? The content of ExceptAddrStack record TEXCEPTADDR { BUF = $a3ef728, NEXT = $a3ef768, FRAMETYPE = 1} _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Martin
to Martin

compile the below code with -gt -O2 -al

and you get
# Var StockID located in register edx
# Var Image located in register ecx
# Var Mask located in register eax
# Var $self located in register eax
# Var $result located in register al
movl 8(%ebp),%eax
.Ll2:
movb $85,%al
movl $1431655765,(%ecx)
movl $1431655765,(%eax)

program project1;
{$mode objfpc}{$H+}
uses
   {$IFDEF UNIX}{$IFDEF UseCThreads}
   cthreads,
   {$ENDIF}{$ENDIF}
   Classes
   { you can add units after this };
{$R *.res}
type
TBar = class
   function foo(StockID: LongInt; out Image, Mask: Longint): Boolean;
end;
function TBar.foo(StockID: LongInt; out Image, Mask: Longint): Boolean;
begin
   Result := False;
end;
var a,b: Integer;
x:TBar;
begin
x.foo(0,a,b);
end.
Martin wrote 80 lines
Ok, unfortunately I haven't got instruction for reproductions. The bug does no longer happen in todays lazarus svn code. => I'll try to work out a revision where it happens. (likely laz svn 25937) I found the fo9llowing assembler (disassembled by gdb) was generated for mov $0x55,%al movl $0x55555555,(%ecx) movl $0x55555555,(%eax) function TThemeServices.GetStockImage(StockID: LongInt; out Image, Mask: HBitmap): Boolean; var img : TBitmap; begin if lazarus was compiled with -gh -g -gl -gw -godwarfsets -CX -XX -Xs -gt -O2 -OpPENTIUMM since "al" is trashed first, and then the content of the address pointed to by eax => eax is no longer correct => some random memory is trashed. al seems to be the result, eax must be one of the params svn rev 15398 Martin On 09/06/2010 18:44, Martin wrote: > On 09/06/2010 18:42, Martin wrote: >> >> I am one tiny step forward.. >> >> The SigSegV happens in fpc_ReRaise; => but the actual error must >> have been introduced further up. >> >> Procedure fpc_ReRaise;[Public, Alias : 'FPC_RERAISE']; compilerproc; >> var >> _ExceptAddrStack : PExceptAddr; >> begin >> {$ifdef excdebug} >> writeln ('In reraise'); >> {$endif} >> _ExceptAddrStack:=ExceptAddrStack; >> If _ExceptAddrStack=Nil then >> DoUnHandledException; >> ExceptObjectStack^.refcount := 0; // <<<<<<<<<<<<<<<<< >> longjmp(_ExceptAddrStack^.Buf^,FPC_Exception); >> end; >> >> >> This is RTL (and compiled with -O1 => it doesn't use regvar), so I >> should be able to trust variables here. (I also checked the >> assembler view, and memory/registers...) >> >> - ExceptObjectStack is nil => So the line marked raises a SigSegV. >> - ExceptAddrStack is not nil => so DoUnHandledException was not called >> >> The question is, any hints where to concentrate looking, in order to >> find out, how this can end up with a nil pointer there? > > The content of ExceptAddrStack > > record TEXCEPTADDR { > BUF = $a3ef728, > NEXT = $a3ef768, > FRAMETYPE = 1} > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-devel _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email