sourcepawn icon indicating copy to clipboard operation
sourcepawn copied to clipboard

Function casting not working on 1.11

Open geominorai opened this issue 4 years ago • 15 comments

Help us help you

  • [x] I have checked that my issue doesn't exist yet.
  • [x] I have tried my absolute best to reduce the problem-space and have provided the absolute smallest test-case possible.
  • [x] I can always reproduce the issue with the provided description below.

Environment

  • Current SourceMod snapshot: 1.11.0.6745

Description

Function casting previously working on the 1.10.0.6512 compiler no longer does on 1.11.

Problematic Code

typedef MyFunc = function void ();

public int Native_Test(Handle hPlugin, int iArgC) {
	MyFunc fnFunc = view_as<MyFunc>(GetNativeFunction(1));
}

Expected Behavior

SourcePawn Compiler 1.10.0.6502
Copyright (c) 1997-2006 ITB CompuPhase
Copyright (c) 2004-2018 AlliedModders LLC

C:\Build\SM1.10\scripting\spcomp_function_cast_bug.sp(4) : warning 204: symbol is assigned a value that is never used: "fnFunc"
Code size:             3056 bytes
Data size:             2280 bytes
Stack/heap size:      16384 bytes
Total requirements:   21720 bytes

1 Warning.

Actual Behavior

SourcePawn Compiler 1.11.0.6745
Copyright (c) 1997-2006 ITB CompuPhase
Copyright (c) 2004-2018 AlliedModders LLC

C:\Build\SM1.10\scripting\spcomp_function_cast_bug.sp(4) : error 100: function prototypes do not match

1 Error.

geominorai avatar Sep 25 '21 02:09 geominorai

You should not be calling that function returned from GetNativeFunction as a normal function it should be going through Call_StartFunction if I remember correctly.

see: https://sourcemod.dev/#/functions/function.Call_StartFunction

c0rp3n avatar Sep 27 '21 15:09 c0rp3n

You should not be calling that function returned from GetNativeFunction as a normal function it should be going through Call_StartFunction if I remember correctly.

see: https://sourcemod.dev/#/functions/function.Call_StartFunction

Indeed, I can call the functions just fine via Call_StartFunction on servers running on SM 1.10 and 1.11. It is just the 1.11 compiler misbehaving, so I am sticking with the 1.10 compiler for now until this gets fixed.

geominorai avatar Sep 27 '21 22:09 geominorai

It is just the 1.11 compiler misbehaving, so I am sticking with the 1.10 compiler for now until this gets fixed.

I don't think it is, this was an intentional change: #644

Why do you think that it is misbehaving? GetNativeFunction returns a Function and Call_StartFunction takes a Function - it doesn't appear to need to be a MyFunc at any point inside the native handler.

asherkin avatar Sep 27 '21 23:09 asherkin

Thanks for pointing that out... indeed this is not the most compelling use case. On the other hand, the aim of that patch was to catch mismatched casts. At the time I assumed there was a special-case for "Function". Apparently there isn't.

I was trying to think of why you'd need this, the only case I could think of: if you want to pass the returned value into a native or something.

dvander avatar Sep 27 '21 23:09 dvander

I currently have two projects affected by this.

One project is a modular plugin set I am working on where the main plugin calls specific functions defined in a submodule's plugin, but the submodule first has to pass a pointer for one of its functions up to the main module during initialization via a native so it can be stored first.

The second is a project where I have an enum struct containing a function variable that defines a custom action, and that what that function points to is set up during initialization depending on the circumstances and later called. This is done instead of having a huge switch block dispatching to different functions for each case. These functions may originate outside of the plugin like the first one and requires natives to pass functions.

geominorai avatar Sep 28 '21 01:09 geominorai

The cast in the example is not needed, though.

dvander avatar Sep 28 '21 03:09 dvander

But what variable type can I store it as? function is reserved and cannot be used as a type for variable declaration.

geominorai avatar Sep 28 '21 03:09 geominorai

"Function" should work.

dvander avatar Sep 28 '21 03:09 dvander

Oh shit, I did not realize that was a separate thing. Thanks, I can definitely use this.

Is there a way to check or make sure the Function returned by GetNativeFunction match a specific signature similar to typeset / typedef?

geominorai avatar Sep 28 '21 04:09 geominorai

Is there a way to check or make sure the Function returned by GetNativeFunction match a specific signature similar to typeset / typedef?

No, the check takes place at the compilation level. Full function signatures (passed argument cell types) are not checked during run time. You can represent Function by a type from type(set/def) via view_as.

Wend4r avatar Sep 28 '21 13:09 Wend4r

I'm still open to making this cast work because we can add run-time checks for it later on.

The "Function" type vs "function" keyword is unfortunate. It's probably too late to revisit that though.

dvander avatar Sep 28 '21 16:09 dvander

You can represent Function by a type from type(set/def) via view_as.

This stopped working on the 1.11 compiler too:

typedef MyFunc = function void ();

public int Native_Test(Handle hPlugin, int iArgC) {
	Function fnFunc = GetNativeFunction(1);
	MyFunc fnMyFunc = view_as<MyFunc>(fnFunc);
}
SourcePawn Compiler 1.10.0.6512
Copyright (c) 1997-2006 ITB CompuPhase
Copyright (c) 2004-2018 AlliedModders LLC

C:\Build\SM1.10\scripting\spcomp_function_cast_bug.sp(5) : warning 204: symbol is assigned a value that is never used: "fnMyFunc"
Code size:             3084 bytes
Data size:             2280 bytes
Stack/heap size:      16384 bytes
Total requirements:   21748 bytes

1 Warning.
SourcePawn Compiler 1.11.0.6745                                                                         
Copyright (c) 1997-2006 ITB CompuPhase                                                                  
Copyright (c) 2004-2018 AlliedModders LLC                                                               
                                                                                                        
C:\Build\SM1.10\scripting\spcomp_function_cast_bug.sp(5) : error 100: function prototypes do not match  
                                                                                                        
1 Error.                                                                                                

geominorai avatar Sep 28 '21 23:09 geominorai

Any updates on this? typedefs are unusable at the moment for situations where typed funcs are downgraded to Function type such as forwards and datapack storage. Workaround is to replace type with base Function type.

JoinedSenses avatar Sep 25 '22 23:09 JoinedSenses

I have resorted to passing Function around, ignoring any safety checks offered during compile-time, and then feeling very bad about it afterwards.

geominorai avatar Sep 25 '22 23:09 geominorai

Any updates on this?

Cruze03 avatar Dec 29 '22 18:12 Cruze03