sourcemod icon indicating copy to clipboard operation
sourcemod copied to clipboard

Add new address natives

Open Kenzzer opened this issue 6 months ago • 6 comments

With TF2 64bits release looming on the horizon, its high time Sourcemod is updated with some very much needed natives for addresses. Otherwise we're going to have a lot of upset plugin authors !

Here's a list of a new natives I think could alleviate the issues :

Added offset parameter to LoadFromAddress and StoreToAddress

For instance plugins often retrieve C++ objects addresses and read member properties from them. So the need of offsetting address values is quite common and needs to be addressed, as it would be risky to perform within a plugin environment (overflowing the address value).

~~Added OffsetAddress~~

~~With loading and reading covered, manual offsetting still isn't (e.g setting up a manual SDKCall). A native like this one would be required.~~

Added LoadAddressFromAddress and StoreAddressToAddress

Addresses can be pointer variables. And while plugins could get away with it by treating Address type as NumberType_Int32 to store at a given address, they cannot anymore. An helper function for this scenario is required.

~~Added LoadSpanFromAddress and StoreSpanToAddress, LoadBytesFromAddress and StoreBytesToAddress~~

~~For every other types that aren't covered by our natives. Let's allow plugins to store and load abritrary chunk of bytes. Useful for big types like int64/int128. Or other obscure scenarios, like maybe reading a string in memory.~~

Kenzzer avatar Feb 05 '24 16:02 Kenzzer

As someone that has needed to manipulate addresses in their plugins, this sort of thing is definitely needed as part of the architectural transition. I haven't had the time to confirm how the pseudo addresses work when it comes to heap allocations and the like so I've yet to confirm how this works in practice.

I gave my feedback in another channel, but I'll also comment on it here in case other people had their thoughts:

  • The PR initially only had the "byte" versions of the array accessors; I suggested adding a variant that takes any[] with optional sizes to allow for reading float / int types without having to do awkward char[] conversions.

nosoop avatar Feb 06 '24 04:02 nosoop

Two short comments.

I don't have a strong opinion on unstructured memory access. However, it should be a last resort. It's inherently less maintainable and more susceptible to breakage. Having structured access is vastly better, even if 99% of the way there is structured, and the very last thing is the memory poke. That's why stuff like SDKCall and bintools and gamedata exist. But clearly the unstructured stuff is needed, and serves an important role, so it shouldn't be rejected or stuck in design hell.

As to int64 - my dance card got very full, very quickly and I had to take a step away from SP again. My bar for changes right now is "can I get it done in a night or two". int64 - probably not. Even if I could, I can't start on it right this moment.

Don't wait for int64. Use enumstructs:

enum struct Address {
    int high32
    int low32
}

It is MUCH easier to design syntactic sugar around these, so if you have an issue with them or have an idea that would make them easier to use, please file a bug.

dvander avatar Feb 06 '24 04:02 dvander

Don't wait for int64. Use enumstructs:

enum struct Address {
    int high32
    int low32
}

It is MUCH easier to design syntactic sugar around these, so if you have an issue with them or have an idea that would make them easier to use, please file a bug.

IMO this should just be a new pawn type, something like Address64, that is maybe bcompat with 32 bit Address, where the low32 is populated and high32 is null?

sapphonie avatar Feb 06 '24 08:02 sapphonie

Don't wait for int64. Use enumstructs:

enum struct Address {
    int high32
    int low32
}

It is MUCH easier to design syntactic sugar around these, so if you have an issue with them or have an idea that would make them easier to use, please file a bug.

Such a solution would definitively eliminate the need for OffsetAddress to exist, and the offset parameter to LoadFromAddress and StoreToAddress.

But LoadAddressFromAddress & StoreAddressToAddress would still be required. NumberType_Int32 is currently used to achieve load/storing an address in memory but it will never work for 64bits. Sure we could use LoadSpanFromAddress & StoreSpanToAddress, but this would put higher importance on the order of struct properties for Address.

If we are to assume an enum struct is defined for Address. And it has the ""wrong"" order decided for high32 and low32 in the struct. Neither LoadSpanFromAddress or StoreSpanToAddress can then be used, and a special native like LoadAddressFromAddress and StoreAddressToAddress would be required still.

Kenzzer avatar Feb 06 '24 08:02 Kenzzer

Would a native like GetPseudoAddress(int hi, int low) be accepted? I have a use case where I can't put the address in gamedata as it doesn't have a symbol. Or at least a clone of LoadFromAddress that takes 2 Address values.

bottiger1 avatar May 06 '24 01:05 bottiger1

Would a native like GetPseudoAddress(int hi, int low) be accepted? I have a use case where I can't put the address in gamedata as it doesn't have a symbol. Or at least a clone of LoadFromAddress that takes 2 Address values.

This could be okay, however PeusdoAddresses are currently inherently broken, very high address numbers cannot be mapped to pseudoaddresses. We're currently investigating alternatives. One thing is sure, introducing new API that's gonna be replaced right after doesn't make much sense. That's why this PR has remained in limbo for so long.

Kenzzer avatar May 06 '24 05:05 Kenzzer

Closing in favor of #2196 & alliedmodders/sourcepawn#983 . The core of this PR is to address the lack of arithmetic ability over Address however the aforementioned PRs are both going to fix this problem eventually.

Kenzzer avatar Jul 31 '24 12:07 Kenzzer