From 23f7701eb9e9b6363821eba15ba592ec2f536e15 Mon Sep 17 00:00:00 2001 From: arthur barraux Date: Wed, 3 Jun 2026 14:09:01 +0200 Subject: [PATCH] overflow errors --- include/append_buffer.h | 2 +- include/define.h | 4 ++ main.c | 65 +++++++++--------- src/append_buffer.c | 6 +- src/buffer.c | 138 ++++++++++++++++++++++++--------------- src/builtins.c | 50 ++++++++------ src/editor_op.c | 18 +++-- src/file_io.c | 18 ++--- src/init.c | 36 +++++++--- src/input.c | 9 ++- src/split_screen.c | 15 +++-- src/syntax_highlighter.c | 36 +++++----- 12 files changed, 240 insertions(+), 157 deletions(-) diff --git a/include/append_buffer.h b/include/append_buffer.h index 778762e..3f28992 100644 --- a/include/append_buffer.h +++ b/include/append_buffer.h @@ -7,6 +7,6 @@ void abAppend(struct abuf *ab, const char *s, int len); -void abFree(const struct abuf *ab); +void abFree(struct abuf *ab); #endif // APPEND_BUFFER_H_ diff --git a/include/define.h b/include/define.h index a249afb..b6476ce 100644 --- a/include/define.h +++ b/include/define.h @@ -13,6 +13,10 @@ #define TAB "\t" #define SPACE "\x20" +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + /* Uncomment to see debug logs on stderr */ #define APP_DEBUG diff --git a/main.c b/main.c index c45634c..f12d7c1 100644 --- a/main.c +++ b/main.c @@ -28,45 +28,42 @@ struct editorConfig E; int main(int argc, char *argv[]) { - - char * splash_screen = strdup(getenv("HOME")); - int home_path_len = (int) strlen(splash_screen); - char * splash_screen_relative_path = strdup("/.beluga/assets/beluga.txt"); - int splash_screen_relative_path_len = (int) strlen(splash_screen_relative_path); - - signal(SIGPIPE, SIG_IGN); // don't die on broken pipe, just get EPIPE from write() - - enableRawMode(); - initEditor(); - EditorPane *active = splitScreenGetActivePane(); - struct buffer_t *buf; - - splash_screen = realloc(splash_screen, sizeof(char) * (home_path_len + splash_screen_relative_path_len + 1)); - strcat(splash_screen, "/.beluga/assets/beluga.txt"); - free(splash_screen_relative_path); - - appDebug("splash : %s\n", splash_screen); - active->buffer_id = bufferCreate(splash_screen, READ_ONLY); - - if (argc >= 2) { - if (E.constantes.LSP) { - + // Get HOME with NULL check + const char *home = getenv("HOME"); + if (!home) { + fprintf(stderr, "Error: HOME environment variable not set\n"); + return 1; } - active->buffer_id = bufferCreate(argv[1], READ_AND_WRITE); - buf = &E.buffers[active->buffer_id]; + // Allocate and build splash screen path safely + char *splash_screen; + if (asprintf(&splash_screen, "%s/.beluga/assets/beluga.txt", home) == -1) { + fprintf(stderr, "Error: Failed to allocate splash screen path\n"); + return 1; + } - appDebug("peoject root : %s\n", dirname(buf->fullname)); + signal(SIGPIPE, SIG_IGN); + enableRawMode(); + initEditor(); + EditorPane *active = splitScreenGetActivePane(); + struct buffer_t *buf; - } - free(splash_screen); + appDebug("splash : %s\n", splash_screen); + active->buffer_id = bufferCreate(splash_screen, READ_ONLY); - editorSetStatusMessage("HELP: Ctrl-x Ctrl-s = save | Ctrl-x Ctrl-c = quit"); + if (argc >= 2) { + active->buffer_id = bufferCreate(argv[1], READ_AND_WRITE); + buf = &E.buffers[active->buffer_id]; + appDebug("project root : %s\n", dirname(buf->fullname)); + } - while (1) { - editorRefreshScreen(); - editorProcessKeypress(); - } - return 0; + free(splash_screen); // Now guaranteed safe + + editorSetStatusMessage("HELP: Ctrl-x Ctrl-s = save | Ctrl-x Ctrl-c = quit"); + while (1) { + editorRefreshScreen(); + editorProcessKeypress(); + } + return 0; } diff --git a/src/append_buffer.c b/src/append_buffer.c index 4b0d4e5..d9c827b 100644 --- a/src/append_buffer.c +++ b/src/append_buffer.c @@ -11,4 +11,8 @@ void abAppend(struct abuf *ab, const char *s, int len) { ab->len += len; } -void abFree(const struct abuf *ab) { free(ab->b); } +void abFree(struct abuf *ab) { + free(ab->b); + ab->b = NULL; + ab->len = 0; +} diff --git a/src/buffer.c b/src/buffer.c index 25fc73b..889a869 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -63,7 +63,7 @@ struct buffer_t* bufferFindById(int buffer_id) int bufferCreate(const char* path, enum bufferStatus_e state) { appDebug("Creating new buffer"); - char *filename = basename((char *) path); + char* filename = basename((char*)path); // Check if file is already open const int existing_id = bufferFindByFilename(path); if (existing_id != -1) @@ -81,7 +81,16 @@ int bufferCreate(const char* path, enum bufferStatus_e state) struct buffer_t* new_buf = &E.buffers[E.number_of_buffer]; new_buf->buffer_id = E.number_of_buffer; new_buf->filename = strdup(filename); + if (!new_buf->filename) + { + return -1; + } new_buf->fullname = malloc(1024 * sizeof(char)); + if (!new_buf->fullname) + { + free(new_buf->filename); + return -1; + } realpath(path, new_buf->fullname); new_buf->path = dirname(new_buf->fullname); new_buf->type = FILE_BUFF; @@ -98,8 +107,7 @@ int bufferCreate(const char* path, enum bufferStatus_e state) { if (E.lsp_client->state == LSP_SHUTDOWN) lspStart(E.lsp_client, dirname(new_buf->path)); - while (E.lsp_client->state != LSP_READY) - ; + while (E.lsp_client->state != LSP_READY); lspDidOpen(E.lsp_client, new_buf); } @@ -301,7 +309,7 @@ void bufferFind(struct buffer_t* buf) if (query == NULL) return; int i; - for (i = buf->y+1; i < buf->numrows; i++) + for (i = buf->y + 1; i < buf->numrows; i++) { row_t* row = &buf->row[i]; char* match = strstr(row->chars, query); @@ -337,52 +345,71 @@ void bufferFindReverse(struct buffer_t* buf) free(query); } -void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) { - if (at < 0 || at > buffer->numrows) - return; +void bufferInsertRow(struct buffer_t* buffer, int at, char* s, size_t len) +{ + if (at < 0 || at > buffer->numrows) + return; - row_t *tmp = realloc(buffer->row, sizeof(row_t) * (buffer->numrows + 1)); - if (!tmp) - return; - buffer->row = tmp; + row_t* tmp = realloc(buffer->row, sizeof(row_t) * (buffer->numrows + 1)); + if (!tmp) + return; + buffer->row = tmp; - /* Shift existing rows to make room at 'at' — no at++ */ - if (at < buffer->numrows) { - memmove(&buffer->row[at + 1], &buffer->row[at], - sizeof(row_t) * (buffer->numrows - at)); /* not -at+1 */ - } + /* Shift existing rows to make room at 'at' — no at++ */ + if (at < buffer->numrows) + { + memmove(&buffer->row[at + 1], &buffer->row[at], + sizeof(row_t) * (buffer->numrows - at)); /* not -at+1 */ + } - buffer->row[at].size = (int) len; - buffer->row[at].cap = (int) len + 1; - buffer->row[at].chars = malloc(len + 1); - if (!buffer->row[at].chars) - return; - memcpy(buffer->row[at].chars, s, len); - buffer->row[at].chars[len] = '\0'; /* always NUL-terminate */ + buffer->row[at].size = (int)len; + buffer->row[at].cap = (int)len + 1; + buffer->row[at].chars = malloc(len + 1); + if (!buffer->row[at].chars) + return; + memcpy(buffer->row[at].chars, s, len); + buffer->row[at].chars[len] = '\0'; /* always NUL-terminate */ - buffer->numrows++; - buffer->dirty++; + buffer->numrows++; + buffer->dirty++; } -void bufferFreeRow(row_t *row) { free(row->chars); } +void bufferFreeRow(row_t* row) { free(row->chars); } /** * \fn editorRowInsertChar(erow *row, int at, int c) * \param at Index of where we want to insert the char */ -void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at, - const char *src, int n) { - if (buffer->state == READ_ONLY) - return; - if (row->size + n + 1 > row->cap) { - row->cap = (row->size + n + 1) * 2; - row->chars = realloc(row->chars, row->cap); - } - memmove(row->chars + at + n, row->chars + at, row->size - at); - memcpy(row->chars + at, src, n); - row->size += n; - row->chars = realloc(row->chars, row->size + 2); - ++buffer->dirty; +void bufferRowInsertBytes(struct buffer_t* buffer, row_t* row, int at, + const char* src, int n) +{ + if (buffer->state == READ_ONLY) + return; + if (at < 0 || at > row->size) + { + return; + } + if (row->size + n + 1 > row->cap) + { + size_t new_cap = row->cap == 0 ? 128 : row->cap * 2; + while (new_cap < row->size + n + 1) { + new_cap *= 2; + } + char *new_chars = realloc(row->chars, new_cap); + if (!new_chars) { + return; // Allocation failed + } + row->chars = new_chars; + row->cap = (int) new_cap; + } + memmove(row->chars + at + n, row->chars + at, row->size - at); + + // Copy new bytes + memcpy(row->chars + at, src, n); + row->size += n; + + row->chars[row->size] = '\0'; + ++buffer->dirty; } /** @@ -390,16 +417,17 @@ void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at, * \brief Delete the a char at the chosen position on the given row * \param at Index of the char to delete * \param row Row on operation is made */ -void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n) { +void bufferRowDelByte(struct buffer_t* buffer, row_t* row, int at, int n) +{ if (buffer->state == READ_ONLY) return; if (at < 0 || at >= row->size) return; - memmove(row->chars + at, row->chars + at + n, row->size - at - n); - row->size -= n; - row->chars[row->size] = '\0'; - buffer->x -= n; - ++buffer->dirty; + memmove(row->chars + at, row->chars + at + n, row->size - at - n); + row->size -= n; + row->chars[row->size] = '\0'; + buffer->x -= n; + ++buffer->dirty; } @@ -441,7 +469,7 @@ void bufferDelBytes(void) else { /* Merge current row into the previous one */ - row_t* prev = &buf->row[buf->y - 1]; // FIX: was buf->y (same as r) + row_t* prev = &buf->row[buf->y - 1]; // FIX: was buf->y (same as r) int prev_char_count = editorRowCharCount(prev, prev->size); bufferRowInsertBytes(buf, prev, prev->size, r->chars, r->size); @@ -461,18 +489,22 @@ void bufferDelBytes(void) } } -void bufferInsertNewLine(void) { +void bufferInsertNewLine(void) +{ appDebug("Inserting new line\n"); - EditorPane *active = splitScreenGetActivePane(); - struct buffer_t *buf = bufferFindById(active->buffer_id); + EditorPane* active = splitScreenGetActivePane(); + struct buffer_t* buf = bufferFindById(active->buffer_id); appDebug("buf x %d\n", buf->x); - if (buf->y >= buf->numrows) { + if (buf->y >= buf->numrows) + { /* Cursor is past the last row: just append a blank line */ bufferInsertRow(buf, buf->numrows, "", 0); - } else { - row_t *row = &buf->row[buf->y]; + } + else + { + row_t* row = &buf->row[buf->y]; /* Insert the tail (from cursor to end) as a new row below */ bufferInsertRow(buf, buf->y + 1, &row->chars[buf->x], row->size - buf->x); @@ -481,7 +513,7 @@ void bufferInsertNewLine(void) { row = &buf->row[buf->y]; /* Truncate the current row at the cursor */ - row->size = buf->x; + row->size = buf->x; row->chars[row->size] = '\0'; /* Do NOT touch row->cap — the allocation is still valid */ } diff --git a/src/builtins.c b/src/builtins.c index e81bee1..0f5e187 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -137,24 +137,27 @@ void bFree_structs(void) { int i, j; free(E.prefix); - for (i = 0; i < E.number_of_keybinds; ++i) - { + for (i = 0; i < E.number_of_keybinds; ++i) { free(E.key_binds[i].key_sequence); + E.key_binds[i].key_sequence = NULL; } free(E.key_binds); - // bFree layout - free(E.layout.panes); + E.key_binds = NULL; + E.number_of_keybinds = 0; - // bFree buffers - for (i = 0; i < E.number_of_buffer; ++i) - { + // Similar fix for buffers + for (i = 0; i < E.number_of_buffer; ++i) { free(E.buffers[i].filename); - for (j = 0; j < E.buffers[i].numrows; ++j) - { + E.buffers[i].filename = NULL; + for (j = 0; j < E.buffers[i].numrows; ++j) { free(E.buffers[i].row[j].chars); + E.buffers[i].row[j].chars = NULL; } free(E.buffers[i].row); + E.buffers[i].row = NULL; } + // bFree layout + free(E.layout.panes); free(E.init_file_path); fclose(E.fd_init_file); @@ -187,7 +190,7 @@ Lisp editorQuit(Lisp args, LispError* e, LispContext ctx) write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); lspShutdown(E.lsp_client); lisp_shutdown(E.ctx); - deInitEditor(); + // deInitEditor(); disableRawMode(); exit(0); } @@ -414,16 +417,23 @@ Lisp addPackage(Lisp args, LispError* e, LispContext ctx) { const char* package_name = lisp_string(lisp_car(args)); appDebug("%s\n", package_name); - char* package_dir = calloc(256, sizeof(char)); - FILE* fd_package = NULL; - strcat(package_dir, getenv("HOME")); - strcat(package_dir, "/.beluga/packages/"); - strcat(package_dir, package_name); - strcat(package_dir, "/init.lisp"); - appDebug("%s\n", package_dir); - fd_package = fopen(package_dir, "r"); - lisp_eval(lisp_read_file(fd_package, &E.ctx_error, E.ctx), &E.ctx_error, - E.ctx); + const char *home = getenv("HOME"); + if (!home) { + return lisp_null(); + } + + char *package_dir; + if (asprintf(&package_dir, "%s/.beluga/packages/%s/init.lisp", home, package_name) == -1) { + return lisp_null(); + } + + FILE* fd_package = fopen(package_dir, "r"); + if (!fd_package) { + free(package_dir); + return lisp_null(); + } + + lisp_eval(lisp_read_file(fd_package, &E.ctx_error, E.ctx), &E.ctx_error, E.ctx); fclose(fd_package); free(package_dir); diff --git a/src/editor_op.c b/src/editor_op.c index 345a2e5..bf00e01 100644 --- a/src/editor_op.c +++ b/src/editor_op.c @@ -49,13 +49,13 @@ int editorMoveCursor(int key) { if (row && buf->x < row->size) { int len = utf8Seqlen(row->chars[buf->x]); buf->x += len; - } else if (row && buf->y < buf->numrows) { + } else if (row && buf->y < buf->numrows - 1) { buf->y++; buf->x = 0; } break; case ARROW_DOWN: - if (buf->y < buf->numrows) { + if (buf->y < buf->numrows - 1) { buf->y++; } @@ -86,18 +86,28 @@ char *editorGetClipboard(void) { size_t cap = 4096; size_t len = 0; char *buf = malloc(cap); + if (!buf) { + pclose(pipe); + return NULL; + } int c; while ((c = fgetc(pipe)) != EOF) { if (len + 1 >= cap) { cap *= 2; - buf = realloc(buf, cap); + char *new_buf = realloc(buf, cap); + if (!new_buf) { + free(buf); + pclose(pipe); + return NULL; + } + buf = new_buf; } buf[len++] = (char)c; } buf[len] = '\0'; pclose(pipe); - return buf; // caller must free + return buf; } void editorSetClipboard(const char *text, int len) { diff --git a/src/file_io.c b/src/file_io.c index 8b08933..65d2738 100644 --- a/src/file_io.c +++ b/src/file_io.c @@ -60,19 +60,12 @@ void editorCloseFile(void) { */ void editorOpen(struct buffer_t* buffer) { FILE *fp; - char full_name[1024]; - strcpy(full_name, buffer->path); - strcat(full_name, "/"); - strcat(full_name, buffer->filename); - strcat(full_name, "\0"); - appDebug("full name : %s", full_name); - - fp = fopen(full_name, "a+"); + fp = fopen(buffer->fullname, "a+"); if (!fp) die("fopen"); char *line = NULL; - size_t line_cap; + size_t line_cap = 0; ssize_t line_len; rewind(fp); @@ -81,13 +74,12 @@ void editorOpen(struct buffer_t* buffer) { while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r')) { --line_len; - } - appDebug("line %s\n", line); + } bufferInsertRow(buffer, buffer->numrows, line, line_len); free(line); line = NULL; + line_cap = 0; // Reset for next iteration } - free(line); fclose(fp); E.dirty = 0; } @@ -114,7 +106,7 @@ void editorSave() { return; } } - fd = open(buffer->fullname, O_RDWR | O_CREAT, 0644); + fd = open(buffer->fullname, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd != -1) { for (int i = 0; i < buffer->numrows; ++i) { diff --git a/src/init.c b/src/init.c index 6d9ac13..48d6986 100644 --- a/src/init.c +++ b/src/init.c @@ -57,7 +57,7 @@ void initBuiltins() { void initConfig() { E.ctx = lisp_init(); - E.ctx.p->err_port = fopen("log.err", "w"); + E.ctx.p->err_port = fopen("lisp_log.err", "w"); E.env = lisp_env(E.ctx); lisp_lib_load(E.ctx); // Init builtins lisp functions @@ -117,14 +117,26 @@ void initEditor() { active->width = E.screencols; active->height = E.screenrows; - E.init_file_path = (char *)calloc(256, sizeof(char)); - strcat(E.init_file_path, getenv("HOME")); - strcat(E.init_file_path, "/.beluga/config/init.lisp"); - appDebug("%s\n", E.init_file_path); - E.fd_init_file = fopen(E.init_file_path, "r"); + const char *home = getenv("HOME"); + if (!home) { + die("HOME environment variable not set"); + } - // Status bar - E.status_msg = (char *)calloc(E.screencols, sizeof(char)); + if (asprintf(&E.init_file_path, "%s/.beluga/config/init.lisp", home) == -1) { + die("asprintf failed"); + } + + E.fd_init_file = fopen(E.init_file_path, "r"); + if (!E.fd_init_file) { + // File might not exist, that's okay for some cases + // Handle accordingly + } + + E.status_msg = calloc(E.screencols, sizeof(char)); + if (!E.status_msg) { + die("malloc failed"); + } + E.status_msg[0] = '\0'; E.status_msg[0] = '\0'; E.status_msg_time = 0; @@ -168,5 +180,13 @@ void deInitEditor() { free(E.key_binds[i].key_sequence); } + for (int i = 0; i < E.number_of_buffer; ++i) + { + free(E.buffers[i].filename); + free(E.buffers[i].path); + free(E.buffers[i].fullname); + free(E.buffers[i].row->chars); + free(E.buffers[i].row); + } } diff --git a/src/input.c b/src/input.c index 11cf34d..6db58e8 100644 --- a/src/input.c +++ b/src/input.c @@ -158,10 +158,13 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) { } else if (!iscntrl(c) && c < 256) { if (buf_len == buf_size - 1) { buf_size *= 2; - buf = realloc(buf, buf_size); + char *new_buf = realloc(buf, buf_size); + if (!new_buf) { + free(buf); + return NULL; + } + buf = new_buf; } - buf[buf_len++] = (char)c; - buf[buf_len] = '\0'; } } } diff --git a/src/split_screen.c b/src/split_screen.c index 51228a6..b2514e4 100644 --- a/src/split_screen.c +++ b/src/split_screen.c @@ -20,7 +20,12 @@ void splitScreenInit(void) { E.layout.num_panes = 1; E.layout.active_pane = 0; - E.layout.panes = malloc(sizeof(EditorPane) * 2); + EditorPane *new_panes = realloc(E.layout.panes, sizeof(EditorPane) * 2); + if (!new_panes) { + editorSetStatusMessage("Error: realloc failed"); + return; + } + E.layout.panes = new_panes; // Initialize single fullscreen pane E.layout.panes[0].buffer_id = -1; // No buffer for now @@ -218,9 +223,11 @@ EditorPane *splitScreenGetActivePane(void) { return &E.layout.panes[E.layout.active_pane]; } -void freeScreenLayout(ScreenLayout *layout) -{ - free(layout->panes); +void freeScreenLayout(ScreenLayout *layout) { + if (layout) { + free(layout->panes); + layout->panes = NULL; + } } void freePane(EditorPane *pane) diff --git a/src/syntax_highlighter.c b/src/syntax_highlighter.c index c751094..600ba07 100644 --- a/src/syntax_highlighter.c +++ b/src/syntax_highlighter.c @@ -110,9 +110,13 @@ int comment_section = 0; char *highlight_line(const char *line, int *length) { // Each byte can expand to at most (color_prefix + 4 bytes + color_reset). // Allocate generously based on line length to avoid overflow. - int line_len = strlen(line); + int line_len = (int) strlen(line); int buf_size = line_len * 32 + 256; char *result = malloc(buf_size); + if (!result) { + *length = 0; + return NULL; + } int result_pos = 0; int i = 0; @@ -125,31 +129,31 @@ char *highlight_line(const char *line, int *length) { } if (comment_section) { - result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); + result_pos += snprintf(&result[result_pos], 10, "%s", E.theme.COLOR_COMMENT); while (line[i] != '\0' && line[i] != '\n') { if (line[i] == '*' && line[i + 1] == '/') { comment_section = 0; } copy_utf8_char(result, &result_pos, line, &i); } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); continue; } // Handle line comments if (line[i] == '/' && line[i + 1] == '/') { - result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); + result_pos += snprintf(&result[result_pos], 10, "%s", E.theme.COLOR_COMMENT); while (line[i] != '\0' && line[i] != '\n') { copy_utf8_char(result, &result_pos, line, &i); } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); continue; } // Handle block comments if (line[i] == '/' && line[i + 1] == '*') { comment_section = 1; - result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); + result_pos += snprintf(&result[result_pos], 10, "%s", E.theme.COLOR_COMMENT); result[result_pos++] = line[i++]; result[result_pos++] = line[i++]; while (line[i] != '\0') { @@ -161,13 +165,13 @@ char *highlight_line(const char *line, int *length) { } copy_utf8_char(result, &result_pos, line, &i); } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); continue; } // Handle strings if (line[i] == '"') { - result_pos += sprintf(&result[result_pos], "%s\"", E.theme.COLOR_STRING); + result_pos += snprintf(&result[result_pos], 10, "%s\"", E.theme.COLOR_STRING); i++; while (line[i] != '\0' && line[i] != '"') { if (line[i] == '\\') { @@ -179,13 +183,13 @@ char *highlight_line(const char *line, int *length) { } if (line[i] == '"') result[result_pos++] = line[i++]; - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); continue; } // Handle character literals if (line[i] == '\'') { - result_pos += sprintf(&result[result_pos], "%s'", E.theme.COLOR_STRING); + result_pos += snprintf(&result[result_pos], 10, "%s'", E.theme.COLOR_STRING); i++; while (line[i] != '\0' && line[i] != '\'') { if (line[i] == '\\') { @@ -197,17 +201,17 @@ char *highlight_line(const char *line, int *length) { } if (line[i] == '\'') result[result_pos++] = line[i++]; - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); continue; } // Handle numbers if (line[i] >= '0' && line[i] <= '9') { - result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_NUMBER); + result_pos += snprintf(&result[result_pos], 10, "%s", E.theme.COLOR_NUMBER); while (is_word_char(&line[i]) || line[i] == '.') { copy_utf8_char(result, &result_pos, line, &i); } - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); continue; } @@ -231,15 +235,15 @@ char *highlight_line(const char *line, int *length) { else if (is_type(word)) type = TOKEN_TYPE; - result_pos += sprintf(&result[result_pos], "%s%s%s", get_color(type), + result_pos += snprintf(&result[result_pos], 100, "%s%s%s", get_color(type), word, COLOR_RESET); continue; } // Handle operators and other characters (including non-ASCII multi-byte) - result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_DEFAULT); + result_pos += snprintf(&result[result_pos], 10, "%s", E.theme.COLOR_DEFAULT); copy_utf8_char(result, &result_pos, line, &i); - result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); + result_pos += snprintf(&result[result_pos], 10, "%s", COLOR_RESET); } result[result_pos] = '\0';