Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added context struct #43

Merged
merged 9 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ Some of zForth's highlights:
- **Small footprint**: the kernel C code compiles to about 3 or 4 kB of machine
code, depending on the architecture and chosen cell data types.

-- **Support for multiple instances**: The compiler and VM state is stored in a
struct, allowing multiple instances of zForth to run in parallel.

- **Tracing**: zForth is able to show a nice trace of what it is doing under the
hood, see below for an example.

Expand Down
2 changes: 2 additions & 0 deletions forth/core.zf
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
: allot h +! ;
: var : ' lit , here 5 allot here swap ! 5 allot postpone ; ;
: const : ' lit , , postpone ; ;
: constant >r : r> postpone literal postpone ; ;
: variable >r here r> postpone , constant ;

( 'begin' gets the current address, a jump or conditional jump back is generated
by 'again', 'until' )
Expand Down
20 changes: 11 additions & 9 deletions src/atmega8/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ int main(void)
uart_init(UART_BAUD(9600));
stdout = stdin = &f;

zf_ctx _ctx;
zf_ctx *ctx = &_ctx;

/* Initialize zforth */

zf_init(1);
zf_bootstrap();
zf_eval(": . 1 sys ;");
zf_init(ctx, 1);
zf_bootstrap(ctx);
zf_eval(ctx, ": . 1 sys ;");


/* Main loop: read words and eval */
Expand All @@ -47,7 +49,7 @@ int main(void)
int c = getchar();
putchar(c);
if(c == 10 || c == 13 || c == 32) {
zf_result r = zf_eval(buf);
zf_result r = zf_eval(ctx, buf);
if(r != ZF_OK) puts("A");
l = 0;
} else if(l < sizeof(buf)-1) {
Expand All @@ -60,19 +62,19 @@ int main(void)
}


zf_input_state zf_host_sys(zf_syscall_id id, const char *input)
zf_input_state zf_host_sys(zf_ctx *ctx, zf_syscall_id id, const char *input)
{
char buf[16];

switch((int)id) {

case ZF_SYSCALL_EMIT:
putchar((char)zf_pop());
putchar((char)zf_pop(ctx));
fflush(stdout);
break;

case ZF_SYSCALL_PRINT:
itoa(zf_pop(), buf, 10);
itoa(zf_pop(ctx), buf, 10);
puts(buf);
break;
}
Expand All @@ -81,12 +83,12 @@ zf_input_state zf_host_sys(zf_syscall_id id, const char *input)
}


zf_cell zf_host_parse_num(const char *buf)
zf_cell zf_host_parse_num(zf_ctx *ctx, const char *buf)
{
char *end;
zf_cell v = strtol(buf, &end, 0);
if(*end != '\0') {
zf_abort(ZF_ABORT_NOT_A_WORD);
zf_abort(ctx, ZF_ABORT_NOT_A_WORD);
}
return v;
}
Expand Down
2 changes: 1 addition & 1 deletion src/atmega8/zfconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ typedef int32_t zf_cell;
it will cause sign fill, so we need manual specify it */
typedef int zf_int;

/* The type to use for pointers and adresses. 'unsigned int' is usually a good
/* The type to use for pointers and addresses. 'unsigned int' is usually a good
* choice for best performance and smallest code size */

typedef unsigned int zf_addr;
Expand Down
58 changes: 30 additions & 28 deletions src/linux/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
* Evaluate buffer with code, check return value and report errors
*/

zf_result do_eval(const char *src, int line, const char *buf)
zf_result do_eval(zf_ctx *ctx, const char *src, int line, const char *buf)
{
const char *msg = NULL;

zf_result rv = zf_eval(buf);
zf_result rv = zf_eval(ctx, buf);

switch(rv)
{
Expand Down Expand Up @@ -56,15 +56,15 @@
* Load given forth file
*/

void include(const char *fname)
void include(zf_ctx *ctx, const char *fname)
{
char buf[256];

FILE *f = fopen(fname, "rb");
int line = 1;
if(f) {
while(fgets(buf, sizeof(buf), f)) {
do_eval(fname, line++, buf);
do_eval(ctx, fname, line++, buf);
}
fclose(f);
} else {
Expand All @@ -77,10 +77,10 @@
* Save dictionary
*/

static void save(const char *fname)
static void save(zf_ctx *ctx, const char *fname)
{
size_t len;
void *p = zf_dump(&len);
void *p = zf_dump(ctx, &len);
FILE *f = fopen(fname, "wb");
if(f) {
fwrite(p, 1, len, f);
Expand All @@ -93,10 +93,10 @@
* Load dictionary
*/

static void load(const char *fname)
static void load(zf_ctx *ctx, const char *fname)
{
size_t len;
void *p = zf_dump(&len);
void *p = zf_dump(ctx, &len);
FILE *f = fopen(fname, "rb");
if(f) {
fread(p, 1, len, f);
Expand All @@ -111,29 +111,29 @@
* Sys callback function
*/

zf_input_state zf_host_sys(zf_syscall_id id, const char *input)
zf_input_state zf_host_sys(zf_ctx *ctx, zf_syscall_id id, const char *input)
{
switch((int)id) {


/* The core system callbacks */

case ZF_SYSCALL_EMIT:
putchar((char)zf_pop());
putchar((char)zf_pop(ctx));
fflush(stdout);
break;

case ZF_SYSCALL_PRINT:
printf(ZF_CELL_FMT " ", zf_pop());
printf(ZF_CELL_FMT " ", zf_pop(ctx));
break;

case ZF_SYSCALL_TELL: {
zf_cell len = zf_pop();
zf_cell addr = zf_pop();
zf_cell len = zf_pop(ctx);
zf_cell addr = zf_pop(ctx);
if(addr >= ZF_DICT_SIZE - len) {
zf_abort(ZF_ABORT_OUTSIDE_MEM);
zf_abort(ctx, ZF_ABORT_OUTSIDE_MEM);
}
void *buf = (uint8_t *)zf_dump(NULL) + (int)addr;
void *buf = (uint8_t *)zf_dump(ctx, NULL) + (int)addr;
(void)fwrite(buf, 1, len, stdout);
fflush(stdout); }
break;
Expand All @@ -147,18 +147,18 @@
break;

case ZF_SYSCALL_USER + 1:
zf_push(sin(zf_pop()));
zf_push(ctx, sin(zf_pop(ctx)));
break;

case ZF_SYSCALL_USER + 2:
if(input == NULL) {
return ZF_INPUT_PASS_WORD;
}
include(input);
include(ctx, input);
break;

case ZF_SYSCALL_USER + 3:
save("zforth.save");
save(ctx, "zforth.save");
break;

default:
Expand All @@ -174,7 +174,7 @@
* Tracing output
*/

void zf_host_trace(const char *fmt, va_list va)
void zf_host_trace(zf_ctx *ctx, const char *fmt, va_list va)
{
fprintf(stderr, "\033[1;30m");
vfprintf(stderr, fmt, va);
Expand All @@ -186,13 +186,13 @@
* Parse number
*/

zf_cell zf_host_parse_num(const char *buf)
zf_cell zf_host_parse_num(zf_ctx *ctx, const char *buf)
{
zf_cell v;
int n = 0;
int r = sscanf(buf, ZF_SCAN_FMT"%n", &v, &n);
if(r != 1 || buf[n] != '\0') {
zf_abort(ZF_ABORT_NOT_A_WORD);
zf_abort(ctx, ZF_ABORT_NOT_A_WORD);
}
return v;
}
Expand Down Expand Up @@ -247,31 +247,33 @@
argc -= optind;
argv += optind;

zf_ctx *ctx = malloc(sizeof(zf_ctx));
printf("%p\n", (void *)ctx);

/* Initialize zforth */

zf_init(trace);
zf_init(ctx, trace);


/* Load dict from disk if requested, otherwise bootstrap fort
* dictionary */

if(fname_load) {
load(fname_load);
load(ctx, fname_load);
} else {
zf_bootstrap();
zf_bootstrap(ctx);
}


/* Include files from command line */

for(i=0; i<argc; i++) {
include(argv[i]);
include(ctx, argv[i]);

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This argument to a file access function is derived from
user input (a command-line argument)
and then passed to include(fname), which calls fopen(__filename).

Copilot Autofix AI 19 days ago

To fix the problem, we need to validate the user input before using it to construct a file path. Specifically, we should ensure that the file path provided by the user does not contain any path separators or ".." sequences, which could lead to path traversal vulnerabilities. We can achieve this by adding a validation function that checks for these invalid sequences and rejects the input if any are found.

Suggested changeset 1
src/linux/main.c

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/linux/main.c b/src/linux/main.c
--- a/src/linux/main.c
+++ b/src/linux/main.c
@@ -270,2 +270,6 @@
 	for(i=0; i<argc; i++) {
+		if (strstr(argv[i], "..") || strchr(argv[i], '/') || strchr(argv[i], '\\')) {
+			fprintf(stderr, "Invalid file path: %s\n", argv[i]);
+			continue;
+		}
 		include(ctx, argv[i]);
EOF
@@ -270,2 +270,6 @@
for(i=0; i<argc; i++) {
if (strstr(argv[i], "..") || strchr(argv[i], '/') || strchr(argv[i], '\\')) {
fprintf(stderr, "Invalid file path: %s\n", argv[i]);
continue;
}
include(ctx, argv[i]);
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
}

if(!quiet) {
zf_cell here;
zf_uservar_get(ZF_USERVAR_HERE, &here);
zf_uservar_get(ctx, ZF_USERVAR_HERE, &here);
printf("Welcome to zForth, %d bytes used\n", (int)here);
}

Expand All @@ -289,7 +291,7 @@

if(strlen(buf) > 0) {

do_eval("stdin", ++line, buf);
do_eval(ctx, "stdin", ++line, buf);
printf("\n");

add_history(buf);
Expand All @@ -303,7 +305,7 @@
for(;;) {
char buf[4096];
if(fgets(buf, sizeof(buf), stdin)) {
do_eval("stdin", ++line, buf);
do_eval(ctx, "stdin", ++line, buf);
printf("\n");
} else {
break;
Expand Down
2 changes: 1 addition & 1 deletion src/linux/zfconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ typedef float zf_cell;
it will cause sign fill, so we need manual specify it */
typedef int zf_int;

/* The type to use for pointers and adresses. 'unsigned int' is usually a good
/* The type to use for pointers and addresses. 'unsigned int' is usually a good
* choice for best performance and smallest code size */

typedef unsigned int zf_addr;
Expand Down
Loading
Loading