Fix load_varargs to prevent local var corruption

Assigning to a varargs variable that is not passed by the C caller can result in corruption of another parameter. EG: the var contains data for another parameter, which is then changed unexpectedly. The code was rewritten to assign to a new variable, to prevent this from happening.
This commit is contained in:
Justin Ethier 2015-04-23 15:06:49 -04:00
parent 5855c77a74
commit 4230295683
2 changed files with 23 additions and 22 deletions

View file

@ -878,7 +878,7 @@
((pair? (cdr formals)) ((pair? (cdr formals))
(string-append ", " (c-compile-formals (cdr formals) type))) (string-append ", " (c-compile-formals (cdr formals) type)))
((not (equal? 'args:fixed type)) ((not (equal? 'args:fixed type))
(string-append ", object " (mangle (cdr formals)) ", ...")) (string-append ", object " (mangle (cdr formals)) "_raw, ..."))
(else (else
""))))) "")))))
@ -925,7 +925,9 @@
; (number->string (length (lambda-formals->list exp))) ");" ; (number->string (length (lambda-formals->list exp))) ");"
"load_varargs(" "load_varargs("
(mangle (lambda-varargs-var exp)) (mangle (lambda-varargs-var exp))
", argc - " (number->string ", "
(mangle (lambda-varargs-var exp))
"_raw, argc - " (number->string
(- (length (lambda-formals->list exp)) (- (length (lambda-formals->list exp))
1 1
(if has-closure? 1 0))) (if has-closure? 1 0)))

View file

@ -37,28 +37,27 @@ static object cell_get(object cell){
our compiler will compute the difference between the number of required our compiler will compute the difference between the number of required
args and the number of provided ones, and pass the difference as 'count' args and the number of provided ones, and pass the difference as 'count'
*/ */
#define load_varargs(var, count) { \ #define load_varargs(var, arg_var, count) \
int i; \ list var = (count > 0) ? alloca(sizeof(cons_type)*count) : nil; \
object tmp; \ { \
list args = nil; \ int i; \
va_list va; \ object tmp; \
if (count > 0) { \ va_list va; \
args = alloca(sizeof(cons_type)*count); \ if (count > 0) { \
va_start(va, var); \ va_start(va, arg_var); \
for (i = 0; i < count; i++) { \ for (i = 0; i < count; i++) { \
if (i) { \ if (i) { \
tmp = va_arg(va, object); \ tmp = va_arg(va, object); \
} else { \ } else { \
tmp = var; \ tmp = arg_var; \
} \
var[i].tag = cons_tag; \
var[i].cons_car = tmp; \
var[i].cons_cdr = (i == (count-1)) ? nil : &var[i + 1]; \
} \ } \
args[i].tag = cons_tag; \ va_end(va); \
args[i].cons_car = tmp; \
args[i].cons_cdr = (i == (count-1)) ? nil : &args[i + 1]; \
} \ } \
va_end(va); \ }
} \
var = args; \
}
/* Prototypes for Lisp built-in functions. */ /* Prototypes for Lisp built-in functions. */