poe

Уређивач .po фајлова
git clone https://git.sr.ht/~strahinja/poe
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување e17256bbcc3d4c07ec7764e587dea094df966afa
родитељ 9c6c2f06f2437b67a77d25646adb7bb50b3e109c
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Wed,  6 Mar 2024 21:54:46 +0100

Switch to strlcpy, strlcat

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MTODO | 3---
MTODO.done | 3+++
Mconfig.mk | 4++--
Mdraw.c | 20++++++++++++++++----
Mpo.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mpoe.c | 176++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Astrlcat.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astrlcpy.c | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.c | 77+++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mutil.h | 16+++++++++++++---
измењених датотека: 10, додавања: 448(+), брисања: 122(-)

diff --git a/TODO b/TODO @@ -1,9 +1,6 @@ TODO ==== -[ ] Switch to strlcpy, strlcat similar to sled; compare util.c and util.h to - versions of those files from sled - [ ] Add pledge(2) and unveil(2) [ ] Support Yudit's nonstandard PO format (no empty lines between individual diff --git a/TODO.done b/TODO.done @@ -1,6 +1,9 @@ Done todos ========== +[x] Switch to strlcpy, strlcat similar to sled; compare util.c and util.h to + versions of those files from sled + [/] Replace strn* -> strc*: like str[^n]*, but with configurable string ending character (for msgstr, which has multiple lines delimited with '\n') diff --git a/config.mk b/config.mk @@ -6,9 +6,9 @@ CFLAGS = -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \ # -D_XOPEN_SOURCE=700 -D_BSD_SOURCE INSTALL = install LIBS = -SRC = draw.c po.c poe.c util.c #strlcat.c strlcpy.c +SRC = draw.c po.c poe.c strlcat.c strlcpy.c util.c HEADERS = config.h draw.h po.h termbox.h util.h version.h -OBJS = draw.o po.o poe.o util.o #strlcat.o strlcpy.o +OBJS = draw.o po.o poe.o strlcat.o strlcpy.o util.o PREFIX = /usr/local PROG = poe diff --git a/draw.c b/draw.c @@ -60,6 +60,8 @@ const char* prompt_cancel_dirty = "Entry changed, save [y/n/ESC]?"; const char* prompt_overwrite = "Not empty, overwrite? [y/n/ESC]?"; /* clang-format on */ +int print_error(const int code, const char* msg, ...); + void init_bufferline(struct BufferLine* bl) { @@ -612,9 +614,18 @@ draw_editbox(const struct DrawState* state) struct PoEntry* entry = state->entries + state->msgid_number - 1; size_t dlen = 0; - strcpy(flags_buf, "[ "); + if (strlcpy(flags_buf, "[ ", MAXFLAGSBUF + 4) >= MAXFLAGSBUF + 4) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } format_flags(flags_buf + 2, MAXFLAGSBUF, entry); - strcpy(flags_buf + 2 + MAXFLAGSBUF - 1, " ]"); + if (strlcpy(flags_buf + 2 + MAXFLAGSBUF - 1, " ]", MAXFLAGSBUF + 4 - 2) + >= MAXFLAGSBUF + 4 - 2) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } startx = w > maxx ? 0 : (maxx - w) / 2; endx = w > maxx ? maxx - 1 : startx + w; @@ -689,13 +700,14 @@ draw_editbox(const struct DrawState* state) char sbuf[MAXBUFLINE]; if (entry->msgstr_count > 1) - sprintf(sbuf, "%d[%d]:%d[%d]/%d (plural: %d/%d)", + snprintf(sbuf, MAXBUFLINE, "%d[%d]:%d[%d]/%d (plural: %d/%d)", state->input_display_column, state->input_first_shown_column, state->input_row, state->input_first_shown_row, state->input_rows_count, state->msgstr_index + 1, entry->msgstr_count); else - sprintf(sbuf, "%d[%d]:%d[%d]/%d", state->input_display_column, + snprintf(sbuf, MAXBUFLINE, "%d[%d]:%d[%d]/%d", + state->input_display_column, state->input_first_shown_column, state->input_row, state->input_first_shown_row, state->input_rows_count); draw_string(startx + 1, endy - 2, DLG_FG, DLG_BG, sbuf, diff --git a/po.c b/po.c @@ -20,6 +20,8 @@ extern const char* errors[]; extern const char* flag_strings[]; +int print_error(const int code, const char* msg, ...); + char* format_flags(char* buffer, const size_t max, const struct PoEntry* entry) { @@ -415,8 +417,8 @@ load_file(struct DrawState* dstate, long* lineno, long* col) FILE* input = NULL; char input_line[MAXBUFLINE]; /* lines to tolerate the lack of msgid */ - int msgid_counter = PO_DETECTION_LINES; - int msgstr_index = -1; + int msgid_counter = PO_DETECTION_LINES; + int msgstr_index = -1; size_t non_obsolete_sofar = 0; dstate->msgid_size = 0; @@ -460,8 +462,9 @@ load_file(struct DrawState* dstate, long* lineno, long* col) return LOAD_ERR_NOT_PO_FILE; } else if (result == PARSE_ERR_SYNTAX) - sprintf(dstate->error, "%s:%ld:%ld: Syntax error", - dstate->filename, *lineno, *col); + snprintf(dstate->error, MAXBUFLINE, + "%s:%ld:%ld: Syntax error", dstate->filename, + *lineno, *col); else { free(dstate->entries); @@ -483,7 +486,13 @@ load_file(struct DrawState* dstate, long* lineno, long* col) entry->obsolete = 1; #ifndef PLURAL_STRING if (has_plural_msgid && !dstate->entries->plural_forms) - strcpy(dstate->error, errors[ERR_NO_PLURAL_FORMS]); + if (strlcpy(dstate->error, errors[ERR_NO_PLURAL_FORMS], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } #endif } @@ -497,7 +506,7 @@ load_file(struct DrawState* dstate, long* lineno, long* col) current = dstate->entries; dstate->obsolete_at_end_count = 0; - non_obsolete_sofar = 0; + non_obsolete_sofar = 0; while (current != dstate->entries + dstate->real_msgid_count) { if (!current->obsolete) @@ -546,8 +555,16 @@ save_file(const struct PoEntry* entries, const size_t real_msgid_count, if (stat(real_filename, &st) == -1) return SAVE_ERR_CANT_STAT_FILE; } - strcpy(backup_filename, filename); - strcat(backup_filename, backup_suffix); + if (strlcpy(backup_filename, filename, MAXPATH) >= MAXPATH) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } + if (strlcat(backup_filename, backup_suffix, MAXPATH) >= MAXPATH) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } if (rename(rfn_len > 0 ? real_filename : filename, backup_filename) == -1) @@ -583,16 +600,19 @@ save_comments: char* u8_comment = NULL; for (size_t c = 0; c < current->comment_lines; c++) { - size_t len = u32_strlen(*(current->comments + c)) + 1; + size_t len = u32_strlen(*(current->comments + c)); + size_t size = len * UTF8REPMAX + 1; if (!u8_comment) - u8_comment = calloc(len * UTF8REPMAX, 1); + { + u8_comment = malloc(size); + memset(u8_comment, 0, size); + } else - u8_comment - = realloc(u8_comment, len * UTF8REPMAX); + u8_comment = realloc(u8_comment, size); if (!u8_comment) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_comment, - *(current->comments + c), len * UTF8REPMAX); + unicode_string_to_u8(u8_comment, size, + *(current->comments + c), len); fprintf(output, "#%s%s\n", current->obsolete ? "~" : "", u8_comment); } @@ -603,18 +623,22 @@ save_comments: char* u8_trans_comment = NULL; for (size_t tc = 0; tc < current->trans_comment_lines; tc++) { - size_t len = u32_strlen(*(current->trans_comments + tc)) - + 1; + size_t len + = u32_strlen(*(current->trans_comments + tc)); + size_t size = len * UTF8REPMAX + 1; + if (!u8_trans_comment) - u8_trans_comment = calloc(len * UTF8REPMAX, 1); + { + u8_trans_comment = malloc(size); + memset(u8_trans_comment, 0, size); + } else - u8_trans_comment = realloc(u8_trans_comment, - len * UTF8REPMAX); + u8_trans_comment + = realloc(u8_trans_comment, size); if (!u8_trans_comment) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_trans_comment, - *(current->trans_comments + tc), - len * UTF8REPMAX); + unicode_string_to_u8(u8_trans_comment, size, + *(current->trans_comments + tc), len); fprintf(output, "#.%s%s\n", u8_trans_comment[0] == 0 ? "" : " ", u8_trans_comment); @@ -673,9 +697,8 @@ save_obsolete_check: if (current->msgid) { - size_t msgid_size = current->msgid_size * UTF8REPMAX; - size_t num_lines = u32_lines_in_string(current->msgid, 1, - SAVE_WRAP_WIDTH); + size_t num_lines = u32_lines_in_string(current->msgid, 1, + SAVE_WRAP_WIDTH); if ((num_lines > 1) && (u32_strlen(current->msgid) @@ -687,7 +710,8 @@ save_obsolete_check: while (*pumsgid) { - size_t len = 0; + size_t len = 0; + size_t size; char* u8_msgid = NULL; const uint32_t* old_pumsgid = pumsgid; @@ -696,23 +720,34 @@ save_obsolete_check: if (len == 0) continue; - u8_msgid = calloc(len + 1, UTF8REPMAX); + size = len * UTF8REPMAX + 1; + + u8_msgid = malloc(size); if (!u8_msgid) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_msgid, old_pumsgid, len); + memset(u8_msgid, 0, size); + + unicode_string_to_u8(u8_msgid, size, + old_pumsgid, len); fprintf(output, "\"%s\"\n", u8_msgid); free(u8_msgid); } } else { - char* u8_msgid - = calloc(current->msgid_size, UTF8REPMAX); + size_t size; + char* u8_msgid = NULL; + + size = current->msgid_size * UTF8REPMAX + 1; + u8_msgid = malloc(size); if (!u8_msgid) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_msgid, current->msgid, - msgid_size); + + memset(u8_msgid, 0, size); + + unicode_string_to_u8(u8_msgid, size, current->msgid, + current->msgid_size); fprintf(output, "msgid \"%s\"\n", u8_msgid); free(u8_msgid); } @@ -722,8 +757,6 @@ save_obsolete_check: if (current->msgid_plural) { - size_t msgid_plural_size - = current->msgid_plural_size * UTF8REPMAX; size_t num_lines = u32_lines_in_string(current->msgid_plural, 1, SAVE_WRAP_WIDTH); @@ -740,29 +773,42 @@ save_obsolete_check: size_t len = 0; char* u8_msgid = NULL; const uint32_t* old_pumsgid = pumsgid; + size_t size; len = u32_next_line(current->msgid_plural, &pumsgid, 1, SAVE_WRAP_WIDTH); if (len == 0) continue; - u8_msgid = calloc(len + 1, UTF8REPMAX); + size = len * UTF8REPMAX + 1; + u8_msgid = malloc(size); if (!u8_msgid) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_msgid, old_pumsgid, len); + memset(u8_msgid, 0, size); + + unicode_string_to_u8(u8_msgid, size, + old_pumsgid, len); fprintf(output, "\"%s\"\n", u8_msgid); free(u8_msgid); } } else { - char* u8_msgid = calloc(current->msgid_plural_size, - UTF8REPMAX); + char* u8_msgid = NULL; + size_t size; + size_t msgid_plural_len; + + size = current->msgid_plural_size * UTF8REPMAX + 1; + u8_msgid = malloc(size); if (!u8_msgid) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_msgid, current->msgid_plural, - msgid_plural_size); + + memset(u8_msgid, 9, size); + + msgid_plural_len = u32_strlen(current->msgid_plural); + unicode_string_to_u8(u8_msgid, size, + current->msgid_plural, msgid_plural_len); fprintf(output, "msgid_plural \"%s\"\n", u8_msgid); free(u8_msgid); } @@ -793,7 +839,8 @@ save_obsolete_check: while (*pumsgstr) { - size_t len = 0; + size_t len = 0; + size_t size; char* u8_msgstr = NULL; const uint32_t* old_pumsgstr = pumsgstr; @@ -807,12 +854,15 @@ save_obsolete_check: if (len == 0) continue; - u8_msgstr = calloc(len + 1, UTF8REPMAX); + size = len * UTF8REPMAX + 1; + u8_msgstr = malloc(size); if (!u8_msgstr) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_msgstr, old_pumsgstr, - len); + memset(u8_msgstr, 0, size); + + unicode_string_to_u8(u8_msgstr, size, + old_pumsgstr, len); if (first_entry && starts_with(u8_msgstr, "PO-Revision-Date: ")) @@ -858,9 +908,13 @@ save_obsolete_check: fprintf(output, "msgstr[%d] \"\"\n", i); else { - char u8_msgstr[MAXMSGLINE * UTF8REPMAX]; - unicode_string_to_u8(u8_msgstr, *current->msgstr, - MAXMSGLINE * UTF8REPMAX); + size_t size = MAXMSGLINE * UTF8REPMAX + 1; + char u8_msgstr[size]; + size_t msgstr_len; + + msgstr_len = u32_strlen(*current->msgstr); + unicode_string_to_u8(u8_msgstr, size, *current->msgstr, + msgstr_len); fprintf(output, "msgstr \"%s\"\n", u8_msgstr); } } @@ -882,7 +936,8 @@ save_obsolete_check: while (*pumsgstr) { - size_t len = 0; + size_t len = 0; + size_t size; char* u8_msgstr = NULL; const uint32_t* old_pumsgstr = pumsgstr; @@ -892,11 +947,14 @@ save_obsolete_check: if (len == 0) continue; - u8_msgstr = calloc(len + 1, UTF8REPMAX); + size = len * UTF8REPMAX + 1; + u8_msgstr = malloc(size); if (!u8_msgstr) return SAVE_ERR_CANT_ALLOC; - unicode_string_to_u8(u8_msgstr, + memset(u8_msgstr, 0, size); + + unicode_string_to_u8(u8_msgstr, size, old_pumsgstr, len); fprintf(output, "\"%s\"\n", u8_msgstr); free(u8_msgstr); @@ -904,10 +962,12 @@ save_obsolete_check: } else { - char u8_msgstr[MAXMSGLINE * UTF8REPMAX]; - unicode_string_to_u8(u8_msgstr, - *(current->msgstr + m), - MAXMSGLINE * UTF8REPMAX); + size_t size = MAXMSGLINE * UTF8REPMAX + 1; + char u8_msgstr[size]; + size_t msgstr_len; + msgstr_len = u32_strlen(*(current->msgstr + m)); + unicode_string_to_u8(u8_msgstr, size, + *(current->msgstr + m), msgstr_len); fprintf(output, "msgstr[%ld] \"%s\"\n", m, u8_msgstr); } diff --git a/poe.c b/poe.c @@ -120,7 +120,12 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) if (state->show_help) { - strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); + if (strlcpy(state->error, errors[ERR_DLG_OPEN_QUIT], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return; } else if (state->show_edit) @@ -178,11 +183,33 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) } if (state->edit_info_focused) - strcpy(state->error, errors[ERR_DLG_FOCUS_EDIT]); + { + if (strlcpy(state->error, errors[ERR_DLG_FOCUS_EDIT], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } + } else if (state->show_edit || state->show_search) - strcpy(state->error, errors[ERR_UNKNOWN_KEY]); + { + if (strlcpy(state->error, errors[ERR_UNKNOWN_KEY], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } + } else - strcpy(state->error, errors[ERR_UNKNOWN_KEY_HELP]); + { + if (strlcpy(state->error, errors[ERR_UNKNOWN_KEY_HELP], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } + } } int @@ -661,8 +688,12 @@ cancel_close(struct DrawState* state) cancel_msgstr(state); else if (state->show_search) cancel_search(state); - else - strcpy(state->error, errors[ERR_EXIT_KEY]); + else if (strlcpy(state->error, errors[ERR_EXIT_KEY], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } @@ -673,7 +704,12 @@ cancel_msgstr(struct DrawState* state) if (!state->in_prompt && state->dirty) { state->in_prompt = 1; - strcpy(state->prompt, prompt_cancel_dirty); + if (strlcpy(state->prompt, prompt_cancel_dirty, MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->prompt_callback = cancel_callback; return 0; } @@ -727,14 +763,25 @@ copy_msgid_to_input(struct DrawState* state) if (!state->in_prompt && *state->input_buffer->text) { state->in_prompt = 1; - strcpy(state->prompt, prompt_overwrite); + if (strlcpy(state->prompt, prompt_overwrite, MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->prompt_callback = overwrite_copy_msgid_callback; return 0; } if (state->msgid_number == 1) { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } @@ -896,7 +943,13 @@ erase_forward(struct DrawState* state) { if (!join_lines(state, state->input_row, 1)) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; } } @@ -1096,13 +1149,23 @@ exit_program(struct DrawState* state) { if (state->show_edit) { - strcpy(state->error, errors[ERR_DLG_OPEN]); + if (strlcpy(state->error, errors[ERR_DLG_OPEN], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } if (state->dirty) { state->in_prompt = 1; - strcpy(state->prompt, prompt_dirty); + if (strlcpy(state->prompt, prompt_dirty, MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->prompt_callback = quit_callback; } else @@ -1132,7 +1195,12 @@ insert_line(struct DrawState* state) state->input_rows_count * sizeof(struct BufferLine)); if (!newbuf) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; return 0; } @@ -1142,7 +1210,12 @@ insert_line(struct DrawState* state) uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); if (!newtext) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; return 0; } @@ -1723,14 +1796,25 @@ paste_paste_buffer_to_input(struct DrawState* state) if (!state->in_prompt && *state->input_buffer->text) { state->in_prompt = 1; - strcpy(state->prompt, prompt_overwrite); + if (strlcpy(state->prompt, prompt_overwrite, MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->prompt_callback = overwrite_paste_callback; return 0; } if (state->msgid_number == 1) { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } @@ -1855,7 +1939,13 @@ save_msgstr(struct DrawState* state) to_save = calloc(to_save_size, sizeof(uint32_t)); if (!to_save) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } struct BufferLine* pinput_buffer = NULL; @@ -1902,7 +1992,12 @@ show_edit(struct DrawState* state) { if (!load_msgstr(state) || !load_info(state)) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; return 0; } @@ -1950,7 +2045,13 @@ toggle_fuzzy(struct DrawState* state) { if (state->msgid_number == 1) { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } if (state->msgid_count > 0) @@ -1992,7 +2093,13 @@ yank_input_to_paste_buffer(struct DrawState* state) if (state->msgid_number == 1) { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } return 0; } @@ -2068,15 +2175,30 @@ write_file(struct DrawState* state) switch (result) { case SAVE_ERR_CANT_ALLOC: - strcpy(state->error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case SAVE_ERR_CANT_OPEN_FILE: - strcpy(state->error, errors[ERR_CANT_SAVE]); + if (strlcpy(state->error, errors[ERR_CANT_SAVE], MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; case SAVE_ERR_CANT_MOVE_FILE: - strcpy(state->error, strerror(errno)); + if (strlcpy(state->error, strerror(errno), MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } state->running = 0; break; default: @@ -2205,7 +2327,13 @@ main(int argc, char** argv) state.maxy = tb_height(); if (!draw(&state)) - strcpy(state.error, errors[ERR_CANT_ALLOC]); + if (strlcpy(state.error, errors[ERR_CANT_ALLOC], + MAXBUFLINE) + >= MAXBUFLINE) + { + print_error(1, "strlcpy:%d: Overflow", __LINE__); + exit(1); + } tb_present(); result = tb_poll_event(&ev); if (result == TB_OK && ev.type == TB_EVENT_RESIZE) diff --git a/strlcat.c b/strlcat.c @@ -0,0 +1,54 @@ +/* $OpenBSD: strlcat.c,v 1.9 2019/01/25 00:19:26 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/strlcpy.c b/strlcpy.c @@ -0,0 +1,49 @@ +/* $OpenBSD: strlcpy.c,v 1.9 2019/01/25 00:19:26 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <string.h> + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/util.c b/util.c @@ -12,6 +12,12 @@ #include "po.h" #include "util.h" +enum { UTLERRNONE = 0, UTLERROVFL = 1 }; + +int utlerrno = UTLERRNONE; + +/* max - max Unicode characters to convert from UTF-8 + * Returns: number of processed Unicode characters */ size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max) { @@ -36,12 +42,16 @@ u8_string_to_unicode(uint32_t* us, const char* s, const size_t max) return added; } +/* max - max Unicode characters to convert to UTF-8 + * Returns: number of processed Unicode characters */ size_t -unicode_string_to_u8(char* s, const uint32_t* us, const size_t max) +unicode_string_to_u8(char* s, const size_t s_size, const uint32_t* us, + const size_t max) { char ch[8]; const uint32_t* pus = us; - size_t added = 0; + size_t len; + size_t added = 0; if (!pus) return added; @@ -49,13 +59,22 @@ unicode_string_to_u8(char* s, const uint32_t* us, const size_t max) *s = 0; while (*pus) { - int len = tb_utf8_unicode_to_char(ch, *pus); - if (added + 1 > max) - break; - strncat(s, ch, len); + size_t res; + + len = tb_utf8_unicode_to_char(ch, *pus); + ch[len] = 0; + res = strlcat(s, ch, s_size); + if (res >= s_size) + { + utlerrno = UTLERROVFL; + return added; + } added++; pus++; + if (added + 1 > max) + break; } + utlerrno = UTLERRNONE; return added; } @@ -68,7 +87,7 @@ u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max) size_t buf_len = 0; size_t msgid_len = 0; - buf_len = u32_strcpy(buf, msgstr); + buf_len = u32_strncpy(buf, msgstr, (max + 1) * sizeof(uint32_t)); msgid_len = u32_strlen(msgid); if (msgid_len > 1 @@ -251,25 +270,13 @@ u32_strchr(const uint32_t* haystack, const uint32_t needle) } size_t -u32_strcpy(uint32_t* to, const uint32_t* from) -{ - const uint32_t* pfrom = from; - size_t copied = 0; - while (*pfrom) - { - *to++ = *pfrom++; - copied++; - } - *to = 0; - return copied; -} - -size_t u32_strncpy(uint32_t* to, const uint32_t* from, size_t max) { const uint32_t* pfrom = from; size_t copied = 0; - while (*pfrom && copied < max - 1) + /* pfrom - from < max - 1 ... except we can't reliably subtract with + * size_t */ + while (*pfrom && pfrom + 1 < max + from) { *to++ = *pfrom++; copied++; @@ -287,12 +294,12 @@ u32_strncat(uint32_t* to, const uint32_t* from, size_t max) { const uint32_t* pfrom = from; size_t copied = 0; - while (*to) + while (*to && copied + 1 < max) { to++; copied++; } - while (*pfrom && copied < max - 1) + while (*pfrom && copied + 1 < max) { *to++ = *pfrom++; copied++; @@ -304,11 +311,12 @@ u32_strncat(uint32_t* to, const uint32_t* from, size_t max) size_t u32_u8_strncpy(uint32_t* to, const char* from, size_t max) { - uint32_t* ufrom = calloc(strlen(from) + 1, sizeof(uint32_t)); + uint32_t* ufrom = calloc(max + 1, sizeof(uint32_t)); + size_t len; if (!ufrom) return 0; u8_string_to_unicode(ufrom, from, max); - size_t len = u32_strncpy(to, ufrom, max); + len = u32_strncpy(to, ufrom, max); free(ufrom); return len; } @@ -316,14 +324,17 @@ u32_u8_strncpy(uint32_t* to, const char* from, size_t max) size_t u8_u32_strncpy(char* to, const uint32_t* from, size_t max) { - char* cfrom = calloc(u32_strlen(from) * UTF8REPMAX + 1, 1); + char* cfrom = calloc(max + 1, 1); + size_t len; if (!cfrom) return 0; - unicode_string_to_u8(cfrom, from, max); + unicode_string_to_u8(cfrom, max + 1, from, max); + len = strlen(cfrom); strncpy(to, cfrom, max); - to[max - 1] = 0; + if (len && len < max) + to[len] = 0; free(cfrom); - return strlen(to); + return len; } /* wrap - if >0, also wrap lines @@ -455,9 +466,10 @@ u32_starts_with(const uint32_t* s, const uint32_t* with) const char* u8_basename(const char* path) { + const char* ppath; if (!path) return NULL; - const char* ppath = path + strlen(path); + ppath = path + strlen(path); while (ppath != path && *ppath != '/') ppath--; if (*ppath == '/') @@ -465,6 +477,7 @@ u8_basename(const char* path) return ppath; } +/* void poe_log(const char* msg, ...) { @@ -474,4 +487,4 @@ poe_log(const char* msg, ...) vfprintf(log, msg, args); va_end(args); fclose(log); -} +}*/ diff --git a/util.h b/util.h @@ -25,6 +25,7 @@ enum { }; #define MAXBUFLINE 4096 +#define MAXCOPYBUF 8192 #define MAXDATEBUF 80 #define MAXFLAGSBUF (4 + 1) #define MAXMSGLINE 1024 @@ -33,8 +34,18 @@ enum { /* maximum chars for UTF-8 representations of Unicode chars, per Unicode char */ #define UTF8REPMAX 6 +extern int utlerrno; + +#ifndef strlcpy +size_t strlcpy(char* dst, const char* src, size_t dsize); +#endif +#ifndef strlcat +size_t strlcat(char* dst, const char* src, size_t dsize); +#endif + size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max); -size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max); +size_t unicode_string_to_u8(char* s, const size_t s_size, const uint32_t* us, + const size_t max); size_t u32_match_msgid_ending(const uint32_t* msgid, uint32_t* msgstr, size_t max); size_t u32_count_chars(const uint32_t* s, const uint32_t ch); @@ -44,7 +55,6 @@ size_t u32_decode_tabs(uint32_t* s, size_t max); size_t u32_strlen(const uint32_t* s); const uint32_t* u32_strstr(const uint32_t* haystack, const uint32_t* needle); const uint32_t* u32_strchr(const uint32_t* haystack, const uint32_t needle); -size_t u32_strcpy(uint32_t* to, const uint32_t* from); size_t u32_strncpy(uint32_t* to, const uint32_t* from, size_t max); size_t u32_strncat(uint32_t* to, const uint32_t* from, size_t max); size_t u32_u8_strncpy(uint32_t* to, const char* from, size_t max); @@ -58,4 +68,4 @@ const int u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace) const int starts_with(const char* s, const char* with); const int u32_starts_with(const uint32_t* s, const uint32_t* with); const char* u8_basename(const char* path); -void poe_log(const char* msg, ...); +/*void poe_log(const char* msg, ...);*/