View Single Post
Author Message
Kailo
Senior Member
Join Date: Sep 2014
Location: Moscow, Russia
Old 08-12-2017 , 10:46   [INC] valist.inc Variable arguments function
Reply With Quote #1

Update: 2.0 released. Check changelog below.
How? Dark Magic!

Used a few tricks i created functions for variable arguments access.

This workable only with non-array variables for now (write if it needed to add arrays/strings support).

Instruction:
1) Include valist.inc in plugin with #include directive (You must include it first among all includes for proper work).
2) Call va_start(int param_n) in variable argument function, where param_n number of argument with ..., counting of arguments start with 1.
Note for 1st version: It's important call va_start before any variable will declared. Overwise, it'll work not correct.
(In 1st version need to call va_start first in function, in 2nd not).
3) For getting next argument use va_arg(). In case if no more arguments to get, it'll throw error.
You can use va_args() for getting count of params passed in function and va_more() to check if all arguments getted.
4) When you no more needed to get arguments, you must call va_end(). Overwise, memory leaks.

Offtop: Please, if you see any grammar mistakes, notice me about it. I'm not going well in English.

Plugin example:
PHP Code:
// © Maxim "Kailo" Telezhenko, 2017

#pragma newdecls required
#pragma semicolon 1

#include <valist>

public void OnPluginStart()
{
    
RegConsoleCmd("sm_nums"Cmd_Nums);
}

public 
Action Cmd_Nums(int clientint args)
{
    
ReplyToCommand(client"Sum: %i"Sum(104050, -3080));

    return 
Plugin_Handled;
}

int Sum(int ...)
{
    
va_start(1);
    
PrintToServer("args: %i"va_args());
    
int sum 0;
    while (
va_more())
        
sum += va_arg();
    
va_end();
    return 
sum;

valist.inc code


Attention!
1st version not working in 1.9 since sourcepawn "Disallow negative indices in all array access patterns" (d7743c3) update.

Changelog:
v2: Changelog
v1: First release.

// Download latest version below in attachments.
Old versions:
v1: valist.inc

How i did this: (tricks)
1) Unchecked memory access
Then you pass array as param, plugin know only address and check index for negative value
PHP Code:
{
    
int array[1];
    
int var1 50;
    
PrintToServer("%i %i"Fn(array), var1);
}

int Fn(int[] array)
{
    return array[
1]; // will return var1 value

2) Knowledge of SourcePawn virtual machine
Plugin memory сonsists of DAT (globals, statics, consts), heap, stack (order as i wrote).
When functions calls:
1) Pass arguments in reverse order
2) Pass num of arguments
3) pass old frame address
4) pass 0
Using sipmle trick i can dump stack
PHP Code:
void Fn()
{
    
int a[1] = {777};
    
dumpstack(a);
}

stock void dumpstack(int[] anchor)
{
    for (
int a 0<= 15a++)
        
PrintToServer("%i: %i"aanchor[a]);

Using this in process of writing include i got ():
Code:
etc.
-8: 2220   // unused memory
-7: 20780 // unused memory
-6: 20776 // unused memory
-5: -5       // value of a
-4: 0        // just 0
-3: 20804 // old frame // for example look at {1}
-2: 1        // param count
-1: 20800 // 1st param; address of a // Here is started vm_start() call
0: 666     // a[1] = {666} // address of this array is 20800
/// {1} Here beging frame of vm_start(), here address is 20804
1: 0        // just 0
2: 20824 // old frame
3: 1        // param count
4: 1        // 1st param // Here is started vm_start() call
5: 0        // Valist VALIST variable
6: 0        // just 0
7: 20856 // old frame
8: 5        // arg count in Sum call
9: 2264   // 1st param
10: 2260 // 2nd param
11: 2256 // 3rd param
12: 2252 // 4th param
13: 2248 // 5th param // Here is started Sum() call; All 5 params is heap address
14: 2236 // this heap addr of where will stored result of Sum() for call ReplyToCommand in future
15: 20876  // this  addr of "Sum: %i" for call ReplyToCommand in future
All addresses is local for plugin memory.
Also as we see stack reversed in memory.
memory: DAT-start ... DAT-end, heap-start ... heap-end, stack-end ... stack-start;
3) pseudo-class based on methodmap + ArrayList
4) Some macros for good looking code
Attached Files
File Type: inc valist.inc (2.5 KB, 400 views)

Last edited by Kailo; 12-11-2017 at 06:12.
Kailo is offline