mirror of
https://github.com/justinethier/cyclone.git
synced 2025-07-04 11:46:35 +02:00
Issue #143 - Max recursion depth for printing
Enforce a maximum C recursion depth when printing data structures. This protects against cases where a circular data structure may produce infinite output, blowing the stack. The recursive limit is sufficiently large such that a non-circular structure should not be impacted.
This commit is contained in:
parent
460147601f
commit
d3f7262414
2 changed files with 41 additions and 46 deletions
|
@ -16,6 +16,11 @@
|
||||||
(set-cdr! l1 l2)
|
(set-cdr! l1 l2)
|
||||||
(display l1)
|
(display l1)
|
||||||
|
|
||||||
|
(define l1 (list 1 2 3))
|
||||||
|
(define l2 (list 1 l1 3))
|
||||||
|
(set-cdr! (cdr l1) l2)
|
||||||
|
(write l1)
|
||||||
|
|
||||||
; TODO: need to compare pointers to prevent this sort of thing:
|
; TODO: need to compare pointers to prevent this sort of thing:
|
||||||
;
|
;
|
||||||
; cyclone> (display #(1 1 1 1 1 1 1 1))
|
; cyclone> (display #(1 1 1 1 1 1 1 1))
|
||||||
|
|
82
runtime.c
82
runtime.c
|
@ -22,6 +22,8 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
static const int MAX_DEPTH = 512;
|
||||||
|
|
||||||
static uint32_t Cyc_utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte);
|
static uint32_t Cyc_utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte);
|
||||||
static int Cyc_utf8_count_code_points_and_bytes(uint8_t* s, char_type *codepoint, int *cpts, int *bytes);
|
static int Cyc_utf8_count_code_points_and_bytes(uint8_t* s, char_type *codepoint, int *cpts, int *bytes);
|
||||||
|
|
||||||
|
@ -1031,29 +1033,7 @@ object Cyc_display_va_list(void *data, object x, object opts)
|
||||||
return Cyc_display(data, x, fp);
|
return Cyc_display(data, x, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
object _next(object x) {
|
object _Cyc_display(void *data, object x, FILE * port, int depth)
|
||||||
if (x == NULL || is_value_type(x)) {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type_of(x)) {
|
|
||||||
case pair_tag:
|
|
||||||
return cdr(x);
|
|
||||||
case vector_tag: {
|
|
||||||
vector_type *v = (vector)x;
|
|
||||||
if (v->num_elements > 1) {
|
|
||||||
return v->elements[1];
|
|
||||||
} else {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
object _Cyc_display(void *data, object x, FILE * port, object fast)
|
|
||||||
{
|
{
|
||||||
object tmp = NULL;
|
object tmp = NULL;
|
||||||
object has_cycle = boolean_f;
|
object has_cycle = boolean_f;
|
||||||
|
@ -1134,17 +1114,15 @@ object _Cyc_display(void *data, object x, FILE * port, object fast)
|
||||||
fprintf(port, "#(");
|
fprintf(port, "#(");
|
||||||
if (has_cycle == boolean_t) {
|
if (has_cycle == boolean_t) {
|
||||||
fprintf(port, "...");
|
fprintf(port, "...");
|
||||||
|
} else if (depth == MAX_DEPTH) {
|
||||||
|
fprintf(port, "...");
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < ((vector) x)->num_elements; i++) {
|
for (i = 0; i < ((vector) x)->num_elements; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
fprintf(port, " ");
|
fprintf(port, " ");
|
||||||
}
|
}
|
||||||
object o = ((vector) x)->elements[i];
|
_Cyc_display(data, ((vector) x)->elements[i], port, depth + 1);
|
||||||
if (o == fast) {
|
|
||||||
fprintf(port, "...");
|
|
||||||
} else {
|
|
||||||
_Cyc_display(data, o, port, _next(_next(fast)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(port, ")");
|
fprintf(port, ")");
|
||||||
|
@ -1160,14 +1138,13 @@ object _Cyc_display(void *data, object x, FILE * port, object fast)
|
||||||
fprintf(port, ")");
|
fprintf(port, ")");
|
||||||
break;
|
break;
|
||||||
case pair_tag:
|
case pair_tag:
|
||||||
if (x == fast) {
|
|
||||||
fprintf(port, "...");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
has_cycle = Cyc_has_cycle(x);
|
has_cycle = Cyc_has_cycle(x);
|
||||||
fprintf(port, "(");
|
fprintf(port, "(");
|
||||||
_Cyc_display(data, car(x), port, _next(_next(fast)));
|
if (depth == MAX_DEPTH) {
|
||||||
|
fprintf(port, "...");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
_Cyc_display(data, car(x), port, depth + 1);
|
||||||
|
|
||||||
// Experimenting with displaying lambda defs in REPL
|
// Experimenting with displaying lambda defs in REPL
|
||||||
// not good enough but this is a start. would probably need
|
// not good enough but this is a start. would probably need
|
||||||
|
@ -1175,7 +1152,7 @@ object _Cyc_display(void *data, object x, FILE * port, object fast)
|
||||||
if (Cyc_is_symbol(car(x)) == boolean_t &&
|
if (Cyc_is_symbol(car(x)) == boolean_t &&
|
||||||
strncmp(((symbol) car(x))->desc, "procedure", 10) == 0) {
|
strncmp(((symbol) car(x))->desc, "procedure", 10) == 0) {
|
||||||
fprintf(port, " ");
|
fprintf(port, " ");
|
||||||
_Cyc_display(data, cadr(x), port, _next(_next(cadr(x)))); // TODO: fast?
|
_Cyc_display(data, cadr(x), port, depth + 1);
|
||||||
fprintf(port, " ...)"); /* skip body and env for now */
|
fprintf(port, " ...)"); /* skip body and env for now */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1186,13 +1163,17 @@ object _Cyc_display(void *data, object x, FILE * port, object fast)
|
||||||
break; /* arbitrary number, for now */
|
break; /* arbitrary number, for now */
|
||||||
}
|
}
|
||||||
fprintf(port, " ");
|
fprintf(port, " ");
|
||||||
_Cyc_display(data, car(tmp), port, _next(_next(fast)));
|
if (depth == MAX_DEPTH) {
|
||||||
|
fprintf(port, "...");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
_Cyc_display(data, car(tmp), port, depth + 1);
|
||||||
}
|
}
|
||||||
if (has_cycle == boolean_t) {
|
if (has_cycle == boolean_t) {
|
||||||
fprintf(port, " ...");
|
fprintf(port, " ...");
|
||||||
} else if (tmp) {
|
} else if (tmp) {
|
||||||
fprintf(port, " . ");
|
fprintf(port, " . ");
|
||||||
_Cyc_display(data, tmp, port, _next(_next(fast)));
|
_Cyc_display(data, tmp, port, depth + 1);
|
||||||
}
|
}
|
||||||
fprintf(port, ")");
|
fprintf(port, ")");
|
||||||
break;
|
break;
|
||||||
|
@ -1232,11 +1213,12 @@ object _Cyc_display(void *data, object x, FILE * port, object fast)
|
||||||
fprintf(port, "Cyc_display: bad tag x=%d\n", ((closure) x)->tag);
|
fprintf(port, "Cyc_display: bad tag x=%d\n", ((closure) x)->tag);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
return quote_void;
|
return quote_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
object Cyc_display(void *data, object x, FILE * port) {
|
object Cyc_display(void *data, object x, FILE * port) {
|
||||||
return _Cyc_display(data, x, port, _next(x));
|
return _Cyc_display(data, x, port, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatch_write_va(void *data, object clo, int argc, object *args)
|
void dispatch_write_va(void *data, object clo, int argc, object *args)
|
||||||
|
@ -1279,7 +1261,7 @@ object Cyc_write_va_list(void *data, object x, object opts)
|
||||||
return Cyc_write(data, x, fp);
|
return Cyc_write(data, x, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static object _Cyc_write(void *data, object x, FILE * port)
|
static object _Cyc_write(void *data, object x, FILE * port, int depth)
|
||||||
{
|
{
|
||||||
object tmp = NULL;
|
object tmp = NULL;
|
||||||
object has_cycle = boolean_f;
|
object has_cycle = boolean_f;
|
||||||
|
@ -1343,12 +1325,15 @@ static object _Cyc_write(void *data, object x, FILE * port)
|
||||||
fprintf(port, "#(");
|
fprintf(port, "#(");
|
||||||
if (has_cycle == boolean_t) {
|
if (has_cycle == boolean_t) {
|
||||||
fprintf(port, "...");
|
fprintf(port, "...");
|
||||||
|
} else if (depth == MAX_DEPTH) {
|
||||||
|
fprintf(port, "...");
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < ((vector) x)->num_elements; i++) {
|
for (i = 0; i < ((vector) x)->num_elements; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
fprintf(port, " ");
|
fprintf(port, " ");
|
||||||
}
|
}
|
||||||
_Cyc_write(data, ((vector) x)->elements[i], port);
|
_Cyc_write(data, ((vector) x)->elements[i], port, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(port, ")");
|
fprintf(port, ")");
|
||||||
|
@ -1356,7 +1341,11 @@ static object _Cyc_write(void *data, object x, FILE * port)
|
||||||
case pair_tag:
|
case pair_tag:
|
||||||
has_cycle = Cyc_has_cycle(x);
|
has_cycle = Cyc_has_cycle(x);
|
||||||
fprintf(port, "(");
|
fprintf(port, "(");
|
||||||
_Cyc_write(data, car(x), port);
|
if (depth == MAX_DEPTH) {
|
||||||
|
fprintf(port, "...");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
_Cyc_write(data, car(x), port, depth + 1);
|
||||||
|
|
||||||
// Experimenting with displaying lambda defs in REPL
|
// Experimenting with displaying lambda defs in REPL
|
||||||
// not good enough but this is a start. would probably need
|
// not good enough but this is a start. would probably need
|
||||||
|
@ -1364,7 +1353,7 @@ static object _Cyc_write(void *data, object x, FILE * port)
|
||||||
if (Cyc_is_symbol(car(x)) == boolean_t &&
|
if (Cyc_is_symbol(car(x)) == boolean_t &&
|
||||||
strncmp(((symbol) car(x))->desc, "procedure", 10) == 0) {
|
strncmp(((symbol) car(x))->desc, "procedure", 10) == 0) {
|
||||||
fprintf(port, " ");
|
fprintf(port, " ");
|
||||||
_Cyc_write(data, cadr(x), port);
|
_Cyc_write(data, cadr(x), port, depth + 1);
|
||||||
fprintf(port, " ...)"); /* skip body and env for now */
|
fprintf(port, " ...)"); /* skip body and env for now */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1375,25 +1364,26 @@ static object _Cyc_write(void *data, object x, FILE * port)
|
||||||
break; /* arbitrary number, for now */
|
break; /* arbitrary number, for now */
|
||||||
}
|
}
|
||||||
fprintf(port, " ");
|
fprintf(port, " ");
|
||||||
_Cyc_write(data, car(tmp), port);
|
_Cyc_write(data, car(tmp), port, depth + 1);
|
||||||
}
|
}
|
||||||
if (has_cycle == boolean_t) {
|
if (has_cycle == boolean_t) {
|
||||||
fprintf(port, " ...");
|
fprintf(port, " ...");
|
||||||
} else if (tmp) {
|
} else if (tmp) {
|
||||||
fprintf(port, " . ");
|
fprintf(port, " . ");
|
||||||
_Cyc_write(data, tmp, port);
|
_Cyc_write(data, tmp, port, depth + 1);
|
||||||
}
|
}
|
||||||
fprintf(port, ")");
|
fprintf(port, ")");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Cyc_display(data, x, port);
|
Cyc_display(data, x, port);
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
return quote_void;
|
return quote_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
object Cyc_write(void *data, object x, FILE * port)
|
object Cyc_write(void *data, object x, FILE * port)
|
||||||
{
|
{
|
||||||
object y = _Cyc_write(data, x, port);
|
object y = _Cyc_write(data, x, port, 0);
|
||||||
//fprintf(port, "\n");
|
//fprintf(port, "\n");
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue