Skip to content

Commit

Permalink
Fix default argument for varargs and inherited functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
thefallentree committed Jan 7, 2024
1 parent 5ccdde1 commit ff7e617
Show file tree
Hide file tree
Showing 20 changed files with 253 additions and 91 deletions.
8 changes: 5 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL

# Sanitizer support
if (ENABLE_SANITIZER)
add_compile_options("-fsanitize=address,undefined")
add_compile_options("-fsanitize=address")
#add_compile_options("-fsanitize=undefined")
add_compile_options("-fno-common")
# add_linker_options is only avaiable cmake 3.13
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -fno-common")

add_link_options("-fsanitize=address")
#add_link_options("-fsanitize=undefined")
else ()
add_compile_options(
"-D_FORTIFY_SOURCE=2"
Expand Down
1 change: 1 addition & 0 deletions src/base/internal/md.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "base/internal/log.h"
#include "base/internal/stralloc.h"
#include "outbuf.h"
#include "debugmalloc.h"

#include <fmt/format.h>

Expand Down
67 changes: 39 additions & 28 deletions src/compiler/internal/compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -757,8 +757,7 @@ int copy_functions(program_t *from, int typemod) {
num_functions = from->num_functions_defined + from->last_inherited;

if (from->num_functions_defined &&
(from->function_table[from->num_functions_defined - 1].funcname[0] ==
APPLY___INIT_SPECIAL_CHAR)) {
(strcmp(APPLY___INIT, from->function_table[from->num_functions_defined - 1].funcname)== 0)) {
initializer = --num_functions;
}

Expand Down Expand Up @@ -1025,11 +1024,10 @@ int arrange_call_inherited(char *name, parse_node_t *node) {
* function. Thus, there are tests to avoid generating error messages more
* than once by looking at (flags & NAME_PROTOTYPE).
*/
/* Warning: returns an index into A_FUNCTIONS, not the full
* function list
/* Returns an index into A_FUNCTIONS_DEFS.
*/
int define_new_function(const char *name, int num_arg, int num_local, int flags, int type) {
int oldindex, num, newindex;
int oldindex=-1, num=-1, newindex=-1;
unsigned short argument_start_index;
ident_hash_elem_t *ihe;
function_t *funp = nullptr;
Expand Down Expand Up @@ -2059,18 +2057,22 @@ static int compare_funcs(const void *x, const void *y) {
/* make sure #global_init# stays last; also shuffle empty entries to
* the end so we can delete them easily.
*/
if (n1[0] == '#') {
sp1 = 1;
} else if (FUNC(*(unsigned short *)x)->address == ADDRESS_MAX) {
if (FUNC(*(unsigned short *)x)->address == ADDRESS_MAX) {
sp1 = 3;
} else if (strcmp(n1, APPLY___INIT) == 0) {
sp1 = 2;
} else if (n1[0] == APPLY___INIT_SPECIAL_CHAR) {
sp1 = 1;
} else {
sp1 = 0;
}

if (n2[0] == '#') {
sp2 = 1;
} else if (FUNC(*(unsigned short *)y)->address == ADDRESS_MAX) {
if (FUNC(*(unsigned short *)y)->address == ADDRESS_MAX) {
sp2 = 3;
} else if (strcmp(n2, APPLY___INIT) == 0) {
sp2 = 2;
} else if (n2[0] == APPLY___INIT_SPECIAL_CHAR) {
sp2 = 1;
} else {
sp2 = 0;
}
Expand Down Expand Up @@ -2138,8 +2140,7 @@ static void handle_functions() {
inherited_prog->num_functions_defined;

if (inherited_prog->num_functions_defined &&
inherited_prog->function_table[inherited_prog->num_functions_defined - 1].funcname[0] ==
APPLY___INIT_SPECIAL_CHAR) {
strcmp(APPLY___INIT, inherited_prog->function_table[inherited_prog->num_functions_defined - 1].funcname) == 0) {
comp_last_inherited--;
}
} else {
Expand Down Expand Up @@ -2191,21 +2192,6 @@ static void handle_functions() {
}
}
}

// Fixup the default argument function index
for (int i = 0; i < num_func; i++) {
constexpr auto default_args_limit = sizeof(FUNC(i)->default_args_findex) / sizeof(FUNC(i)->default_args_findex[0]);
auto *func = FUNC(i);
for (int j = 0; j < default_args_limit; j++) {
if (func->default_args_findex[j] != 0) {
func->default_args_findex[j] = comp_sorted_funcs[func->default_args_findex[j]];
}
}
}

if (total_func) {
FREE((char *)comp_sorted_funcs);
}
}

/*
Expand Down Expand Up @@ -2378,6 +2364,31 @@ static program_t *epilog(void) {
prog->function_table = reinterpret_cast<function_t *>(p);
for (i = 0; i < num_func; i++) {
prog->function_table[i] = *FUNC(func_index_map[i]);
// debug_message("Function table %d: %s\n", i, prog->function_table[i].funcname);
}

// Fixup the default argument function index
for (int i = 0; i < num_func; i++) {
auto *func = &prog->function_table[i];
constexpr auto default_args_limit = sizeof(func->default_args_findex) / sizeof(func->default_args_findex[0]);
if (func->min_arg != func->num_arg) {
// debug_message("Handling default arguments for %d: %s\n", i, func->funcname);
for (int j = 0; j < default_args_limit; j++) {
auto findex = func->default_args_findex[j];
if (findex != 0) {
func->default_args_findex[j] = comp_sorted_funcs[findex];
// debug_message("Default argument %d of function %s was %d, now is %d\n", j, func->funcname, findex, func->default_args_findex[j]);
if(prog->function_table[(func->default_args_findex[j])].funcname[0] != APPLY___INIT_SPECIAL_CHAR) {
func->default_args_findex[j] = 0; // attempt to continue;
DEBUG_FATAL("Bad new default argument index calculated\n");
}
}
}
}
}

if (num_func) {
FREE((char *)comp_sorted_funcs);
}

p += align(sizeof(function_t) * num_func);
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/internal/disassembler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ static void print_function_sig(FILE *f, program_t *prog, int idx) {
auto end = &buf[sizeof(buf) - 1];

auto funp = prog->function_table[idx];
auto funflags = prog->function_flags[prog->last_inherited + idx];

buf[0] = '\0';
get_type_modifiers(&buf[0], end, funflags);
fprintf(f, "%s", buf);

get_type_name(&buf[0], end, funp.type);
fprintf(f, "%s", buf);
fprintf(f, "%s", funp.funcname);
Expand All @@ -220,6 +226,9 @@ static void print_function_sig(FILE *f, program_t *prog, int idx) {
}
} else {
fprintf(f, "args: %d", funp.num_arg);
if (funp.min_arg != funp.num_arg) {
fprintf(f, "min args: %d", funp.num_arg);
}
}
}
fprintf(f, ")");
Expand Down
13 changes: 7 additions & 6 deletions src/compiler/internal/grammar_rules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void rule_func(parse_node_t **function, LPC_INT type, LPC_INT optional_star, cha
(*function)->l.number = max_num_locals;
(*function)->r.expr = *block_or_semi;

if (argument.num_arg) {
if (!(*func_types & FUNC_TRUE_VARARGS) && argument.num_arg) {
bool have_default_args = false;
auto default_args_limit = sizeof(FUNCTION_DEF(fun)->default_args_findex) / sizeof(FUNCTION_DEF(fun)->default_args_findex[0]);
for (int i = 0; i < argument.num_arg; i++) {
Expand All @@ -215,13 +215,14 @@ void rule_func(parse_node_t **function, LPC_INT type, LPC_INT optional_star, cha
return ;
}
FUNCTION_DEF(fun)->min_arg--;
auto funcname = fmt::format(FMT_STRING("__{}_{}"), identifier, local.ihe->name);

// the funcnum here will change in epilog(), see fixup in handle_functions()
// TODO: generate a unique name for the function
auto funcname = fmt::format(FMT_STRING("#__{}_{}_{}"), get_current_time(), identifier, local.ihe->name, local.ihe->name);
// the funcnum here will change in epilog().
auto funcnum = define_new_function(funcname.c_str(), 0, 0,
*func_types | DECL_NOMASK, // same access as origin function
(*func_types & DECL_ACCESS) | DECL_NOMASK, // same access as origin function
type_of_locals_ptr[locals_ptr[i].runtime_index]);
FUNCTION_DEF(fun)->default_args_findex[i] = funcnum;
FUNCTION_DEF(fun)->default_args_findex[i] = FUNCTION_TEMP(funcnum)->u.index;
// debug_message("function %s (%d), new def arg function %s (%d)\n", identifier, fun, funcname.c_str(), funcnum);

parse_node_t *node_return;
CREATE_RETURN(node_return, local.funcptr_default);
Expand Down
16 changes: 14 additions & 2 deletions src/packages/develop/checkmemory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ static void mark_object(object_t *ob) {
outbuf_addv(&out, "can't mark variables; %s is swapped.\n", ob->obname);
}

static void mark_funp(funptr_t *fp);

void mark_svalue(svalue_t *sv) {
switch (sv->type) {
case T_OBJECT:
Expand Down Expand Up @@ -229,6 +231,7 @@ void mark_svalue(svalue_t *sv) {
EXTRA_REF(BLOCK(sv->u.string))++;
break;
}
break;
}
}

Expand Down Expand Up @@ -706,7 +709,8 @@ void check_all_blocks(int flag) {
#ifdef PACKAGE_ASYNC
async_mark_request();
#endif
mark_svalue(&apply_ret_value);
free_svalue(&apply_ret_value, "checkmemory");
apply_ret_value = const0u;

if (master_ob) {
master_ob->extra_ref++;
Expand Down Expand Up @@ -904,10 +908,18 @@ void check_all_blocks(int flag) {
}
if (fp->hdr.ref != fp->hdr.extra_ref) {
outbuf_addv(&out,
"Bad ref count for function pointer (owned by %s), "
"Bad ref count for function pointer %p (type %d, owned by %s), "
"is %d - should be %d\n",
fp,
fp->hdr.type,
(fp->hdr.owner ? fp->hdr.owner->obname : "(null)"), fp->hdr.ref,
fp->hdr.extra_ref);
switch(fp->hdr.type) {
case FP_FUNCTIONAL:
outbuf_addv(&out, "fp offset %04x :\n", fp->f.functional.offset);
dump_prog(fp->f.functional.prog, stdout, 1|2);
}
md_print_ref_journal(entry, &out);
}
break;
case TAG_BUFFER:
Expand Down
18 changes: 14 additions & 4 deletions src/vm/internal/apply.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "compiler/internal/compiler.h"
#include "compiler/internal/lex.h"
#include "compiler/internal/disassembler.h"
#include "applies_table.autogen.h"

// global static result
svalue_t apply_ret_value;
Expand Down Expand Up @@ -243,7 +244,7 @@ int apply_low(const char *fun, object_t *ob, int num_arg) {
auto *progp = entry.progp;
auto *funcp = entry.funp;

if (!(funcp->type & FUNC_VARARGS) && funcp->min_arg != funcp->num_arg) {
if (!(funflags & FUNC_TRUE_VARARGS) && funcp->min_arg != funcp->num_arg) {
if (num_arg < funcp->min_arg) {
// COMPAT: fluffos allow apply to call functions with fewer arguments than required, so we fix it up here
push_undefineds(funcp->min_arg - num_arg);
Expand All @@ -259,10 +260,12 @@ int apply_low(const char *fun, object_t *ob, int num_arg) {
for (int i = num_arg; i < funcp->num_arg; i++) {
auto current_sp = sp;
auto *default_funcp =progp->function_table + funcp->default_args_findex[i];
if(default_funcp->funcname[0]!='_') {
if(default_funcp->funcname[0]!=APPLY___INIT_SPECIAL_CHAR) {
#ifdef DEBUG
dump_vm_state();
dump_prog(progp, stdout, 1|2);
error("Illegal default argument function name %s in %s\n", default_funcp->funcname, progp->filename);
#endif
error("Driver Bug: Illegal default argument function name %s in %s\n", default_funcp->funcname, progp->filename);
}
// notice we don't change current_object here, so the default arguments closure
// will be called in the context of the caller
Expand All @@ -274,14 +277,21 @@ int apply_low(const char *fun, object_t *ob, int num_arg) {
current_prog = progp;
call_program(progp, default_funcp->address);

if (sp - current_sp != 1 || sp->type != T_FUNCTION) {
error("Driver Bug: Bad stack after default arguments call.");
}

// get the returned closure then evaluate for the real value
svalue_t sv_funcp;
assign_svalue_no_free(&sv_funcp, sp);
pop_stack();

DEBUG_CHECK((sv_funcp.type != T_FUNCTION || sv_funcp.u.fp == nullptr) && dump_vm_state(),
"apply_low: default args closure returned null.");

// evaluate the closure in current context
push_svalue(call_function_pointer(sv_funcp.u.fp, 0));
free_svalue(&sv_funcp, "apply_low");
free_svalue(&sv_funcp, "apply_low: default args closure");

DEBUG_CHECK(sp - current_sp != 1 && dump_vm_state(), "Bad stack after default arguments call.");
}
Expand Down
2 changes: 1 addition & 1 deletion src/vm/internal/base/debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ bool dump_vm_state() {
// Dump control stack
auto *p = csp;
int depth = 1;
while (p != control_stack) {
while (p != control_stack && p->prog != nullptr) {
std::cout << "control stack: "<< -depth << "\n";
std::cout << prefix << "framekind = " << framekind_name(p->framekind) << "(" << p->framekind << ")\n";
std::cout << prefix << "ob = " << print_object_ptr(p->ob) << "\n";
Expand Down
2 changes: 2 additions & 0 deletions src/vm/internal/base/function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "compiler/internal/lex.h" // for instrs, FIXME

#include "packages/core/replace_program.h"
#include "backward.hpp"

void dealloc_funp(funptr_t *fp) {
program_t *prog = nullptr;
Expand Down Expand Up @@ -206,6 +207,7 @@ funptr_t *make_functional_funp(short num_arg, short num_local, short len, svalue
}

fp->hdr.ref = 1;
md_record_ref_journal(PTR_TO_NODET(fp), true, 1, "make_functional_funp");
return fp;
}

Expand Down
2 changes: 1 addition & 1 deletion src/vm/internal/base/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct functional_t {
struct program_t *prog;
int offset;
short vio;
char lpccode[80];
// char lpccode[80];
};

/* common header */
Expand Down
Loading

0 comments on commit ff7e617

Please sign in to comment.