[gamecode] Save all param pointers with PR_SaveParams

Builtins calling other functions that call back into progs can get their
parameter pointers messed up resulting in all sorts of errors. Thus wrap
all callbacks to progs in PR_SaveParams/PR_RestoreParams.

Also, ditch PR_RESET_PARAMS in favor of using PR_SetupParams and move
setting pr_argc into PR_SetupParams.
This commit is contained in:
Bill Currie 2024-09-05 00:00:44 +09:00
parent e35bff066f
commit 698d27c996
19 changed files with 108 additions and 108 deletions

View file

@ -84,21 +84,6 @@ void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(PRI
*/
///@{
/** Ensure P_* macros point to the right place for passing parameters to progs
functions.
\param pr pointer to ::progs_t VM struct
\warning Failure to use this macro before assigning to the P_* macros can
cause corruption of the VM data due to "register" based calling. Can be
safely ignored for parameterless functions, or forwarding parameters
though a builtin. However, it is ok (and encouraged) to call
PR_SetupParams instead, as this macro calls PR_SetupParams with
PR_MAX_PARAMS and 1 for the alignment.
\hideinitializer
*/
#define PR_RESET_PARAMS(pr) PR_SetupParams (pr, PR_MAX_PARAMS, 1)
/** \name Nested Function Calls
These functions allow a builtin function that uses PR_CallFunction() to
@ -116,7 +101,7 @@ void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(PRI
*/
///@{
typedef struct pr_stashed_params_s {
pr_type_t *param_ptrs[2];
pr_type_t *param_ptrs[PR_MAX_PARAMS];
pr_type_t *return_ptr;
int argc;
pr_type_t params[1];

View file

@ -133,18 +133,19 @@ bi_inputline_enter (inputline_t *il)
return; // no callback defined
PR_PushFrame (pr);
PR_RESET_PARAMS (pr);
auto params = PR_SaveParams (pr);
if (data->method) {
PR_SetupParams (pr, 3, 1);
P_POINTER (pr, 0) = data->data[0];
P_POINTER (pr, 1) = data->data[1];
P_STRING (pr, 2) = PR_SetTempString (pr, line);
pr->pr_argc = 3;
} else {
PR_SetupParams (pr, 2, 1);
P_STRING (pr, 0) = PR_SetTempString (pr, line);
P_POINTER (pr, 1) = data->data[0];
pr->pr_argc = 2;
}
PR_ExecuteProgram (pr, data->enter);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
}

View file

@ -468,11 +468,10 @@ bi_Menu_Enter (progs_t *pr, void *data)
if (item->func) {
run_menu_pre ();
PR_PushFrame (&menu_pr_state);
PR_RESET_PARAMS (&menu_pr_state);
PR_SetupParams (pr, 2, 1);
P_STRING (&menu_pr_state, 0) =
PR_SetTempString (&menu_pr_state, item->text);
P_INT (&menu_pr_state, 1) = 0;
pr->pr_argc = 2;
PR_ExecuteProgram (&menu_pr_state, item->func);
PR_PopFrame (&menu_pr_state);
run_menu_post ();
@ -727,10 +726,9 @@ Menu_Draw (view_t view)
run_menu_pre ();
PR_PushFrame (&menu_pr_state);
PR_RESET_PARAMS (&menu_pr_state);
PR_SetupParams (&menu_pr_state, 2, 1);
P_INT (&menu_pr_state, 0) = x;
P_INT (&menu_pr_state, 1) = y;
menu_pr_state.pr_argc = 2;
PR_ExecuteProgram (&menu_pr_state, menu->draw);
ret = R_INT (&menu_pr_state);
PR_PopFrame (&menu_pr_state);
@ -764,10 +762,9 @@ Menu_Draw (view_t view)
if (menu->cursor) {
run_menu_pre ();
PR_PushFrame (&menu_pr_state);
PR_RESET_PARAMS (&menu_pr_state);
PR_SetupParams (&menu_pr_state, 2, 1);
P_INT (&menu_pr_state, 0) = x + item->x;
P_INT (&menu_pr_state, 1) = y + item->y;
menu_pr_state.pr_argc = 2;
PR_ExecuteProgram (&menu_pr_state, menu->cursor);
PR_PopFrame (&menu_pr_state);
run_menu_post ();
@ -799,11 +796,10 @@ menu_key_event (const IE_event_t *ie_event)
if (menu->keyevent) {
run_menu_pre ();
PR_PushFrame (&menu_pr_state);
PR_RESET_PARAMS (&menu_pr_state);
PR_SetupParams (&menu_pr_state, 3, 1);
P_INT (&menu_pr_state, 0) = key.code;
P_INT (&menu_pr_state, 1) = key.unicode;
P_INT (&menu_pr_state, 2) = 1; //FIXME only presses now
menu_pr_state.pr_argc = 3;
PR_ExecuteProgram (&menu_pr_state, menu->keyevent);
ret = R_INT (&menu_pr_state);
PR_PopFrame (&menu_pr_state);
@ -815,11 +811,10 @@ menu_key_event (const IE_event_t *ie_event)
run_menu_pre ();
PR_PushFrame (&menu_pr_state);
item = menu->items[menu->cur_item];
PR_RESET_PARAMS (&menu_pr_state);
PR_SetupParams (&menu_pr_state, 2, 1);
P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state,
item->text);
P_INT (&menu_pr_state, 1) = key.code;
menu_pr_state.pr_argc = 2;
PR_ExecuteProgram (&menu_pr_state, item->func);
ret = R_INT (&menu_pr_state);
PR_PopFrame (&menu_pr_state);

View file

@ -102,17 +102,19 @@ _PR_SaveParams (progs_t *pr, pr_stashed_params_t *params)
int i;
int size = pr->pr_param_size * sizeof (pr_type_t);
params->param_ptrs[0] = pr->pr_params[0];
params->param_ptrs[1] = pr->pr_params[1];
memcpy (params->param_ptrs, pr->pr_params, sizeof (pr->pr_params));
params->return_ptr = pr->pr_return;
pr->pr_params[0] = pr->pr_real_params[0];
pr->pr_params[1] = pr->pr_real_params[1];
pr->pr_return = pr->pr_return_buffer;
for (i = 0; i < pr->pr_argc; i++) {
memcpy (params->params + i * pr->pr_param_size,
pr->pr_real_params[i], size);
}
params->argc = pr->pr_argc;
return params;
}
@ -122,9 +124,9 @@ PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params)
int i;
int size = pr->pr_param_size * sizeof (pr_type_t);
pr->pr_params[0] = params->param_ptrs[0];
pr->pr_params[1] = params->param_ptrs[1];
memcpy (pr->pr_params, params->param_ptrs, sizeof (pr->pr_params));
pr->pr_return = params->return_ptr;
pr->pr_argc = params->argc;
for (i = 0; i < pr->pr_argc; i++) {
memcpy (pr->pr_real_params[i],
@ -493,6 +495,7 @@ PR_SetupParams (progs_t *pr, int num_params, int min_alignment)
}
pr->pr_params[0] = pr->pr_real_params[0];
pr->pr_params[1] = pr->pr_real_params[1];
pr->pr_argc = num_params;
return pr->pr_real_params[0];
}
int offset = num_params * 4;
@ -1504,7 +1507,8 @@ op_rcall:
case OP_CALL6_v6p:
case OP_CALL7_v6p:
case OP_CALL8_v6p:
PR_RESET_PARAMS (pr);
pr->pr_params[0] = pr->pr_real_params[0];
pr->pr_params[1] = pr->pr_real_params[1];
pr->pr_argc = st->op - OP_CALL0_v6p;
op_call:
pr->pr_xfunction->profile += profile - startprofile;

View file

@ -529,9 +529,8 @@ ED_LoadFromFile (progs_t *pr, const char *data)
if (pr->edict_parse) {
PR_PushFrame (pr);
PR_RESET_PARAMS (pr);
PR_SetupParams (pr, 1, 1);
P_INT (pr, 0) = PR_SetTempString (pr, data);
pr->pr_argc = 1;
PR_ExecuteProgram (pr, pr->edict_parse);
PR_PopFrame (pr);
return;

View file

@ -90,11 +90,12 @@ bi_gib_builtin_f (void)
PR_PTR (string, &pr_list[i]) = PR_SetTempString (builtin->pr,
GIB_Argv(i));
PR_RESET_PARAMS (builtin->pr);
auto params = PR_SaveParams (builtin->pr);
PR_SetupParams (builtin->pr, 2, 1);
P_INT (builtin->pr, 0) = GIB_Argc();
P_INT (builtin->pr, 1) = PR_SetPointer (builtin->pr, pr_list);
builtin->pr->pr_argc = 2;
PR_ExecuteProgram (builtin->pr, builtin->func);
PR_RestoreParams (builtin->pr, params);
PR_PopFrame (builtin->pr);
PR_Zone_Free (builtin->pr, pr_list);
}

View file

@ -149,8 +149,7 @@ bi__call_cbuf (progs_t *pr, pr_func_t func, pr_int_t cbuf)
{
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
pr->pr_argc = 1;
PR_SetupParams (pr, pr->pr_argc, 1);
PR_SetupParams (pr, 1, 1);
P_INT (pr, 0) = cbuf;
PR_ExecuteProgram (pr, func);
PR_RestoreParams (pr, params);
@ -163,8 +162,7 @@ bi__call_cbuf_string (progs_t *pr, pr_func_t func, pr_int_t cbuf,
{
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
pr->pr_argc = 2;
PR_SetupParams (pr, pr->pr_argc, 1);
PR_SetupParams (pr, 2, 1);
P_INT (pr, 0) = cbuf;
P_STRING (pr, 1) = PR_SetTempString (pr, str);
PR_ExecuteProgram (pr, func);

View file

@ -101,15 +101,17 @@ bi_get_key (const void *key, void *_ht)
{
qfZoneScoped (true);
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_PushFrame (ht->pr);
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key);
P_INT (ht->pr, 1) = ht->ud;
ht->pr->pr_argc = 2;
PR_ExecuteProgram (ht->pr, ht->gk);
progs_t *pr = ht->pr;
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 2, 1);
P_INT (pr, 0) = (intptr_t) (key);
P_INT (pr, 1) = ht->ud;
PR_ExecuteProgram (pr, ht->gk);
pr_string_t string = R_STRING (ht->pr);
PR_PopFrame (ht->pr);
return PR_GetString (ht->pr, string);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
return PR_GetString (pr, string);
}
static uintptr_t
@ -117,14 +119,16 @@ bi_get_hash (const void *key, void *_ht)
{
qfZoneScoped (true);
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_PushFrame (ht->pr);
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key);
P_INT (ht->pr, 1) = ht->ud;
ht->pr->pr_argc = 2;
PR_ExecuteProgram (ht->pr, ht->gh);
int hash = R_INT (ht->pr);
PR_PopFrame (ht->pr);
progs_t *pr = ht->pr;
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 2, 1);
P_INT (pr, 0) = (intptr_t) (key);
P_INT (pr, 1) = ht->ud;
PR_ExecuteProgram (pr, ht->gh);
int hash = R_INT (pr);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
return hash;
}
@ -133,15 +137,17 @@ bi_compare (const void *key1, const void *key2, void *_ht)
{
qfZoneScoped (true);
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_PushFrame (ht->pr);
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key1);
P_INT (ht->pr, 1) = (intptr_t) (key2);
P_INT (ht->pr, 2) = ht->ud;
ht->pr->pr_argc = 3;
PR_ExecuteProgram (ht->pr, ht->cmp);
int cmp = R_INT (ht->pr);
PR_PopFrame (ht->pr);
progs_t *pr = ht->pr;
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 3, 1);
P_INT (pr, 0) = (intptr_t) (key1);
P_INT (pr, 1) = (intptr_t) (key2);
P_INT (pr, 2) = ht->ud;
PR_ExecuteProgram (pr, ht->cmp);
int cmp = R_INT (pr);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
return cmp;
}
@ -150,13 +156,15 @@ bi_free (void *key, void *_ht)
{
qfZoneScoped (true);
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_PushFrame (ht->pr);
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key);
P_INT (ht->pr, 1) = ht->ud;
ht->pr->pr_argc = 2;
PR_ExecuteProgram (ht->pr, ht->f);
PR_PopFrame (ht->pr);
progs_t *pr = ht->pr;
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 2, 1);
P_INT (pr, 0) = (intptr_t) (key);
P_INT (pr, 1) = ht->ud;
PR_ExecuteProgram (pr, ht->f);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
}
static void

View file

@ -355,11 +355,12 @@ rua_listener_func (rua_in_cookie_t *cookie, const void *input)
qfZoneScoped (true);
progs_t *pr = cookie->pr;
PR_PushFrame (pr);
PR_RESET_PARAMS (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 2, 1);
P_POINTER (pr, 0) = cookie->data;
P_POINTER (pr, 1) = PR_SetPointer (pr, input);//FIXME check input
pr->pr_argc = 2;
PR_ExecuteProgram (pr, cookie->func);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
}
@ -369,12 +370,13 @@ rua_listener_method (rua_in_cookie_t *cookie, const void *input)
qfZoneScoped (true);
progs_t *pr = cookie->pr;
PR_PushFrame (pr);
PR_RESET_PARAMS (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 3, 1);
P_POINTER (pr, 0) = cookie->data;
P_POINTER (pr, 1) = 0; // don't know the method name (selector)
P_POINTER (pr, 2) = PR_SetPointer (pr, input);//FIXME check input
pr->pr_argc = 3;
PR_ExecuteProgram (pr, cookie->func);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
}

View file

@ -1548,11 +1548,12 @@ rua_at_handler (progs_t *pr, pr_ptr_t at_param, void *_probj)
pr_func_t imp = get_imp (probj, class, describe_sel);
PR_PushFrame (pr);
PR_RESET_PARAMS (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 2, 1);
P_POINTER (pr, 0) = at_param;
P_POINTER (pr, 1) = PR_SetPointer (pr, describe_sel);
pr->pr_argc = 2;
PR_ExecuteProgram (pr, imp);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
//FIXME the lifetime of the string may be a problem
return PR_GetString (pr, R_STRING (pr));

View file

@ -75,15 +75,17 @@ rua_compare (const void *a, const void *b, void *_f)
{
qfZoneScoped (true);
function_t *f = _f;
progs_t *pr = f->pr;
PR_PushFrame (f->pr);
PR_RESET_PARAMS (f->pr);
P_POINTER (f->pr, 0) = PR_SetPointer (f->pr, a);
P_POINTER (f->pr, 1) = PR_SetPointer (f->pr, b);
f->pr->pr_argc = 2;
PR_ExecuteProgram (f->pr, f->func);
int cmp = R_INT (f->pr);
PR_PopFrame (f->pr);
PR_PushFrame (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 2, 1);
P_POINTER (pr, 0) = PR_SetPointer (pr, a);
P_POINTER (pr, 1) = PR_SetPointer (pr, b);
PR_ExecuteProgram (pr, f->func);
int cmp = R_INT (pr);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
return cmp;
}

View file

@ -212,18 +212,21 @@ static inline void
sv_pr_exec (edict_t *self, edict_t *other, pr_func_t func)
{
pr_int_t this;
pr_stashed_params_t *params = nullptr;
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, self);
*sv_globals.other = EDICT_TO_PROG (&sv_pr_state, other);
if ((this = sv_pr_state.fields.this) != -1) {
PR_PushFrame (&sv_pr_state);
PR_RESET_PARAMS (&sv_pr_state);
params = PR_SaveParams (&sv_pr_state);
PR_SetupParams (&sv_pr_state, 3, 1);
P_INT (&sv_pr_state, 0) = E_POINTER (self, this);
P_INT (&sv_pr_state, 1) = 0;
P_INT (&sv_pr_state, 2) = other ? E_POINTER (other, this) : 0;
}
PR_ExecuteProgram (&sv_pr_state, func);
if ((this = sv_pr_state.fields.this) != -1) {
if (this != -1) {
PR_RestoreParams (&sv_pr_state, params);
PR_PopFrame (&sv_pr_state);
}
}

View file

@ -217,18 +217,21 @@ static inline void
sv_pr_exec (edict_t *self, edict_t *other, pr_func_t func)
{
pr_int_t this;
pr_stashed_params_t *params = nullptr;
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, self);
*sv_globals.other = EDICT_TO_PROG (&sv_pr_state, other);
if ((this = sv_pr_state.fields.this) != -1) {
PR_PushFrame (&sv_pr_state);
PR_RESET_PARAMS (&sv_pr_state);
params = PR_SaveParams (&sv_pr_state);
PR_SetupParams (&sv_pr_state, 3, 1);
P_INT (&sv_pr_state, 0) = E_POINTER (self, this);
P_INT (&sv_pr_state, 1) = 0;
P_INT (&sv_pr_state, 2) = other ? E_POINTER (other, this) : 0;
}
PR_ExecuteProgram (&sv_pr_state, func);
if ((this = sv_pr_state.fields.this) != -1) {
if (this != -1) {
PR_RestoreParams (&sv_pr_state, params);
PR_PopFrame (&sv_pr_state);
}
}

View file

@ -954,12 +954,13 @@ SV_SetLocalinfo (const char *key, const char *value)
*sv_globals.time = sv.time;
*sv_globals.self = 0;
PR_PushFrame (&sv_pr_state);
PR_RESET_PARAMS (&sv_pr_state);
auto params = PR_SaveParams (&sv_pr_state);
PR_SetupParams (&sv_pr_state, 3, 1);
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key);
P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue);
P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value);
sv_pr_state.pr_argc = 3;
PR_ExecuteProgram (&sv_pr_state, sv_funcs.LocalinfoChanged);
PR_RestoreParams (&sv_pr_state, params);
PR_PopFrame (&sv_pr_state);
}

View file

@ -821,14 +821,15 @@ cpqw_user_cmd (void)
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
PR_PushFrame (pr);
PR_RESET_PARAMS (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 8, 1);
P_FLOAT (pr, 0) = argc;
for (i = 1; i < argc + 1; i++)
P_STRING (pr, i) = PR_SetTempString (pr, Cmd_Argv (i - 1));
for (; i < 8; i++)
P_STRING (pr, i) = 0;
pr->pr_argc = 8;
PR_ExecuteProgram (pr, cpqw_funcs.ClientCommand);
PR_RestoreParams (pr, params);
PR_PopFrame (pr);
return (int) R_FLOAT (pr);
}

View file

@ -344,7 +344,8 @@ PF_calltimeofday (progs_t *pr, void *data)
Sys_TimeOfDay (&date);
PR_PushFrame (&sv_pr_state);
PR_RESET_PARAMS (pr);
auto params = PR_SaveParams (pr);
PR_SetupParams (pr, 7, 1);
P_FLOAT (pr, 0) = (float) date.sec;
P_FLOAT (pr, 1) = (float) date.min;
P_FLOAT (pr, 2) = (float) date.hour;
@ -352,9 +353,8 @@ PF_calltimeofday (progs_t *pr, void *data)
P_FLOAT (pr, 4) = (float) date.mon;
P_FLOAT (pr, 5) = (float) date.year;
P_STRING (pr, 6) = PR_SetReturnString (pr, date.str);
pr->pr_argc = 7;
PR_ExecuteProgram (pr, (pr_func_t) (f - sv_pr_state.pr_functions));
PR_RestoreParams (pr, params);
PR_PopFrame (&sv_pr_state);
}
}

View file

@ -1060,7 +1060,7 @@ SV_Say (bool team)
if (sv_funcs.ChatMessage) {
PR_PushFrame (&sv_pr_state);
PR_RESET_PARAMS (&sv_pr_state);
PR_SetupParams (&sv_pr_state, 2, 1);
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, p);
P_FLOAT (&sv_pr_state, 1) = (float) team;
@ -1379,11 +1379,10 @@ SV_SetUserinfo (client_t *client, const char *key, const char *value)
PR_PushFrame (&sv_pr_state);
*sv_globals.time = sv.time;
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, client->edict);
PR_RESET_PARAMS (&sv_pr_state);
PR_SetupParams (&sv_pr_state, 3, 1);
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key);
P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue);
P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value);
sv_pr_state.pr_argc = 3;
PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoChanged);
PR_PopFrame (&sv_pr_state);
send_changes = !R_FLOAT (&sv_pr_state);
@ -1431,10 +1430,9 @@ SV_SetInfo_f (void *unused)
if (sv_funcs.UserInfoCallback) {
PR_PushFrame (&sv_pr_state);
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
PR_RESET_PARAMS (&sv_pr_state);
PR_SetupParams (&sv_pr_state, 2, 1);
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key);
P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, value);
sv_pr_state.pr_argc = 2;
PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoCallback);
PR_PopFrame (&sv_pr_state);
if (R_FLOAT (&sv_pr_state))

View file

@ -297,10 +297,9 @@ spawn_progs (qwaq_thread_t *thread)
}
pr_argv[i] = 0;
PR_RESET_PARAMS (pr);
PR_SetupParams (pr, 2, 1);
P_INT (pr, 0) = pr_argc;
P_POINTER (pr, 1) = PR_SetPointer (pr, pr_argv);
pr->pr_argc = 2;
}
static void *

View file

@ -294,10 +294,9 @@ main (int argc, char **argv)
}
pr_argv[i] = 0;
PR_RESET_PARAMS (&test_pr);
PR_SetupParams (&test_pr, 2, 0);
P_INT (&test_pr, 0) = pr_argc;
P_POINTER (&test_pr, 1) = PR_SetPointer (&test_pr, pr_argv);
test_pr.pr_argc = 2;
PR_ExecuteProgram (&test_pr, main_func);
PR_PopFrame (&test_pr);