Proto without proper params

Just starting out? Need help? Post your questions and find answers here.
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Proto without proper params

Post by Joubarbe »

Code: Select all

Prototype __Generic(custom_value)

Structure _var
  *callback.__Generic
EndStructure

Procedure Func() ; We omit custom_value for the sake of the demonstration.
  Debug "Func() called"
EndProcedure

Procedure AddCallback(*var._var, *callback.__Generic)
  *var\callback = *callback
EndProcedure

Procedure CallCallback(*var._var, custom_value)
  *var\callback(custom_value)
EndProcedure

Define var._var

AddCallback(@var, @Func())
CallCallback(@var, 0)
I often do this kind of code for various reasons, and I use the __Generic prototype without argument. Considering that Func() is NOT complying with the prototype definition, I'd like to know if there's any chance of a memory leak or any undefined behaviour? In other words, is it a problem?
User avatar
NicTheQuick
Addict
Addict
Posts: 1527
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Proto without proper params

Post by NicTheQuick »

I am not an expert in this but I think on 64 bit platforms that one parameter should not be an issue because parameters are usually passed through registers. On 32 bit platforms parameters will be pushed on the stack before calling a function and there you can run into huge problems because the stack is no longer properly aligned.

Anyway, I might be wrong here and I am sure other members are more experienced in stuff like that.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
SMaag
Enthusiast
Enthusiast
Posts: 327
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Proto without proper params

Post by SMaag »

I go conforme with NichTheQuick!

A short time ago there was a similar problem on the forum, where such a construction caused a problem (but wiht more parameters).
By any reason PB do not check the correctnes of the Parameter.
I remember there was a comment from Fred. But I can't remember it.

C x32, x64
I guess it works in C-Backend. I guess C will use EAX, EDX for the first 2 parameters.

ASM x32, x64
I guess it will work because PB moves anything to the Stack!

here the x64 ASM Output

Code: Select all

; Procedure CallCallback(*var._var, custom_value)
_Procedure6:
  MOV    qword [rsp+8],rcx		; looks  like 1st Parameter to var on Stack
  MOV    qword [rsp+16],rdx               , looks like 2nd Paramenter to var on Stack
  PUSH   rbp
  PS6=64
  XOR    rax,rax					; RAX = 0
  PUSH   rax						; 0 to Stack - looks like the custom_value
  SUB    rsp,40
; *var\callback(custom_value)        ; prepare for Call the Callback
  MOV    rbp,qword [rsp+PS6+0]
  PUSH   qword [rbp]
  SUB    rsp,8
  PUSH   qword [rsp+PS6+24]
  POP    rcx
  SUB    rsp,32
  CALL   qword [rsp+40]
  ADD    rsp,40
  ADD    rsp,8
; EndProcedure

Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Proto without proper params

Post by Joubarbe »

Interesting...

@Fred: would it not be possible to add a check when passing a non-conform function address as callback (like @Func() in my example)?
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Proto without proper params

Post by wilbert »

Joubarbe wrote: Fri May 16, 2025 10:49 am In other words, is it a problem?
Yes, it's a problem (on Windows x86).

There are different calling conventions for different systems and processors.
On Windows x86 the default calling convention (stdcall) requires the callee to clean up the stack. In this case it's important the amount of procedure arguments match.
When using the C calling convention (cdecl) on Windows x86, the caller is responsible for cleaning up the stack so in that case there is no problem if more arguments are passed as the callee expects.

To fix the problem with your code you can use the C convention like this

Code: Select all

PrototypeC __Generic(custom_value)

Structure _var
  *callback.__Generic
EndStructure

ProcedureC Func() ; We omit custom_value for the sake of the demonstration.
  Debug "Func() called"
EndProcedure

Procedure AddCallback(*var._var, *callback.__Generic)
  *var\callback = *callback
EndProcedure

Procedure CallCallback(*var._var, custom_value)
  *var\callback(custom_value)
EndProcedure

Define var._var

AddCallback(@var, @Func())
CallCallback(@var, 0)
Windows (x64)
Raspberry Pi OS (Arm64)
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Proto without proper params

Post by Joubarbe »

Thank you wilbert for the explanation. I'll try declaring proper functions from now on :D But I always compile in x64, so if I understand you correctly, it shouldn't cause any problem (still going to do proper declarations for sure).
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Proto without proper params

Post by wilbert »

Joubarbe wrote: Fri May 16, 2025 10:03 pm But I always compile in x64, so if I understand you correctly, it shouldn't cause any problem (still going to do proper declarations for sure).
When using 64 bit, most procedure arguments are passed by registers but even if the stack is used, the 64 bit calling conventions require the caller to do the stack cleanup (on Windows, macOS and Linux, both x64 and ARM64).
So if you always compile for 64 bit there shouldn't be a problem.
Windows (x64)
Raspberry Pi OS (Arm64)
Joubarbe
Enthusiast
Enthusiast
Posts: 714
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Proto without proper params

Post by Joubarbe »

Would that be possible to implement a compiler check on @Func() when calling AddCallback()?
In CallCallback(), *var\callback()'s arity is checked, so maybe it's doable...? Or maybe it would be too much of a change for existing programs?
Post Reply