From f706e107c6945ee581a67238d6a11cd288dc8038 Mon Sep 17 00:00:00 2001 From: YungcheLi Date: Wed, 12 Feb 2025 07:30:16 +0000 Subject: [PATCH] Return -1 for syscall close on fd less than 3 Some user programs attempt to close stdout or stderr, but rv32emu relies on these file descriptors for logging and debugging. Allowing their closure could lead to unexpected behavior, making it difficult to trace emulator activity. This commit modifies the syscall close implementation to return -1 when attempting to close file descriptors less than 3. By ensuring these essential output channels remain open, rv32emu retains its ability to print logs and error messages. User programs receive a clear failure signal instead of silently closing critical streams. Close #435 Co-authored-by: ChinYikMing --- src/emulate.c | 16 +++++++++++----- src/riscv.c | 9 +++++++++ src/riscv.h | 8 ++++++++ src/syscall.c | 16 ++++++++++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/emulate.c b/src/emulate.c index a8c79e9a8..30474c356 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -1078,11 +1078,17 @@ void rv_step(void *arg) assert(block->satp == rv->csr_satp); #endif - /* After emulating the previous block, it is determined whether the - * branch is taken or not. The IR array of the current block is then - * assigned to either the branch_taken or branch_untaken pointer of - * the previous block. - */ +#if !RV32_HAS(SYSTEM) + /* on exit */ + if (unlikely(block->ir_head->pc == PRIV(rv)->exit_addr)) + PRIV(rv)->on_exit = true; +#endif + + /* After emulating the previous block, it is determined whether the + * branch is taken or not. The IR array of the current block is then + * assigned to either the branch_taken or branch_untaken pointer of + * the previous block. + */ #if RV32_HAS(BLOCK_CHAINING) if (prev diff --git a/src/riscv.c b/src/riscv.c index d277618e4..61d95d2d8 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -434,6 +434,15 @@ riscv_t *rv_create(riscv_user_t rv_attr) if ((end = elf_get_symbol(elf, "_end"))) attr->break_addr = end->st_value; +#if !RV32_HAS(SYSTEM) + /* set not exiting */ + attr->on_exit = false; + + const struct Elf32_Sym *exit; + if ((exit = elf_get_symbol(elf, "exit"))) + attr->exit_addr = exit->st_value; +#endif + assert(elf_load(elf, attr->mem)); /* set the entry pc */ diff --git a/src/riscv.h b/src/riscv.h index bc343e8a9..88eceef56 100644 --- a/src/riscv.h +++ b/src/riscv.h @@ -548,6 +548,14 @@ typedef struct { /* the data segment break address */ riscv_word_t break_addr; +#if !RV32_HAS(SYSTEM) + /* the exit entry address */ + riscv_word_t exit_addr; + + /* flag to determine if the emulator exits the target program */ + bool on_exit; +#endif + /* SBI timer */ uint64_t timer; } vm_attr_t; diff --git a/src/syscall.c b/src/syscall.c index 09eab5648..e3c4e400a 100644 --- a/src/syscall.c +++ b/src/syscall.c @@ -230,6 +230,22 @@ static void syscall_close(riscv_t *rv) /* _close(fd); */ uint32_t fd = rv_get_reg(rv, rv_reg_a0); +#if !RV32_HAS(SYSTEM) + /* + * The crt0 closes standard file descriptor(0, 1, 2) when + * the process exits. Thus, the operations by the crt0 + * should not considered as error. + */ + if (fd < 3 && !PRIV(rv)->on_exit) { + rv_set_reg(rv, rv_reg_a0, -1); + rv_log_error( + "Attempted to close a file descriptor < 3 (fd=%u). Operation " + "not supported.", + fd); + return; + } +#endif + if (fd >= 3) { /* lookup the file descriptor */ map_iter_t it; map_find(attr->fd_map, &it, &fd);