overflow errors

This commit is contained in:
2026-06-03 14:09:01 +02:00
parent 564292b03e
commit 23f7701eb9
12 changed files with 240 additions and 157 deletions
+1 -1
View File
@@ -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_
+4
View File
@@ -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
+17 -20
View File
@@ -28,42 +28,39 @@
struct editorConfig E;
int main(int argc, char *argv[]) {
// Get HOME with NULL check
const char *home = getenv("HOME");
if (!home) {
fprintf(stderr, "Error: HOME environment variable not set\n");
return 1;
}
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()
// 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;
}
signal(SIGPIPE, SIG_IGN);
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) {
}
active->buffer_id = bufferCreate(argv[1], READ_AND_WRITE);
buf = &E.buffers[active->buffer_id];
appDebug("peoject root : %s\n", dirname(buf->fullname));
appDebug("project root : %s\n", dirname(buf->fullname));
}
free(splash_screen);
free(splash_screen); // Now guaranteed safe
editorSetStatusMessage("HELP: Ctrl-x Ctrl-s = save | Ctrl-x Ctrl-c = quit");
while (1) {
editorRefreshScreen();
editorProcessKeypress();
+5 -1
View File
@@ -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;
}
+45 -13
View File
@@ -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);
}
@@ -337,7 +345,8 @@ void bufferFindReverse(struct buffer_t* buf)
free(query);
}
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) {
void bufferInsertRow(struct buffer_t* buffer, int at, char* s, size_t len)
{
if (at < 0 || at > buffer->numrows)
return;
@@ -347,7 +356,8 @@ void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) {
buffer->row = tmp;
/* Shift existing rows to make room at 'at' — no at++ */
if (at < buffer->numrows) {
if (at < buffer->numrows)
{
memmove(&buffer->row[at + 1], &buffer->row[at],
sizeof(row_t) * (buffer->numrows - at)); /* not -at+1 */
}
@@ -371,17 +381,34 @@ void bufferFreeRow(row_t *row) { free(row->chars); }
* \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) {
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);
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 = realloc(row->chars, row->size + 2);
row->chars[row->size] = '\0';
++buffer->dirty;
}
@@ -390,7 +417,8 @@ 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)
@@ -461,17 +489,21 @@ 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);
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 {
}
else
{
row_t* row = &buf->row[buf->y];
/* Insert the tail (from cursor to end) as a new row below */
+30 -20
View File
@@ -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);
+14 -4
View File
@@ -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) {
+4 -12
View File
@@ -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);
@@ -82,12 +75,11 @@ void editorOpen(struct buffer_t* buffer) {
(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)
{
+28 -8
View File
@@ -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);
}
}
+6 -3
View File
@@ -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';
}
}
}
+10 -3
View File
@@ -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)
{
void freeScreenLayout(ScreenLayout *layout) {
if (layout) {
free(layout->panes);
layout->panes = NULL;
}
}
void freePane(EditorPane *pane)
+20 -16
View File
@@ -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';