From dbdafec9069e69005b523bc60acbfcb59224078d Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 3 Jan 2023 11:34:45 -0500 Subject: check for orphaned nodes and node cycles this is a temporary fix, but i can't consistently reproduce the orphaned node bug --- main.c | 28 +++++++++++++--------------- ted.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ ted.h | 9 +++++++-- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/main.c b/main.c index 7ee1bc4..0926d5d 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,6 @@ /* @TODO: - ted.h documentation -- broken session fix: close buffers not in any used node - handle multiple symbols with same name in go-to-definition menu - better non-error window/showMessage(Request) - document lsp.h and lsp.c. @@ -394,14 +393,15 @@ int main(int argc, char **argv) { } - FILE *log = NULL; { // open log file + FILE *log = NULL; char log_filename[TED_PATH_MAX]; strbuf_printf(log_filename, "%s/log.txt", ted->local_data_dir); log = fopen(log_filename, "w"); + setbuf(log, NULL); + ted->log = log; } - ted->log = log; { // get current working directory fs_get_cwd(ted->cwd, sizeof ted->cwd); @@ -1021,16 +1021,13 @@ int main(int argc, char **argv) { ted->error_time = ted->frame_time; str_cpy(ted->error_shown, sizeof ted->error_shown, ted->error); - { // output error to log file - char tstr[256]; - time_t t = time(NULL); - struct tm *tm = localtime(&t); - strftime(tstr, sizeof tstr, "%Y-%m-%d %H:%M:%S", tm); - if (log) { - fprintf(log, "[ERROR %s] %s\n", tstr, ted->error); - fflush(log); - } - } + // output error to log file + char tstr[256]; + time_t t = time(NULL); + struct tm *tm = localtime(&t); + strftime(tstr, sizeof tstr, "%Y-%m-%d %H:%M:%S", tm); + ted_log(ted, "[ERROR %s] %s\n", tstr, ted->error); + ted_clearerr(ted); } @@ -1064,6 +1061,8 @@ int main(int argc, char **argv) { text_render(font); } } + + ted_check_for_node_problems(ted); #if !NDEBUG for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) @@ -1144,7 +1143,7 @@ int main(int argc, char **argv) { free(*cmd); } arr_free(ted->shell_history); - + fclose(ted->log), ted->log = NULL; SDL_FreeCursor(ted->cursor_arrow); SDL_FreeCursor(ted->cursor_ibeam); SDL_FreeCursor(ted->cursor_wait); @@ -1155,7 +1154,6 @@ int main(int argc, char **argv) { SDL_GL_DeleteContext(glctx); SDL_DestroyWindow(window); SDL_Quit(); - if (log) fclose(log); definitions_selector_close(ted); for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) if (ted->buffers_used[i]) diff --git a/ted.c b/ted.c index 840244d..a6c10ca 100644 --- a/ted.c +++ b/ted.c @@ -16,6 +16,23 @@ void die(const char *fmt, ...) { exit(EXIT_FAILURE); } +void ted_seterr(Ted *ted, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vsnprintf(ted->error, sizeof ted->error - 1, fmt, args); + va_end(args); +} + +void ted_log(Ted *ted, const char *fmt, ...) { + if (!ted->log) return; + + va_list args; + va_start(args, fmt); + vfprintf(ted->log, fmt, args); + va_end(args); +} + + void ted_seterr_to_buferr(Ted *ted, TextBuffer *buffer) { size_t size = sizeof ted->error; if (sizeof buffer->error < size) size = sizeof buffer->error; @@ -578,3 +595,32 @@ void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition pos void ted_cancel_lsp_request(Ted *ted, LSPID lsp, LSPRequestID request) { lsp_cancel_request(ted_get_lsp_by_id(ted, lsp), request); } + + +static void mark_node_reachable(Ted *ted, u16 node, bool reachable[TED_MAX_NODES]) { + if (reachable[node]) { + ted_seterr(ted, "NODE CYCLE %u\nThis should never happen.", node); + ted_log(ted, "NODE CYCLE %u\n", node); + node_close(ted, node); + return; + } + reachable[node] = true; + Node *n = &ted->nodes[node]; + if (!n->tabs) { + mark_node_reachable(ted, n->split_a, reachable); + mark_node_reachable(ted, n->split_b, reachable); + } +} + +void ted_check_for_node_problems(Ted *ted) { + bool reachable[TED_MAX_NODES] = {0}; + if (ted->nodes_used[0]) + mark_node_reachable(ted, 0, reachable); + for (u16 i = 0; i < TED_MAX_NODES; ++i) { + if (ted->nodes_used[i] && !reachable[i]) { + ted_seterr(ted, "ORPHANED NODE %u\nThis should never happen.", i); + ted_log(ted, "ORPHANED NODE %u\n", i); + node_close(ted, i); + } + } +} diff --git a/ted.h b/ted.h index 16aa07d..33293ec 100644 --- a/ted.h +++ b/ted.h @@ -589,6 +589,7 @@ typedef struct Ted { char build_dir[TED_PATH_MAX]; // directory where we run the build command char tags_dir[TED_PATH_MAX]; // where we are reading tags from bool nodes_used[TED_MAX_NODES]; + // nodes[0] is always the "root node", if any buffers are open. Node nodes[TED_MAX_NODES]; // NOTE: the buffer at index 0 is reserved as a "null buffer" and should not be used. bool buffers_used[TED_MAX_BUFFERS]; @@ -1031,10 +1032,12 @@ bool tag_goto(Ted *ted, const char *tag); SymbolInfo *tags_get_symbols(Ted *ted); // === ted.c === -#define ted_seterr(ted, ...) \ - snprintf((ted)->error, sizeof (ted)->error - 1, __VA_ARGS__) // for fatal errors void die(PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2); +// for non-fatal errors that should be displayed to the user +void ted_seterr(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); +// for information that should be logged +void ted_log(Ted *ted, PRINTF_FORMAT_STRING const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); void *ted_malloc(Ted *ted, size_t size); void *ted_calloc(Ted *ted, size_t n, size_t size); void *ted_realloc(Ted *ted, void *p, size_t new_size); @@ -1086,6 +1089,8 @@ void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition pos void ted_cancel_lsp_request(Ted *ted, LSPID lsp, LSPRequestID request); // how tall is a line buffer? float ted_line_buffer_height(Ted *ted); +// check for orphaned nodes and node cycles +void ted_check_for_node_problems(Ted *ted); // === ui.c === void selector_up(Ted *ted, Selector *s, i64 n); -- cgit v1.2.3