Page 1 of 3

Calling exported string functions - PB 4.2 beta 2

Posted: Wed Jan 30, 2008 2:53 pm
by srod
Hi,

this quite serious problem is shown in the generated ASM file, but first, if you wish to reproduce this bug, tailbite the following to create a simple userlib (or even create a dll instead) :

Userlib :

Code: Select all

ProcedureDLL.s HeyHo(a)
  Protected a$
  a$=Str(a)
  ProcedureReturn a$
EndProcedure
Now a client program :

Code: Select all

Procedure TEST_PROC() 
  tarea.s = HeyHo(100) 
  MessageRequester("Bloody hell's bells!", tarea) 
EndProcedure 

If OpenWindow(0,0,0,640,300,"Tally bally ho!",#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_Maximize|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  CreateMenu(0,WindowID(0)) 
  MenuTitle("test") 
  MenuItem(1, "testing") 
  Repeat 
    EventID = WaitWindowEvent() 
    If EventID=#PB_Event_Menu And  EventMenu()=1 
      TEST_PROC() 
    EndIf 
  Until EventID = #PB_Event_CloseWindow 
EndIf 
Run the client (after creating the userlib) and select the menu option. CRASH!

The problem is generated by the HeyHo(100) call in the TEST_PROC() procedure and would appear to be one of stack corruption.

The problem is quite easily seen in the ASM corresponding to the TEST_PROC() procedure; see the two instances of

Code: Select all

PUSH   dword [_PB_StringBasePosition]
ASM for the TEST_PROC() procedure.

Code: Select all

; :
; Procedure TEST_PROC() 
macro MP0{
_Procedure0:
  PS0=8
  XOR    eax,eax
  PUSH   eax                                                                                                                                                                                                                             
; tarea.s = HeyHo(100) 
  PUSH   dword [_PB_StringBasePosition]
  PUSH   dword [_PB_StringBasePosition]
  PUSH   dword 100
  CALL   PB_HeyHo
  LEA    ecx,[esp+4]
  POP    edx
  CALL   SYS_AllocateString
; MessageRequester("Bloody hell's bells!", tarea) 
  PUSH   dword [esp]
  PUSH   dword _S1
  CALL  _PB_MessageRequester@8
; EndProcedure 
  XOR    eax,eax
_EndProcedure1:
  PUSH   dword [esp]
  CALL  _SYS_FreeString@4
  ADD    esp,4
  RET
}
;
All of this runs fine with PB 4.1 and indeed the generated ASM file only has one instance of the PUSH dword [_PB_StringBasePosition] instruction in this case!

Posted: Wed Jan 30, 2008 4:16 pm
by DoubleDutch
Don't know if it's related, but it seems to also happen on a gosub:

Code: Select all

Gosub FindFileLocations
End

FindFileLocations:
	DeskTop$=GetSpecialFolderLocation(#CSIDL_DESKTOP)
Return
The GetSpecialFolderLocation command is from Droopy's library.

The crash happens on th return. :(

Posted: Wed Jan 30, 2008 4:27 pm
by srod
I would guess that it is exactly the same problem.

Have a look at the ASM to see if the PUSH dword [_PB_StringBasePosition] instruction is duplicated?

Posted: Wed Jan 30, 2008 4:46 pm
by DoubleDutch
Is there an easy way in the PB IDE to generate the ASM file? I do this a lot and don't want to have to bother going to DOS and start typing, etc ...

Posted: Wed Jan 30, 2008 4:48 pm
by srod
Guess you could create a tool for it.

I just use a simple batch file.

Posted: Wed Jan 30, 2008 8:00 pm
by DoubleDutch

Code: Select all

; Gosub FindFileLocations 
  CALL   l_findfilelocations
; End 
  JMP   _PB_EOP_NoValue
; 
; FindFileLocations: 
l_findfilelocations:
; DeskTop$=GetSpecialFolderLocation(#CSIDL_DESKTOP) 
  PUSH   dword [_PB_StringBasePosition]
  PUSH   dword [_PB_StringBasePosition]
  PUSH   dword 0
  CALL   PB_GetSpecialFolderLocation
  LEA    ecx,[v_DeskTop$]
  POP    edx
  CALL   SYS_AllocateString
; Return
  RET
_PB_EOP_NoValue:
  PUSH   dword 0
_PB_EOP:
  CALL  _PB_EndFunctions
  PUSH   dword [PB_MemoryBase]
  CALL  _HeapDestroy@4
  CALL  _ExitProcess@4
_PB_EndFunctions:
  CALL  _PB_FreeFiles@0
  CALL  _PB_FreeFonts@0
  CALL  _PB_FreeWindows@0
  CALL  _PB_FreeImages@0
  CALL  _PB_FreeLibraries@0
  CALL  _PB_FreeMemorys@0
  CALL  _PB_FreeNetworks@0
  CALL  _PB_FreeSimpleLists@0
  RET
Looks like it's the same problem!

I hope this one gets fixed fast, it could cause lots of unexpected problems all over the place.

Posted: Wed Jan 30, 2008 8:59 pm
by freak
The double PUSH is on purpose (there is also a POP after the CALL if you look closely)
This should not affect the called library functions actually. There is no problem with our libraries.

Dunno why Tailbite libraries have a problem. We'll have to take a closer look.

Posted: Wed Jan 30, 2008 10:43 pm
by srod
Ah, sorry I didn't notice the extra POP freak. Also I've tested a dll created with PB 4.2 beta 2 with essentially the code in my first post above, and it all works fine.

Could something have changed with PB 4.2 which Tailbite hasn't picked up on yet?

Posted: Thu Jan 31, 2008 12:09 am
by DoubleDutch
Freak: It must be something behind the scenes like you said as version 4.2a4 produces the same visible ASM source code, but does not crash.

Posted: Thu Jan 31, 2008 8:11 am
by Blue
DoubleDutch wrote:Is there an easy way in the PB IDE to generate the ASM file? I do this a lot and don't want to have to bother going to DOS and start typing, etc ...
You can simply create a tool that will run the compiler, produce an executable (called PureBasic.exe !!! not my choice) and a commented source file called PureBasic.ASM, both saved in your PB file's directory:

line #1: D:\Basic\Pure\Compilers\PBCompiler.exe ( ...wherever it is on your machine.)
line #2: %FILE /COMMENTED
line #3: <empty>
line #4: Output ASM ( ... whatever name you prefer)

There must be an easy way to automatically rename the output to something other than the odd PureBasic.exe name, but I don't know it.
As well, I've found out that if you rename the asm source to something other than its default PureBasic.asm name, the compiler gets very unhappy with you when you attempt to re-assemble your modified asm source !!!

Posted: Thu Jan 31, 2008 11:52 am
by srod
http://www.purebasic.fr/english/viewtopic.php?t=30843

:wink:

Actually, I might add this to the tricks and tips section.

Posted: Mon Feb 04, 2008 12:24 pm
by srod
@Freak, I don't know if this will help get to the bottom of the problem with Tailbite and calling exported string functions through a procedure?

I tailbited the following small snippet whilst selecting the "Keep source files after making the library" option :

Code: Select all

ProcedureDLL.s Hey(a)
  a$="Heyho, I am "+Str(a) + " today!"
  ProcedureReturn a$
EndProcedure
Now delete the resulting user lib, but grab a copy of the resulting .lib file which Tailbite produces prior to creating the user lib.
I've uploaded a copy : Download 'HeyHo.lib'

Now, place the lib in a folder alongside the following program (which runs fine and produces the correct output) :

Code: Select all

Import "heyho.lib"
  Hey.l(a) As "PB_Hey"
EndImport

a = Hey(6)
a$=PeekS(a)
Debug a$
However, place the above program in a procedure and you'll see that the return string is duplicated :

Code: Select all

Import "heyho.lib"
  Hey.l(a) As "PB_Hey"
EndImport

Procedure.s Display()
  a = Hey(6)
  a$=PeekS(a)
  ProcedureReturn a$
EndProcedure

Debug Display()
As I say I don't know if this will be of any help, -but I see no harm in posting! :)

If you think this is a Tailbite problem rather than a PB one, please let me know and I'll dump this little lot on ABBKlaus ! :twisted:

Posted: Tue Mar 25, 2008 2:56 pm
by Fred
Seems to be a problem with tailbite, it now has to handle the double 'push' correctly or you will mess up the stack (that's probably why it runs in the main, but not in the procedure).

Posted: Tue Mar 25, 2008 3:43 pm
by srod
But, as Freak pointed out, the extra push is balanced with an extra pop after the call to the exported function etc.

Posted: Tue Mar 25, 2008 3:58 pm
by gnozal
srod wrote:... the extra push is balanced with an extra pop ...
I don't understand this either. How (why) should Tailbite handle the extra PUSH if it is followed by a POP ?