View Issue Details

IDProjectCategoryView StatusLast Update
0036863FPCCompilerpublic2020-04-06 21:57
ReporterDmitry Assigned ToFlorian  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformWindows 
Fixed in Version3.3.1 
Summary0036863: Placing entire object onto stack instead of using a reference
DescriptionWhen virtual method of an object is called an entire object seems to be placed onto stack causing abnormal stack eating. There is no such behaviour on FPC 3.0.4
Steps To Reproduce{$M 16384,16384}

type
  TObj = object
    v: array [0..$2000] of Byte;
    procedure Proc(depth: Integer);
    procedure VProc; virtual;
  end;

  procedure TObj.VProc;
  begin
  end;

  procedure TObj.Proc(depth: Integer);
  begin
    {stack is eaten here on the function entry}
    if (depth < 64) then
      Proc(depth+1);
    {do not actually call the method since the obj is not initialized, just for minimal demonstration}
    if (depth < 0) then
    VProc;
  end;

var
  Obj: TObj;
begin
  Obj.Proc(0);
  writeln('Completed');
end.

--
There is runtimer error 202 when compiled in Debug mode with FPC 3.2.0rc1, and there are no errors when compiled with FPC 3.0.4
TagsNo tags attached.
Fixed in Revision44598
FPCOldBugId
FPCTarget-
Attached Files

Activities

Awkward

2020-04-03 16:40

reporter   ~0121865

call virtual method without constructor? really?

Dmitry

2020-04-03 16:55

reporter   ~0121866

Using a constructor does not affect the stack eating code generated for the procedure TObj.Proc(depth: Integer);
There is a remark the code is minimized just for demonstration.

Dmitry

2020-04-05 05:43

reporter   ~0121914

Here is the dissambler for entry code of TObj.Proc(depth: Integer):

$004015A0: push %ebp
$004015A1: mov %esp,%ebp
$004015A3: lea -0x200c(%esp),%esp

On Free Pascal v 3.0.4 the entry code was the following (!takes only 8 bytes of stack instead of 0x200c):
$004015A0: push %ebp
$004015A1: mov %esp,%ebp
$004015A3: lea -0x8(%esp),%esp

I think it is a very serious bug as it affects the core of the Object Pascal.

Anton Kavalenka

2020-04-05 07:32

reporter   ~0121920

IMO it is by design, very alike C++ classes/struct on stack.
If you want use heap - use new(PObj,Create);

Dmitry

2020-04-05 08:45

reporter   ~0121923

Last edited: 2020-04-05 08:47

View 2 revisions

Allocating object in a heap _does not affect_ the entry code of TObj.Proc(depth: Integer). It still eats abnormal amount of stack on each call, every call. No matter Obj.Proc() or Obj^.Proc() is called, no matter Obj is allocated in a heap or in a stack.

Awkward

2020-04-05 10:49

reporter   ~0121926

btw, i tried your code right from this post, compiled with 3.3.1 and 3.2.0rc1 with -a key. assembler shows me lea -0x8(%esp),%esp in both cases

Florian

2020-04-05 11:28

administrator   ~0121930

I cannot reproduce it either with the information being posted. Please post the exact command line as well as the output of -l -vi when compiling. Please compile also with -al and post the assembly output.

Dmitry

2020-04-05 12:54

reporter   ~0121934

Have you compiled in Debug mode? I just checked and can see this isn't repoduced without -dDEBUG.

Dmitry

2020-04-05 13:13

reporter   ~0121936

fp.exe test.pas -dDEBUG -l -vi -al

I have modified the code slightly taking into account the comments. The entrance code has changed but stack is still eating in debug mode.

*****
{$M 16384,65536}
type
  PObj = ^TObj;
  TObj = object
    v1: array [0..$8000] of Byte;
    constructor Init;
    procedure Proc(depth: Integer);
    procedure VProc; virtual;
  end;

  constructor TObj.Init;
  begin
  end;

  procedure TObj.VProc;
  begin
  end;

  procedure TObj.Proc(depth: Integer);
  var
    _ESP: cardinal;
  begin
    asm
      movl %esp, _ESP
    end;
    writeln(depth,': ',_ESP);
    if (depth < 30) then
      Proc(depth+1);

    VProc;
  end;

var
  Obj: PObj;
begin
  Obj:= New(PObj, Init);
  Obj^.Proc(0);
  writeln('Completed');
end.

*****
The program output (debug mode):
0: 884516
1: 851708
2: 818900
3: 786092
4: 753284
5: 720476
6: 687668
Runtime error 202 at $004015D0

*****
assembly ouput fragment:

.Lf3:
    .stabn 68,0,22,.Ll6 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll6:
# [22] begin
    pushl %ebp
    movl %esp,%ebp
    pushl %edi
    movl $8,%edi
.Lj15:
    leal -4092(%esp),%esp
    pushl %eax
    subl $1,%edi
    jne .Lj15
    leal -16(%esp),%esp
    movl 32784(%esp),%edi
*****
test.pas (605 bytes)   
{$M 16384,65536}
type
  PObj = ^TObj;
  TObj = object
    v1: array [0..$8000] of Byte;
    constructor Init;
    procedure Proc(depth: Integer);
    procedure VProc; virtual;
  end;

  constructor TObj.Init;
  begin
  end;

  procedure TObj.VProc;
  begin
  end;

  procedure TObj.Proc(depth: Integer);
  var
    _ESP: cardinal;
  begin
    asm
      movl %esp, _ESP
    end;
    writeln(depth,': ',_ESP);
    if (depth < 30) then
      Proc(depth+1);

    VProc;
  end;

var
  Obj: PObj;
begin
  Obj:= New(PObj, Init);
  Obj^.Proc(0);
  writeln('Completed');
end.
test.pas (605 bytes)   
test.s (10,154 bytes)   
	.file "test.pas"
# Begin asmlist al_begin

.section .text.b_DEBUGSTART_$P$PROGRAM,"x"
	.balign 4,0x90
.globl	DEBUGSTART_$P$PROGRAM
DEBUGSTART_$P$PROGRAM:
	.stabs "W:/src/work/win32con.320/",100,0,0,.Lf5
	.stabs "test.pas",100,0,0,.Lf5
.Lf5:
# End asmlist al_begin
# Begin asmlist al_stabs

.section .data.n_PROGRAM,"d"
	.balign 4
.globl	DEBUGINFO_$P$PROGRAM
DEBUGINFO_$P$PROGRAM:
# Defs - Begin unit SYSTEM has index 1
	.stabs "void:t4=4",128,0,0,0
	.stabs "SMALLINT:t7=@s16;r7;-32768;32767;",128,0,0,0
	.stabs "LONGWORD:t8=r8;0;-1;",128,0,0,0
	.stabs "LONGBOOL:t5=-23;",128,0,0,0
# Defs - End unit SYSTEM has index 1
# Defs - Begin unit STRINGS has index 4
# Defs - End unit STRINGS has index 4
# Defs - Begin unit OBJPAS has index 6
# Defs - End unit OBJPAS has index 6
# Defs - Begin unit WINDOWS has index 5
# Defs - End unit WINDOWS has index 5
# Defs - Begin unit EXEINFO has index 3
# Defs - End unit EXEINFO has index 3
# Defs - Begin unit LINEINFO has index 2
# Defs - End unit LINEINFO has index 2
# Defs - Begin unit FPINTRES has index 7
# Defs - End unit FPINTRES has index 7
# Defs - Begin unit SYSINITPAS has index 8
# Defs - End unit SYSINITPAS has index 8
# Defs - Begin Staticsymtable
	.stabs "LONGINT:t9=r9;-2147483648;2147483647;",128,0,0,0
	.stabs "CHAR:t10=-20;",128,0,0,0
	.stabs "BYTE:t11=@s8;r11;0;255;",128,0,0,0
	.stabs "SHORTSTRING:t12=s256length:11,0,8;st:ar11;1;255;10,8,2040;;",128,0,0,0
	.stabs ":t13=*12",128,0,0,0
	.stabs "POINTER:t14=*4",128,0,0,0
	.stabs ":t15=ar9;0;0;14",128,0,0,0
	.stabs "__vtbl_ptr_type:Tt16=s2;",128,0,0,0
	.stabs "pvmt:t17=*16",128,0,0,0
	.stabs "vtblarray:t18=ar9;0;1;17",128,0,0,0
	.stabs "WORD:t19=@s16;r19;0;65535;",128,0,0,0
	.stabs ":t20=ar@s8;19;0;32768;11",128,0,0,0
	.stabs ":Tt2=s32776V1:20,0,262152;$vf2:18,262176;INIT::21=##5;:__ct__4TOBJ11unnamedtype;2A.;PROC::22=##4;:4TOBJ8SMALLINT;2A.;VPROC::23=##4;:4TOBJ;2A*0;2;;;~%2;",128,0,0,0
	.stabs "vmt_PROGRAMTOBJ:S16",40,0,0,VMT_$P$PROGRAM_$$_TOBJ
	.stabs ":t1=*2",128,0,0,0
	.stabs ":t24=*f4",128,0,0,0
	.stabs ":Tt3=s2;",128,0,0,0
# Defs - End Staticsymtable
	.stabs "pvmt:t17=*16",128,0,0,0
# Syms - Begin Staticsymtable
	.stabs "POBJ:t1",128,0,3,0
	.stabs "TOBJ:Tt2",128,0,4,0
	.stabs "vmtdef$TOBJ:Tt3",128,0,11,0
	.stabs "OBJ:S1",38,0,34,U_$P$PROGRAM_$$_OBJ
# Syms - End Staticsymtable
# End asmlist al_stabs
# Begin asmlist al_procedures

.section .text.n_p$program$_$tobj_$__$$_init$$longbool,"x"
	.balign 16,0x90
.globl	P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL:
	.stabs "TOBJ__INIT:F5",36,0,11,P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
	.stabs "vmt:R6",64,0,6,2
	.stabs "vmt:6",160,0,6,-4
	.stabs "$t:v2",160,0,0,-8
	.stabs "test.pas",132,0,0,.Lf1
.Lf1:
	.stabn 68,0,12,.Ll1 - P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
.Ll1:
# [test.pas]
# [12] begin
	pushl	%ebp
	movl	%esp,%ebp
	leal	-8(%esp),%esp
# Var $vmt located at ebp-4, size=OS_32
# Var $self located at ebp-8, size=OS_32
	movl	%eax,-8(%ebp)
	movl	%edx,-4(%ebp)
	.stabn 68,0,12,.Ll2 - P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
.Ll2:
	leal	-4(%ebp),%edx
	movl	-8(%ebp),%eax
	movl	$32772,%ecx
	call	fpc_help_constructor
	movl	%eax,-8(%ebp)
	cmpl	$0,-8(%ebp)
	je	.Lj5
	jmp	.Lj6
.Lj5:
	jmp	.Lj3
	.balign 4,0x90
.Lj6:
.Lj3:
	.stabn 68,0,13,.Ll3 - P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
.Ll3:
# [13] end;
	movl	-8(%ebp),%eax
	movl	%ebp,%esp
	popl	%ebp
	ret
	.stabn 192,0,0,0
	.stabn 224,0,0,.Lt2-P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
.Lt2:

.section .text.n_p$program$_$tobj_$__$$_vproc,"x"
	.balign 16,0x90
.globl	P$PROGRAM$_$TOBJ_$__$$_VPROC
P$PROGRAM$_$TOBJ_$__$$_VPROC:
	.stabs "TOBJ__VPROC:F4",36,0,15,P$PROGRAM$_$TOBJ_$__$$_VPROC
	.stabs "$t:v2",160,0,0,-4
	.stabs "test.pas",132,0,0,.Lf2
.Lf2:
	.stabn 68,0,16,.Ll4 - P$PROGRAM$_$TOBJ_$__$$_VPROC
.Ll4:
# [16] begin
	pushl	%ebp
	movl	%esp,%ebp
	leal	-4(%esp),%esp
# Var $self located at ebp-4, size=OS_32
	movl	%eax,-4(%ebp)
	.stabn 68,0,17,.Ll5 - P$PROGRAM$_$TOBJ_$__$$_VPROC
.Ll5:
# [17] end;
	movl	%ebp,%esp
	popl	%ebp
	ret
	.stabn 192,0,0,0
	.stabn 224,0,0,.Lt4-P$PROGRAM$_$TOBJ_$__$$_VPROC
.Lt4:

.section .text.n_p$program$_$tobj_$__$$_proc$smallint,"x"
	.balign 16,0x90
.globl	P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT:
	.stabs "TOBJ__PROC:F4",36,0,19,P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
	.stabs "DEPTH:R7",64,0,7,2
	.stabs "DEPTH:7",160,0,7,-4
	.stabs "$t:v2",160,0,0,-8
	.stabs "_ESP:8",160,0,21,-12
# Temps allocated between ebp-32788 and ebp-12
	.stabs "test.pas",132,0,0,.Lf3
.Lf3:
	.stabn 68,0,22,.Ll6 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll6:
# [22] begin
	pushl	%ebp
	movl	%esp,%ebp
	pushl	%edi
	movl	$8,%edi
.Lj15:
	leal	-4092(%esp),%esp
	pushl	%eax
	subl	$1,%edi
	jne	.Lj15
	leal	-16(%esp),%esp
	movl	32784(%esp),%edi
	pushl	%ebx
	pushl	%esi
	pushl	%edi
# Var depth located at ebp-4, size=OS_S16
# Var $self located at ebp-8, size=OS_32
# Var _ESP located at ebp-12, size=OS_32
	movl	%eax,-8(%ebp)
	movw	%dx,-4(%ebp)
#  CPU PENTIUM
	.stabn 68,0,24,.Ll7 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll7:
# [24] movl %esp, _ESP
	movl	%esp,-12(%ebp)
#  CPU PENTIUM
	.stabn 68,0,26,.Ll8 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll8:
# [26] writeln(depth,': ',_ESP);
	call	fpc_get_output
	movl	%eax,%ebx
	movswl	-4(%ebp),%ecx
	movl	%ebx,%edx
	movl	$0,%eax
	call	fpc_write_text_sint
	call	fpc_iocheck
	movl	$_$PROGRAM$_Ld1,%ecx
	movl	%ebx,%edx
	movl	$0,%eax
	call	fpc_write_text_shortstr
	call	fpc_iocheck
	movl	-12(%ebp),%ecx
	movl	%ebx,%edx
	movl	$0,%eax
	call	fpc_write_text_uint
	call	fpc_iocheck
	movl	%ebx,%eax
	call	fpc_writeln_end
	call	fpc_iocheck
	.stabn 68,0,27,.Ll9 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll9:
# [27] if (depth < 30) then
	cmpw	$30,-4(%ebp)
	jl	.Lj11
	jmp	.Lj12
.Lj11:
	.stabn 68,0,28,.Ll10 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll10:
# [28] Proc(depth+1);
	movswl	-4(%ebp),%ebx
	addl	$1,%ebx
	jno	.Lj13
	call	FPC_OVERFLOW
.Lj13:
	movl	%ebx,%eax
	subl	$-32768,%eax
	cmpl	$65535,%eax
	jbe	.Lj14
	call	fpc_rangeerror
.Lj14:
	movw	%bx,%dx
	movl	-8(%ebp),%eax
	call	P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
	.balign 4,0x90
.Lj12:
	.stabn 68,0,30,.Ll11 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll11:
# [30] VProc;
	movl	-8(%ebp),%ebx
	movl	-8(%ebp),%esi
	leal	-32788(%ebp),%edi
	movl	$8194,%ecx
	rep
	movsl
	movl	-16(%ebp),%esi
	movl	%esi,%eax
	call	fpc_check_object
	movl	%ebx,%eax
	call	*12(%esi)
	.stabn 68,0,31,.Ll12 - P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Ll12:
# [31] end;
	popl	%edi
	popl	%esi
	popl	%ebx
	movl	%ebp,%esp
	popl	%ebp
	ret
	.stabn 192,0,0,0
	.stabn 224,0,0,.Lt3-P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
.Lt3:

.section .text.n__main,"x"
	.balign 16,0x90
.globl	PASCALMAIN
PASCALMAIN:
.globl	_main
_main:
	.stabs "main:F4",36,0,2,_main
	.stabs "test.pas",132,0,0,.Lf4
.Lf4:
	.stabn 68,0,35,.Ll13 - _main
.Ll13:
# [35] begin
	pushl	%ebp
	movl	%esp,%ebp
	pushl	%ebx
	call	fpc_initializeunits
	.stabn 68,0,36,.Ll14 - _main
.Ll14:
# [36] Obj:= New(PObj, Init);
	movl	$VMT_$P$PROGRAM_$$_TOBJ,%eax
	movl	%eax,%edx
	movl	$0,%eax
	call	P$PROGRAM$_$TOBJ_$__$$_INIT$$LONGBOOL
	movl	%eax,U_$P$PROGRAM_$$_OBJ
	.stabn 68,0,37,.Ll15 - _main
.Ll15:
# [37] Obj^.Proc(0);
	movl	U_$P$PROGRAM_$$_OBJ,%eax
	movw	$0,%dx
	call	P$PROGRAM$_$TOBJ_$__$$_PROC$SMALLINT
	.stabn 68,0,38,.Ll16 - _main
.Ll16:
# [38] writeln('Completed');
	call	fpc_get_output
	movl	%eax,%ebx
	movl	$_$PROGRAM$_Ld2,%ecx
	movl	%ebx,%edx
	movl	$0,%eax
	call	fpc_write_text_shortstr
	call	fpc_iocheck
	movl	%ebx,%eax
	call	fpc_writeln_end
	call	fpc_iocheck
	.stabn 68,0,39,.Ll17 - _main
.Ll17:
# [39] end.
	call	fpc_do_exit
	popl	%ebx
	movl	%ebp,%esp
	popl	%ebp
	ret
	.stabn 192,0,0,0
	.stabn 224,0,0,.Lt1-_main
.Lt1:

.section .fpc.n_links
	.long	DEBUGINFO_$P$PROGRAM
	.long	DEBUGSTART_$P$PROGRAM
	.long	DEBUGEND_$P$PROGRAM
# End asmlist al_procedures
# Begin asmlist al_globals

.section .bss
	.balign 4
# [34] Obj: PObj;
U_$P$PROGRAM_$$_OBJ:
	.zero 4

.section .rodata.n_VMT_$P$PROGRAM_$$_TOBJ,"d"
	.balign 4
.globl	VMT_$P$PROGRAM_$$_TOBJ
VMT_$P$PROGRAM_$$_TOBJ:
	.long	32776,-32776,0
	.long	P$PROGRAM$_$TOBJ_$__$$_VPROC
	.long	0

.section .data.n_INITFINAL,"d"
	.balign 4
.globl	INITFINAL
INITFINAL:
	.long	4,0
	.long	INIT$_$SYSTEM
	.long	0,0
	.long	FINALIZE$_$OBJPAS
	.long	INIT$_$LINEINFO
	.long	FINALIZE$_$LINEINFO
	.long	INIT$_$FPINTRES
	.long	0

.section .data.n_FPC_THREADVARTABLES,"d"
	.balign 4
.globl	FPC_THREADVARTABLES
FPC_THREADVARTABLES:
	.long	1
	.long	THREADVARLIST_$SYSTEM$indirect

.section .rodata.n_FPC_RESOURCESTRINGTABLES,"d"
	.balign 4
.globl	FPC_RESOURCESTRINGTABLES
FPC_RESOURCESTRINGTABLES:
	.long	0

.section .data.n_FPC_WIDEINITTABLES,"d"
	.balign 4
.globl	FPC_WIDEINITTABLES
FPC_WIDEINITTABLES:
	.long	0

.section .data.n_FPC_RESSTRINITTABLES,"d"
	.balign 4
.globl	FPC_RESSTRINITTABLES
FPC_RESSTRINITTABLES:
	.long	0

.section .fpc.n_version
	.balign 16
__fpc_ident:
	.ascii	"FPC 3.2.0rc1 [2020/02/29] for i386 - Win32"

.section .data.n___heapsize,"d"
	.balign 4
.globl	__heapsize
__heapsize:
	.long	65536

.section .data.n___fpc_valgrind,"d"
	.balign 4
.globl	__fpc_valgrind
__fpc_valgrind:
	.byte	0
# End asmlist al_globals
# Begin asmlist al_typedconsts

.section .rodata.n__$PROGRAM$_Ld1,"d"
	.balign 4
.globl	_$PROGRAM$_Ld1
_$PROGRAM$_Ld1:
	.ascii	"\002: \000"

.section .rodata.n__$PROGRAM$_Ld2,"d"
	.balign 4
.globl	_$PROGRAM$_Ld2
_$PROGRAM$_Ld2:
	.ascii	"\011Completed\000"
# End asmlist al_typedconsts
# Begin asmlist al_indirectglobals

.section .rodata.n_VMT_$P$PROGRAM_$$_TOBJ,"d"
	.balign 4
.globl	VMT_$P$PROGRAM_$$_TOBJ$indirect
VMT_$P$PROGRAM_$$_TOBJ$indirect:
	.long	VMT_$P$PROGRAM_$$_TOBJ
# End asmlist al_indirectglobals
# Begin asmlist al_end

.section .text.z_DEBUGEND_$P$PROGRAM,"x"
	.balign 4,0x90
.globl	DEBUGEND_$P$PROGRAM
DEBUGEND_$P$PROGRAM:
	.stabs "",100,0,0,.Lf6
.Lf6:
# End asmlist al_end

test.s (10,154 bytes)   

Florian

2020-04-05 18:27

administrator   ~0121948

Actually, the reason was that -dDEBUG enables -Cr/-CR. For checking the object, the compiler created indeed a full copy. I have fixed it.

Issue History

Date Modified Username Field Change
2020-04-03 15:50 Dmitry New Issue
2020-04-03 16:40 Awkward Note Added: 0121865
2020-04-03 16:55 Dmitry Note Added: 0121866
2020-04-05 05:43 Dmitry Note Added: 0121914
2020-04-05 07:32 Anton Kavalenka Note Added: 0121920
2020-04-05 08:45 Dmitry Note Added: 0121923
2020-04-05 08:47 Dmitry Note Edited: 0121923 View Revisions
2020-04-05 10:49 Awkward Note Added: 0121926
2020-04-05 11:28 Florian Note Added: 0121930
2020-04-05 11:28 Florian Status new => feedback
2020-04-05 11:28 Florian FPCTarget => -
2020-04-05 12:54 Dmitry Note Added: 0121934
2020-04-05 12:54 Dmitry Status feedback => new
2020-04-05 13:13 Dmitry File Added: test.pas
2020-04-05 13:13 Dmitry File Added: test.s
2020-04-05 13:13 Dmitry Note Added: 0121936
2020-04-05 18:27 Florian Assigned To => Florian
2020-04-05 18:27 Florian Status new => resolved
2020-04-05 18:27 Florian Resolution open => fixed
2020-04-05 18:27 Florian Fixed in Version => 3.3.1
2020-04-05 18:27 Florian Fixed in Revision => 44598
2020-04-05 18:27 Florian Note Added: 0121948