[gamecode] Add function PR_PushTempString

This "pushes" a temp string onto the callee's stack frame after removing
it from the caller's stack frame. This is so builtins can pass
auto-freed memory to called progs code. No checking is done, but mayhem
is likely to ensue if a string is pushed that was allocated in an
earlier frame.
This commit is contained in:
Bill Currie 2020-03-09 23:36:09 +09:00
parent 9b0368039e
commit f290b115a5
3 changed files with 44 additions and 1 deletions

View file

@ -1286,6 +1286,17 @@ string_t PR_SetTempString(progs_t *pr, const char *s);
*/
string_t PR_AllocTempBlock (progs_t *pr, size_t size);
/** Push a temporary string to the callee stack frame
This is for when the temp string needs to be freed when the called function
returns rather than the calling function. It is an error to push a non-temp
string.
\param pr pointer to ::progs_t VM struct
\param num string index of the temp string
*/
void PR_PushTempString (progs_t *pr, string_t num);
/** Make a temporary progs string that is the concatenation of two C strings.
\param pr pointer to ::progs_t VM struct
\param a C string
@ -1733,6 +1744,7 @@ struct progs_s {
///@{
struct prstr_resources_s *pr_string_resources;
strref_t *pr_xtstr;
strref_t *pr_pushtstr;
int float_promoted; ///< for PR_Sprintf
///@}

View file

@ -123,7 +123,8 @@ PR_PushFrame (progs_t *pr)
frame->f = pr->pr_xfunction;
frame->tstr = pr->pr_xtstr;
pr->pr_xtstr = 0;
pr->pr_xtstr = pr->pr_pushtstr;
pr->pr_pushtstr = 0;
pr->pr_xfunction = 0;
}
@ -137,6 +138,15 @@ PR_PopFrame (progs_t *pr)
if (pr->pr_xtstr)
PR_FreeTempStrings (pr);
// normally, this won't happen, but if a builtin pushed a temp string
// when calling a function and the callee was another builtin that
// did not call a progs function, then the push strings will still be
// valid because PR_EnterFunction was never called
if (pr->pr_pushtstr) {
pr->pr_xtstr = pr->pr_pushtstr;
pr->pr_pushtstr = 0;
PR_FreeTempStrings (pr);
}
// up stack
frame = pr->pr_stack + --pr->pr_depth;

View file

@ -520,6 +520,27 @@ PR_AllocTempBlock (progs_t *pr, size_t size)
return pr_settempstring (pr, res, pr_strmalloc (pr, size));
}
VISIBLE void
PR_PushTempString (progs_t *pr, string_t num)
{
prstr_resources_t *res = pr->pr_string_resources;
strref_t *ref = get_strref (res, num);
strref_t **temp_ref;
if (!ref || ref->type != str_temp) {
PR_Error (pr, "attempt to push a non-temp string");
}
for (temp_ref = &pr->pr_xtstr; *temp_ref; temp_ref = &(*temp_ref)->next) {
if (*temp_ref == ref) {
*temp_ref = ref->next;
ref->next = pr->pr_pushtstr;
pr->pr_pushtstr = ref;
return;
}
}
PR_Error (pr, "attempt to push stale temp string");
}
VISIBLE string_t
PR_SetDynamicString (progs_t *pr, const char *s)
{