From 2b43340c90fb73788c701c971b20ef45a2090256 Mon Sep 17 00:00:00 2001 From: jfreegman Date: Wed, 28 Oct 2020 00:54:06 -0400 Subject: [PATCH 1/3] Convert all variable length arrays to heap allocations VLA's are inherently unsafe so the safest option is to not use them --- Makefile | 2 +- src/audio_device.c | 25 +++++++++--- src/autocomplete.c | 54 +++++++++++++++++-------- src/avatars.c | 13 +++++- src/chat.c | 36 +++++++++++++---- src/file_transfers.c | 12 +++++- src/friendlist.c | 31 ++++++++++++--- src/global_commands.c | 44 ++++++++++++++++++--- src/misc_tools.c | 75 ++++++++++++++++++++++++++++++----- src/misc_tools.h | 26 ++++++++++-- src/qr_code.c | 14 ++++++- src/toxic.c | 92 ++++++++++++++++++++++++++++++++++++++----- 12 files changed, 355 insertions(+), 69 deletions(-) diff --git a/Makefile b/Makefile index 4326556a0..8f6b0f319 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CFG_DIR = $(BASE_DIR)/cfg LIBS = toxcore ncursesw libconfig libcurl CFLAGS ?= -g -CFLAGS += -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all +CFLAGS += -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64 CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"' CFLAGS += ${USER_CFLAGS} diff --git a/src/audio_device.c b/src/audio_device.c index 200bf52bd..ebc5d6e52 100644 --- a/src/audio_device.c +++ b/src/audio_device.c @@ -301,6 +301,16 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx return de_FailedStart; } + size_t zeros_size = frame_size * sizeof(uint16_t); + uint16_t *zeros = calloc(1, zeros_size); + + if (zeros == NULL) { + free(device); + running[type][*device_idx] = NULL; + unlock; + return de_FailedStart; + } + device->ctx = alcCreateContext(device->dhndl, NULL); alcMakeContextCurrent(device->ctx); @@ -308,13 +318,12 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx alGenSources((uint32_t)1, &device->source); alSourcei(device->source, AL_LOOPING, AL_FALSE); - uint16_t zeros[frame_size]; - memset(zeros, 0, frame_size * 2); - for (i = 0; i < OPENAL_BUFS; ++i) { - alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size * 2, sample_rate); + alBufferData(device->buffers[i], device->sound_mode, zeros, zeros_size, sample_rate); } + free(zeros); + alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers); alSourcePlay(device->source); } @@ -425,10 +434,16 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_ alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued); if (processed) { - ALuint bufids[processed]; + ALuint *bufids = malloc(processed * sizeof(ALuint)); + + if (bufids == NULL) { + return de_InternalError; + } + alSourceUnqueueBuffers(device->source, processed, bufids); alDeleteBuffers(processed - 1, bufids + 1); bufid = bufids[0]; + free(bufids); } else if (queued < 16) { alGenBuffers(1, &bufid); } else { diff --git a/src/autocomplete.c b/src/autocomplete.c index 2333fef46..92175e294 100644 --- a/src/autocomplete.c +++ b/src/autocomplete.c @@ -38,20 +38,32 @@ #include "execute.h" #include "configdir.h" -static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size) +static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matches) { if (m) { execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE); } - const char *L = (char *) list; - int i; + for (size_t i = 0; i < n_matches; ++i) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]); + } - for (i = 0; i < n_items; ++i) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); +} + +static void print_dir_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size) +{ + if (m) { + execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE); + } + + const char *L = (char *)list; + + for (size_t i = 0; i < n_items; ++i) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]); } - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */ + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); } /* puts match in match buffer. if more than one match, add first n chars that are identical. @@ -59,21 +71,19 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_it * * Returns the length of the match. */ -static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char (*matches)[MAX_STR_SIZE], int n) +static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char **matches, size_t n_items, + size_t max_size) { UNUSED_VAR(self); - if (n == 1) { + if (n_items == 1) { return snprintf(match, match_sz, "%s", matches[0]); } - int i; - - for (i = 0; i < MAX_STR_SIZE; ++i) { + for (size_t i = 0; i < max_size; ++i) { char ch1 = matches[0][i]; - int j; - for (j = 0; j < n; ++j) { + for (size_t j = 0; j < n_items; ++j) { char ch2 = matches[j][i]; if (ch1 != ch2 || !ch1) { @@ -102,7 +112,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char * * Note: This function should not be called directly. Use complete_line() and complete_path() instead. */ -static int complete_line_helper(ToxWindow *self, const void *list, size_t n_items, size_t size, bool dir_search) +static int complete_line_helper(ToxWindow *self, const void *list, const size_t n_items, size_t size, bool dir_search) { ChatContext *ctx = self->chatwin; @@ -161,7 +171,14 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item int s_len = strlen(sub); size_t n_matches = 0; - char matches[n_items][MAX_STR_SIZE]; + + char **matches = (char **)malloc_ptr_array(n_items, MAX_STR_SIZE, sizeof(char *)); + + if (matches == NULL) { + free(sub); + return -1; + } + int i = 0; /* put all list matches in matches array */ @@ -177,15 +194,18 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item free(sub); if (!n_matches) { + free_ptr_array((void **) matches, n_items); return -1; } if (!dir_search && n_matches > 1) { - print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE); + print_ac_matches(self, NULL, matches, n_matches); } char match[MAX_STR_SIZE]; - size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches); + size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches, MAX_STR_SIZE); + + free_ptr_array((void **) matches, n_items); if (match_len == 0) { return 0; @@ -365,7 +385,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) if (dircount > 1) { qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr); - print_matches(self, m, dirnames, dircount, NAME_MAX + 1); + print_dir_matches(self, m, dirnames, dircount, NAME_MAX + 1); } return complete_path(self, dirnames, dircount, NAME_MAX + 1); diff --git a/src/avatars.c b/src/avatars.c index 6e52786c6..d20f561ac 100644 --- a/src/avatars.c +++ b/src/avatars.c @@ -196,17 +196,26 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, ft->position = position; } - uint8_t send_data[length]; - size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file); + uint8_t *send_data = malloc(length); + + if (send_data == NULL) { + close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent); + return; + } + + size_t send_length = fread(send_data, 1, length, ft->file); if (send_length != length) { close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent); + free(send_data); return; } Tox_Err_File_Send_Chunk err; tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err); + free(send_data); + if (err != TOX_ERR_FILE_SEND_CHUNK_OK) { fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err); } diff --git a/src/chat.c b/src/chat.c index 00f126276..1f1f6b496 100644 --- a/src/chat.c +++ b/src/chat.c @@ -422,18 +422,28 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, ft->position = position; } - uint8_t send_data[length]; - size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file); + uint8_t *send_data = malloc(length); + + if (send_data == NULL) { + snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Out of memory.", ft->file_name); + close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + return; + } + + size_t send_length = fread(send_data, 1, length, ft->file); if (send_length != length) { snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read fail.", ft->file_name); close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error); + free(send_data); return; } Tox_Err_File_Send_Chunk err; tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err); + free(send_data); + if (err != TOX_ERR_FILE_SEND_CHUNK_OK) { fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err); } @@ -613,20 +623,29 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ bytes_convert_str(sizestr, sizeof(sizestr), file_size); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr); - char file_path[PATH_MAX + name_length + 1]; + size_t file_path_buf_size = PATH_MAX + name_length + 1; + char *file_path = malloc(file_path_buf_size); + + if (file_path == NULL) { + tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Out of memory."); + return; + } + size_t path_len = name_length; /* use specified download path in config if possible */ if (!string_is_empty(user_settings->download_path)) { - snprintf(file_path, sizeof(file_path), "%s%s", user_settings->download_path, filename); + snprintf(file_path, file_path_buf_size, "%s%s", user_settings->download_path, filename); path_len += strlen(user_settings->download_path); } else { - snprintf(file_path, sizeof(file_path), "%s", filename); + snprintf(file_path, file_path_buf_size, "%s", filename); } - if (path_len >= sizeof(file_path) || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) { + if (path_len >= file_path_buf_size || path_len >= sizeof(ft->file_path) || name_length >= sizeof(ft->file_name)) { tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer faield: File path too long."); + free(file_path); return; } @@ -642,7 +661,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ ++count; size_t d_len = strlen(d); - if (path_len + d_len >= sizeof(file_path)) { + if (path_len + d_len >= file_path_buf_size) { path_len -= d_len; file_path[path_len] = '\0'; } @@ -653,6 +672,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ if (count > 999) { tox_file_control(m, friendnum, filenum, TOX_FILE_CONTROL_CANCEL, NULL); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: invalid file path."); + free(file_path); return; } } @@ -664,6 +684,8 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename); tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL); + free(file_path); + if (self->active_box != -1) { box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans, self->active_box, "Incoming file: %s", filename); diff --git a/src/file_transfers.c b/src/file_transfers.c index 26a6dc8a7..82df43512 100644 --- a/src/file_transfers.c +++ b/src/file_transfers.c @@ -81,10 +81,18 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l strcat(prog_line, "-"); } - char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7]; - snprintf(full_line, sizeof(full_line), "%s [%s] %s/s", pct_str, prog_line, bps_str); + size_t line_buf_size = strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7; + char *full_line = malloc(line_buf_size); + + if (full_line == NULL) { + return; + } + + snprintf(full_line, line_buf_size, "%s [%s] %s/s", pct_str, prog_line, bps_str); line_info_set(self, line_id, full_line); + + free(full_line); } static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft) diff --git a/src/friendlist.c b/src/friendlist.c index f5b680db7..a7122aea3 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -187,13 +187,21 @@ static int save_blocklist(char *path) return 0; } - char temp_path[strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1]; - snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_BLOCKLIST_EXT); + size_t temp_buf_size = strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1; + char *temp_path = malloc(temp_buf_size); + + if (temp_path == NULL) { + free(data); + return -1; + } + + snprintf(temp_path, temp_buf_size, "%s%s", path, TEMP_BLOCKLIST_EXT); FILE *fp = fopen(temp_path, "wb"); if (fp == NULL) { free(data); + free(temp_path); return -1; } @@ -201,6 +209,7 @@ static int save_blocklist(char *path) fprintf(stderr, "Failed to write blocklist data.\n"); fclose(fp); free(data); + free(temp_path); return -1; } @@ -208,9 +217,12 @@ static int save_blocklist(char *path) free(data); if (rename(temp_path, path) != 0) { + free(temp_path); return -1; } + free(temp_path); + return 0; } @@ -235,15 +247,22 @@ int load_blocklist(char *path) return -1; } - char data[len]; + char *data = malloc(len); + + if (data == NULL) { + fclose(fp); + return -1; + } if (fread(data, len, 1, fp) != 1) { fclose(fp); + free(data); return -1; } if (len % sizeof(BlockedFriend) != 0) { fclose(fp); + free(data); return -1; } @@ -251,9 +270,7 @@ int load_blocklist(char *path) Blocked.max_idx = num; realloc_blocklist(num); - int i; - - for (i = 0; i < num; ++i) { + for (int i = 0; i < num; ++i) { BlockedFriend tmp; memset(&tmp, 0, sizeof(BlockedFriend)); memset(&Blocked.list[i], 0, sizeof(BlockedFriend)); @@ -279,6 +296,8 @@ int load_blocklist(char *path) } fclose(fp); + free(data); + sort_blocklist_index(); return 0; diff --git a/src/global_commands.c b/src/global_commands.c index 265a7bdd1..13ab112f8 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -476,45 +476,79 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA nick[nick_len] = '\0'; size_t data_file_len = strlen(DATA_FILE); - char dir[data_file_len + 1]; + char *dir = malloc(data_file_len + 1); + + if (dir == NULL) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory."); + return; + } + size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir); #ifdef QRPNG if (argc == 0) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'"); + free(dir); return; } else if (!strcmp(argv[1], "txt")) { #endif /* QRPNG */ - char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1]; - snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT); + size_t qr_path_buf_size = dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1; + char *qr_path = malloc(qr_path_buf_size); + + if (qr_path == NULL) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory"); + free(dir); + return; + } + + snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT); if (ID_to_QRcode_txt(id_string, qr_path) == -1) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); + free(dir); + free(qr_path); return; } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path); + free(qr_path); + #ifdef QRPNG } else if (!strcmp(argv[1], "png")) { - char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1]; - snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG); + size_t qr_path_buf_size = dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1; + char *qr_path = malloc(qr_path_buf_size); + + if (qr_path == NULL) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory"); + free(dir); + return; + } + + snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG); if (ID_to_QRcode_png(id_string, qr_path) == -1) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); + free(dir); + free(qr_path); return; } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path); + free(qr_path); + } else { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]); + free(dir); return; } #endif /* QRPNG */ + + free(dir); } #endif /* QRCODE */ diff --git a/src/misc_tools.c b/src/misc_tools.c index 953e86392..b0b884131 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -50,16 +50,20 @@ void clear_screen(void) void hst_to_net(uint8_t *num, uint16_t numbytes) { #ifndef WORDS_BIGENDIAN - uint32_t i; - uint8_t buff[numbytes]; + uint8_t *buff = malloc(numbytes); - for (i = 0; i < numbytes; ++i) { + if (buff == NULL) { + return; + } + + for (uint32_t i = 0; i < numbytes; ++i) { buff[i] = num[numbytes - i - 1]; } memcpy(num, buff, numbytes); + + free(buff); #endif - return; } time_t get_unix_time(void) @@ -527,20 +531,31 @@ off_t file_size(const char *path) return st.st_size; } -/* compares the first size bytes of fp to signature. - Returns 0 if they are the same, 1 if they differ, and -1 on error. - - On success this function will seek back to the beginning of fp */ +/* Compares the first size bytes of fp to signature. + * + * Returns 0 if they are the same + * Returns 1 if they differ + * Returns -1 on error. + * + * On success this function will seek back to the beginning of fp. + */ int check_file_signature(const unsigned char *signature, size_t size, FILE *fp) { - char buf[size]; + char *buf = malloc(size); + + if (buf == NULL) { + return -1; + } if (fread(buf, size, 1, fp) != 1) { + free(buf); return -1; } int ret = memcmp(signature, buf, size); + free(buf); + if (fseek(fp, 0L, SEEK_SET) == -1) { return -1; } @@ -603,3 +618,45 @@ bool is_ip6_address(const char *address) return num_colons > 1 && num_colons < 8; } + +/* + * Frees `length` members of pointer array `arr` and frees `arr`. + */ +void free_ptr_array(void **arr, size_t length) +{ + if (arr == NULL) { + return; + } + + for (size_t i = 0; i < length; ++i) { + free(arr[i]); + } + + free(arr); +} + +/* + * Returns a new array of `length` pointers of size `ptr_size`. Each pointer is allocated `bytes` bytes. + * Returns NULL on failure. + * + * The caller is responsible for freeing the array with `free_ptr_array`. + */ +void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size) +{ + void **arr = malloc(length * ptr_size); + + if (arr == NULL) { + return NULL; + } + + for (size_t i = 0; i < length; ++i) { + arr[i] = malloc(bytes); + + if (arr[i] == NULL) { + free_ptr_array(arr, i); + return NULL; + } + } + + return arr; +} diff --git a/src/misc_tools.h b/src/misc_tools.h index 551f62b5c..26620d364 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -169,10 +169,14 @@ File_Type file_type(const char *path); /* returns file size. If file doesn't exist returns 0. */ off_t file_size(const char *path); -/* compares the first size bytes of fp and signature. - Returns 0 if they are the same, 1 if they differ, and -1 on error. - - On success this function will seek back to the beginning of fp */ +/* Compares the first size bytes of fp to signature. + * + * Returns 0 if they are the same + * Returns 1 if they differ + * Returns -1 on error. + * + * On success this function will seek back to the beginning of fp. + */ int check_file_signature(const unsigned char *signature, size_t size, FILE *fp); /* sets window title in tab bar. */ @@ -190,4 +194,18 @@ bool is_ip4_address(const char *address); */ bool is_ip6_address(const char *address); + +/* + * Frees `length` members of pointer array `arr` and frees `arr`. + */ +void free_ptr_array(void **arr, size_t length); + +/* + * Returns a new array of `length` pointers of size `ptr_size`. Each pointer is allocated `bytes` bytes. + * Returns NULL on failure. + * + * The caller is responsible for freeing the array with `free_ptr_array`. + */ +void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size); + #endif /* MISC_TOOLS_H */ diff --git a/src/qr_code.c b/src/qr_code.c index 102ece9dc..da9286e83 100644 --- a/src/qr_code.c +++ b/src/qr_code.c @@ -138,12 +138,18 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile) real_width = (qr_obj->width + BORDER_LEN * 2) * SQUARE_SIZE; size_t row_size = real_width * 4; - unsigned char row[row_size]; + unsigned char *row = malloc(row_size); + + if (row == NULL) { + fclose(fp); + return -1; + } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); + free(row); QRcode_free(qr_obj); return -1; } @@ -152,12 +158,14 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile) if (info_ptr == NULL) { fclose(fp); + free(row); QRcode_free(qr_obj); return -1; } if (setjmp(png_jmpbuf(png_ptr))) { fclose(fp); + free(row); QRcode_free(qr_obj); png_destroy_write_struct(&png_ptr, &info_ptr); return -1; @@ -206,10 +214,12 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile) png_write_row(png_ptr, row); } + free(row); + fclose(fp); + png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); QRcode_free(qr_obj); return 0; diff --git a/src/toxic.c b/src/toxic.c index 4b7c7d65d..15d7f799a 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -362,7 +362,13 @@ static void load_conferences(Tox *m) return; } - uint32_t chatlist[num_chats]; + uint32_t *chatlist = malloc(num_chats * sizeof(uint32_t)); + + if (chatlist == NULL) { + fprintf(stderr, "malloc() failed in load_conferences()\n"); + return; + } + tox_conference_get_chatlist(m, chatlist); for (size_t i = 0; i < num_chats; ++i) { @@ -402,6 +408,8 @@ static void load_conferences(Tox *m) continue; } } + + free(chatlist); } /* return length of password on success, 0 on failure */ @@ -567,12 +575,19 @@ int store_data(Tox *m, const char *path) return -1; } - char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1]; - snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT); + size_t temp_buf_size = strlen(path) + strlen(TEMP_PROFILE_EXT) + 1; + char *temp_path = malloc(temp_buf_size); + + if (temp_path == NULL) { + return -1; + } + + snprintf(temp_path, temp_buf_size, "%s%s", path, TEMP_PROFILE_EXT); FILE *fp = fopen(temp_path, "wb"); if (fp == NULL) { + free(temp_path); return -1; } @@ -580,6 +595,7 @@ int store_data(Tox *m, const char *path) char *data = malloc(data_len * sizeof(char)); if (data == NULL) { + free(temp_path); fclose(fp); return -1; } @@ -592,6 +608,7 @@ int store_data(Tox *m, const char *path) if (enc_data == NULL) { fclose(fp); + free(temp_path); free(data); return -1; } @@ -603,6 +620,7 @@ int store_data(Tox *m, const char *path) if (err != TOX_ERR_ENCRYPTION_OK) { fprintf(stderr, "tox_pass_encrypt() failed with error %d\n", err); fclose(fp); + free(temp_path); free(data); free(enc_data); return -1; @@ -611,6 +629,7 @@ int store_data(Tox *m, const char *path) if (fwrite(enc_data, enc_len, 1, fp) != 1) { fprintf(stderr, "Failed to write profile data.\n"); fclose(fp); + free(temp_path); free(data); free(enc_data); return -1; @@ -621,6 +640,7 @@ int store_data(Tox *m, const char *path) if (fwrite(data, data_len, 1, fp) != 1) { fprintf(stderr, "Failed to write profile data.\n"); fclose(fp); + free(temp_path); free(data); return -1; } @@ -630,9 +650,12 @@ int store_data(Tox *m, const char *path) free(data); if (rename(temp_path, path) != 0) { + free(temp_path); return -1; } + free(temp_path); + return 0; } @@ -719,13 +742,22 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (len == 0) { fclose(fp); exit_toxic_err("failed in load_tox", FATALERR_FILEOP); + return NULL; } - char data[len]; + char *data = malloc(len); - if (fread(data, sizeof(data), 1, fp) != 1) { + if (data == NULL) { fclose(fp); + exit_toxic_err("failed in load_tox", FATALERR_MEMORY); + return NULL; + } + + if (fread(data, len, 1, fp) != 1) { + fclose(fp); + free(data); exit_toxic_err("failed in load_tox", FATALERR_FILEOP); + return NULL; } bool is_encrypted = tox_is_data_encrypted((uint8_t *) data); @@ -733,7 +765,9 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New /* attempt to encrypt an already encrypted data file */ if (arg_opts.encrypt_data && is_encrypted) { fclose(fp); + free(data); exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT); + return NULL; } if (arg_opts.unencrypt_data && is_encrypted) { @@ -756,7 +790,13 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New } size_t plain_len = len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; - char plain[plain_len]; + char *plain = malloc(plain_len); // must be freed after tox_new() + + if (plain == NULL) { + fclose(fp); + exit_toxic_err("failed in load_tox", FATALERR_MEMORY); + return NULL; + } while (true) { fflush(stdout); // Flush before prompts so the user sees the question/message @@ -771,6 +811,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (strcasecmp(user_password.pass, "q") == 0) { fclose(fp); + free(plain); exit(0); } @@ -794,6 +835,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (m == NULL) { fclose(fp); + free(data); + free(plain); return NULL; } @@ -805,9 +848,14 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New pweval = 0; } else { fclose(fp); + free(data); + free(plain); exit_toxic_err("tox_pass_decrypt() failed", pwerr); + return NULL; } } + + free(plain); } else { /* data is not encrypted */ tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE); tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len); @@ -816,14 +864,17 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (m == NULL) { fclose(fp); + free(data); return NULL; } } fclose(fp); + free(data); } else { /* Data file does not/should not exist */ if (file_exists(data_path)) { exit_toxic_err("failed in load_tox", FATALERR_FILEOP); + return NULL; } tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_NONE); @@ -836,6 +887,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (store_data(m, data_path) == -1) { exit_toxic_err("failed in load_tox", FATALERR_FILEOP); + return NULL; } } @@ -1207,38 +1259,60 @@ static void parse_args(int argc, char *argv[]) #define OLD_DATA_BLOCKLIST_NAME "data-blocklist" static int rename_old_profile(const char *user_config_dir) { - char old_data_file[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1]; - snprintf(old_data_file, sizeof(old_data_file), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME); + size_t old_buf_size = strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1; + char *old_data_file = malloc(old_buf_size); + + if (old_data_file == NULL) { + return -1; + } + + snprintf(old_data_file, old_buf_size, "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME); if (!file_exists(old_data_file)) { + free(old_data_file); return 0; } if (file_exists(DATA_FILE)) { + free(old_data_file); return 0; } if (rename(old_data_file, DATA_FILE) != 0) { + free(old_data_file); return -1; } + free(old_data_file); + queue_init_message("Data file has been moved to %s", DATA_FILE); - char old_data_blocklist[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1]; + size_t old_block_buf_size = strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1; + char *old_data_blocklist = malloc(old_block_buf_size); + + if (old_data_blocklist == NULL) { + return -1; + } + snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME); if (!file_exists(old_data_blocklist)) { + free(old_data_blocklist); return 0; } if (file_exists(BLOCK_FILE)) { + free(old_data_blocklist); return 0; } if (rename(old_data_blocklist, BLOCK_FILE) != 0) { + free(old_data_blocklist); return -1; } + free(old_data_blocklist); + return 0; } From 7560bc95477c4b2a19882079695d2a0773ef032d Mon Sep 17 00:00:00 2001 From: jfreegman Date: Thu, 29 Oct 2020 20:28:09 -0400 Subject: [PATCH 2/3] modularize string arrays for line completion Instead of using various different forms of string arrays and having to handle them differently for string completion, we now always use char pointer arrays. This allows us to remove some large stack allocations, remove a bunch of confusing defines that keep track of global array sizes, and generally unclutters the code so it's easier to read. --- src/audio_device.c | 1 + src/autocomplete.c | 70 +++++++++++------------- src/autocomplete.h | 9 ++-- src/chat.c | 97 ++++++++++++++------------------- src/file_transfers.c | 5 +- src/global_commands.c | 4 +- src/groupchat.c | 122 ++++++++++++++++++++---------------------- src/groupchat.h | 2 +- src/misc_tools.c | 33 +++++++----- src/misc_tools.h | 11 ++-- src/prompt.c | 81 +++++++++++----------------- src/qr_code.c | 1 + src/toxic.c | 4 +- 13 files changed, 203 insertions(+), 237 deletions(-) diff --git a/src/audio_device.c b/src/audio_device.c index ebc5d6e52..2efc11933 100644 --- a/src/audio_device.c +++ b/src/audio_device.c @@ -437,6 +437,7 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_ ALuint *bufids = malloc(processed * sizeof(ALuint)); if (bufids == NULL) { + pthread_mutex_unlock(device->mutex); return de_InternalError; } diff --git a/src/autocomplete.c b/src/autocomplete.c index 92175e294..51d38849c 100644 --- a/src/autocomplete.c +++ b/src/autocomplete.c @@ -51,21 +51,6 @@ static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matc line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); } -static void print_dir_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size) -{ - if (m) { - execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE); - } - - const char *L = (char *)list; - - for (size_t i = 0; i < n_items; ++i) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]); - } - - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); -} - /* puts match in match buffer. if more than one match, add first n chars that are identical. * e.g. if matches contains: [foo, foobar, foe] we put fo in match. * @@ -102,8 +87,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char * then fills line with the complete word. e.g. "Hello jo" would complete the line * with "Hello john". If multiple matches, prints out all the matches and semi-completes line. * - * list is a pointer to the list of strings being compared, n_items is the number of items - * in the list, and size is the size of each item in the list. + * `list` is a pointer to `n_items` strings. Each string in the list must be <= MAX_STR_SIZE. * * dir_search should be true if the line being completed is a file path. * @@ -112,7 +96,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char * * Note: This function should not be called directly. Use complete_line() and complete_path() instead. */ -static int complete_line_helper(ToxWindow *self, const void *list, const size_t n_items, size_t size, bool dir_search) +static int complete_line_helper(ToxWindow *self, const char **list, const size_t n_items, bool dir_search) { ChatContext *ctx = self->chatwin; @@ -120,11 +104,10 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t return -1; } - if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) { + if (ctx->len >= MAX_STR_SIZE) { return -1; } - const char *L = (const char *) list; const char *endchrs = " "; char ubuf[MAX_STR_SIZE] = {0}; @@ -172,29 +155,24 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t int s_len = strlen(sub); size_t n_matches = 0; - char **matches = (char **)malloc_ptr_array(n_items, MAX_STR_SIZE, sizeof(char *)); + char **matches = (char **) malloc_ptr_array(n_items, MAX_STR_SIZE); if (matches == NULL) { free(sub); return -1; } - int i = 0; - /* put all list matches in matches array */ - for (i = 0; i < n_items; ++i) { - char str[MAX_CMDNAME_SIZE + 1]; - snprintf(str, sizeof(str), "%s", &L[i * size]); - - if (strncasecmp(str, sub, s_len) == 0) { - strcpy(matches[n_matches++], str); + for (size_t i = 0; i < n_items; ++i) { + if (strncasecmp(list[i], sub, s_len) == 0) { + snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]); } } free(sub); if (!n_matches) { - free_ptr_array((void **) matches, n_items); + free_ptr_array((void **) matches); return -1; } @@ -205,7 +183,7 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t char match[MAX_STR_SIZE]; size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches, MAX_STR_SIZE); - free_ptr_array((void **) matches, n_items); + free_ptr_array((void **) matches); if (match_len == 0) { return 0; @@ -281,14 +259,14 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t return diff; } -int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size) +int complete_line(ToxWindow *self, const char **list, size_t n_items) { - return complete_line_helper(self, list, n_items, size, false); + return complete_line_helper(self, list, n_items, false); } -static int complete_path(ToxWindow *self, const void *list, size_t n_items, size_t size) +static int complete_path(ToxWindow *self, const char **list, const size_t n_items) { - return complete_line_helper(self, list, n_items, size, true); + return complete_line_helper(self, list, n_items, true); } /* Transforms a tab complete starting with the shorthand "~" into the full home directory. */ @@ -365,14 +343,21 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) return -1; } - char dirnames[MAX_DIRS][NAME_MAX + 1]; + char **dirnames = (char **) malloc_ptr_array(MAX_DIRS, NAME_MAX + 1); + + if (dirnames == NULL) { + closedir(dp); + return -1; + } + struct dirent *entry; + int dircount = 0; while ((entry = readdir(dp)) && dircount < MAX_DIRS) { if (strncmp(entry->d_name, b_name, b_name_len) == 0 && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) { - snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name); + snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name); ++dircount; } } @@ -380,13 +365,18 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) closedir(dp); if (dircount == 0) { + free_ptr_array((void **) dirnames); return -1; } if (dircount > 1) { - qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr); - print_dir_matches(self, m, dirnames, dircount, NAME_MAX + 1); + qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper); + print_ac_matches(self, m, dirnames, dircount); } - return complete_path(self, dirnames, dircount, NAME_MAX + 1); + int ret = complete_path(self, (const char **) dirnames, dircount); + + free_ptr_array((void **) dirnames); + + return ret; } diff --git a/src/autocomplete.h b/src/autocomplete.h index 64f588709..022aa40ff 100644 --- a/src/autocomplete.h +++ b/src/autocomplete.h @@ -28,13 +28,16 @@ * then fills line with the complete word. e.g. "Hello jo" would complete the line * with "Hello john". If multiple matches, prints out all the matches and semi-completes line. * - * list is a pointer to the list of strings being compared, n_items is the number of items - * in the list, and size is the size of each item in the list. +* `list` is a pointer to `n_items` strings. + * + * dir_search should be true if the line being completed is a file path. * * Returns the difference between the old len and new len of line on success. * Returns -1 on error. + * + * Note: This function should not be called directly. Use complete_line() and complete_path() instead. */ -int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size); +int complete_line(ToxWindow *self, const char **list, size_t n_items); /* Attempts to match /command "" line to matching directories. * If there is only one match the line is auto-completed. diff --git a/src/chat.c b/src/chat.c index 1f1f6b496..bf9ddcab3 100644 --- a/src/chat.c +++ b/src/chat.c @@ -65,67 +65,50 @@ static void init_infobox(ToxWindow *self); static void kill_infobox(ToxWindow *self); #endif /* AUDIO */ -#ifdef AUDIO -#define AC_NUM_CHAT_COMMANDS_AUDIO 9 -#else -#define AC_NUM_CHAT_COMMANDS_AUDIO 0 -#endif /* AUDIO */ -#ifdef PYTHON -#define AC_NUM_CHAT_COMMANDS_PYTHON 1 -#else -#define AC_NUM_CHAT_COMMANDS_PYTHON 0 -#endif /* PYTHON */ -#ifdef QRCODE -#define AC_NUM_CHAT_COMMANDS_QRCODE 1 -#else -#define AC_NUM_CHAT_COMMANDS_QRCODE 0 -#endif /* QRCODE */ -#define AC_NUM_CHAT_COMMANDS (21 + AC_NUM_CHAT_COMMANDS_AUDIO + AC_NUM_CHAT_COMMANDS_PYTHON + AC_NUM_CHAT_COMMANDS_QRCODE) - /* Array of chat command names used for tab completion. */ -static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { - { "/accept" }, - { "/add" }, - { "/avatar" }, - { "/cancel" }, - { "/clear" }, - { "/close" }, - { "/connect" }, - { "/exit" }, - { "/group" }, - { "/help" }, - { "/invite" }, - { "/join" }, - { "/log" }, - { "/myid" }, +static const char *chat_cmd_list[] = { + "/accept", + "/add", + "/avatar", + "/cancel", + "/clear", + "/close", + "/connect", + "/exit", + "/group", + "/help", + "/invite", + "/join", + "/log", + "/myid", #ifdef QRCODE - { "/myqr" }, + "/myqr", #endif /* QRCODE */ - { "/nick" }, - { "/note" }, - { "/nospam" }, - { "/quit" }, - { "/savefile" }, - { "/sendfile" }, - { "/status" }, + "/nick", + "/note", + "/nospam", + "/quit", + "/savefile", + "/sendfile", + "/status", #ifdef AUDIO - { "/call" }, - { "/answer" }, - { "/reject" }, - { "/hangup" }, - { "/sdev" }, - { "/mute" }, - { "/sense" }, - { "/video" }, - { "/bitrate" }, + "/call", + "/answer", + "/reject", + "/hangup", + "/sdev", + "/mute", + "/sense", + "/video", + "/bitrate", #endif /* AUDIO */ #ifdef PYTHON - { "/run" }, + "/run", #endif /* PYTHON */ }; @@ -662,7 +645,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_ size_t d_len = strlen(d); if (path_len + d_len >= file_path_buf_size) { - path_len -= d_len; + path_len = file_path_buf_size - d_len - 1; file_path[path_len] = '\0'; } @@ -1090,14 +1073,14 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) #endif else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) { - const char status_cmd_list[3][8] = { - {"online"}, - {"away"}, - {"busy"}, + const char *status_cmd_list[] = { + "online", + "away", + "busy", }; - diff = complete_line(self, status_cmd_list, 3, 8); + diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *)); } else { - diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); + diff = complete_line(self, chat_cmd_list, sizeof(chat_cmd_list) / sizeof(char *)); } if (diff != -1) { diff --git a/src/file_transfers.c b/src/file_transfers.c index 82df43512..32e3ae4c8 100644 --- a/src/file_transfers.c +++ b/src/file_transfers.c @@ -37,6 +37,7 @@ extern FriendsList Friends; /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */ #define NUM_PROG_MARKS 50 +#define STR_BUF_SIZE 30 /* creates initial progress line that will be updated during file transfer. Assumes progline has room for at least MAX_STR_SIZE bytes */ @@ -59,10 +60,10 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l return; } - char pct_str[24]; + char pct_str[STR_BUF_SIZE] = {0}; snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done); - char bps_str[24]; + char bps_str[STR_BUF_SIZE] = {0}; bytes_convert_str(bps_str, sizeof(bps_str), bps); char prog_line[NUM_PROG_MARKS + 1] = {0}; diff --git a/src/global_commands.c b/src/global_commands.c index 13ab112f8..292dc207f 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -494,7 +494,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA } else if (!strcmp(argv[1], "txt")) { #endif /* QRPNG */ - size_t qr_path_buf_size = dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1; + size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT); char *qr_path = malloc(qr_path_buf_size); if (qr_path == NULL) { @@ -518,7 +518,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA #ifdef QRPNG } else if (!strcmp(argv[1], "png")) { - size_t qr_path_buf_size = dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1; + size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT_PNG); char *qr_path = malloc(qr_path_buf_size); if (qr_path == NULL) { diff --git a/src/groupchat.c b/src/groupchat.c index 83bad18be..0e4c1f0bb 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -70,46 +70,34 @@ static int max_groupchat_index = 0; extern struct user_settings *user_settings; extern struct Winthread Winthread; -#ifdef PYTHON -#define AC_NUM_GROUP_COMMANDS_PYTHON 1 -#else -#define AC_NUM_GROUP_COMMANDS_PYTHON 0 -#endif /* PYTHON */ -#ifdef QRCODE -#define AC_NUM_GROUP_COMMANDS_QRCODE 1 -#else -#define AC_NUM_GROUP_COMMANDS_QRCODE 0 -#endif /* QRCODE */ -#define AC_NUM_GROUP_COMMANDS (19 + AC_NUM_GROUP_COMMANDS_PYTHON + AC_NUM_GROUP_COMMANDS_QRCODE) - /* Array of groupchat command names used for tab completion. */ -static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = { - { "/accept" }, - { "/add" }, - { "/avatar" }, - { "/clear" }, - { "/close" }, - { "/connect" }, - { "/decline" }, - { "/exit" }, - { "/group" }, - { "/help" }, - { "/log" }, - { "/myid" }, +static const char *group_cmd_list[] = { + "/accept", + "/add", + "/avatar", + "/clear", + "/close", + "/connect", + "/decline", + "/exit", + "/group", + "/help", + "/log", + "/myid", #ifdef QRCODE - { "/myqr" }, + "/myqr", #endif /* QRCODE */ - { "/nick" }, - { "/note" }, - { "/nospam" }, - { "/quit" }, - { "/requests" }, - { "/status" }, - { "/title" }, + "/nick", + "/note", + "/nospam", + "/quit", + "/requests", + "/status", + "/title", #ifdef PYTHON - { "/run" }, + "/run", #endif /* PYTHON */ }; @@ -166,7 +154,7 @@ int init_groupchat_win(Tox *m, uint32_t groupnum, uint8_t type, const char *titl void free_groupchat(ToxWindow *self, uint32_t groupnum) { - free(groupchats[groupnum].name_list); + free_ptr_array((void **) groupchats[groupnum].name_list); free(groupchats[groupnum].peer_list); memset(&groupchats[groupnum], 0, sizeof(GroupChat)); @@ -309,26 +297,26 @@ static void group_update_name_list(uint32_t groupnum) return; } - if (chat->name_list) { - free(chat->name_list); - } - - chat->name_list = malloc(sizeof(char *) * chat->num_peers * TOX_MAX_NAME_LENGTH); - - if (chat->name_list == NULL) { - exit_toxic_err("failed in group_update_name_list", FATALERR_MEMORY); + if (!chat->name_list) { + fprintf(stderr, "WARNING: name_list is NULL\n"); + return; } - uint32_t i, count = 0; + size_t count = 0; - for (i = 0; i < chat->max_idx; ++i) { + for (uint32_t i = 0; i < chat->max_idx && count < chat->num_peers; ++i) { if (chat->peer_list[i].active) { - memcpy(&chat->name_list[count * TOX_MAX_NAME_LENGTH], chat->peer_list[i].name, chat->peer_list[i].name_length + 1); + memcpy(chat->name_list[count], chat->peer_list[i].name, chat->peer_list[i].name_length); + chat->name_list[count][chat->peer_list[i].name_length] = 0; ++count; } } - qsort(chat->name_list, count, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr); + if (count != chat->num_peers) { + fprintf(stderr, "WARNING: count != chat->num_peers\n"); + } + + qsort(chat->name_list, count, sizeof(char *), qsort_ptr_char_array_helper); } /* Reallocates groupnum's peer list. Increase is true if the list needs to grow. @@ -369,9 +357,7 @@ static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers) realloc_peer_list(chat, num_peers); - uint32_t i; - - for (i = 0; i < num_peers; ++i) { + for (uint32_t i = 0; i < num_peers; ++i) { GroupPeer *peer = &chat->peer_list[i]; Tox_Err_Conference_Peer_Query err; @@ -412,17 +398,29 @@ static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t gr return; } + if (chat->name_list) { + free_ptr_array((void **) chat->name_list); + chat->name_list = NULL; + chat->num_peers = 0; + } + Tox_Err_Conference_Peer_Query err; uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err); - uint32_t old_num = chat->num_peers; - if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) { - chat->num_peers = num_peers; - } else { - num_peers = old_num; + if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) { + fprintf(stderr, "groupchat_onGroupNameListChange() failed with error: %d\n", err); + return; } + chat->name_list = (char **) malloc_ptr_array(num_peers, TOX_MAX_NAME_LENGTH + 1); + + if (chat->name_list == NULL) { + fprintf(stderr, "groupchat_onGroupNameListChange(): Out of memory.\n"); + return; + } + + chat->num_peers = num_peers; chat->max_idx = num_peers; update_peer_list(m, groupnum, num_peers); } @@ -442,9 +440,7 @@ static void groupchat_onGroupPeerNameChange(ToxWindow *self, Tox *m, uint32_t gr return; } - uint32_t i; - - for (i = 0; i < chat->max_idx; ++i) { + for (uint32_t i = 0; i < chat->max_idx; ++i) { GroupPeer *peer = &chat->peer_list[i]; // Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting) @@ -529,8 +525,7 @@ static bool groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) /* TODO: make this not suck */ if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) { - diff = complete_line(self, groupchats[self->num].name_list, groupchats[self->num].num_peers, - TOX_MAX_NAME_LENGTH); + diff = complete_line(self, (const char **) groupchats[self->num].name_list, groupchats[self->num].num_peers); } else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) { diff = dir_match(self, m, ctx->line, L"/avatar"); } @@ -542,7 +537,7 @@ static bool groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) #endif else { - diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE); + diff = complete_line(self, group_cmd_list, sizeof(group_cmd_list) / sizeof(char *)); } if (diff != -1) { @@ -655,9 +650,8 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m) mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1); int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT; - uint32_t i; - for (i = 0; i < num_peers && i < maxlines; ++i) { + for (uint32_t i = 0; i < num_peers && i < maxlines; ++i) { wmove(ctx->sidebar, i + 2, 1); pthread_mutex_lock(&Winthread.lock); @@ -669,7 +663,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m) int maxlen = SIDEBAR_WIDTH - 2; pthread_mutex_lock(&Winthread.lock); - memcpy(tmpnck, &groupchats[self->num].name_list[peer * TOX_MAX_NAME_LENGTH], maxlen); + memcpy(tmpnck, groupchats[self->num].name_list[peer], maxlen); pthread_mutex_unlock(&Winthread.lock); tmpnck[maxlen] = '\0'; diff --git a/src/groupchat.h b/src/groupchat.h index d0883a853..3b4ac3e27 100644 --- a/src/groupchat.h +++ b/src/groupchat.h @@ -48,7 +48,7 @@ typedef struct { GroupPeer *peer_list; uint32_t max_idx; - char *name_list; + char **name_list; uint32_t num_peers; } GroupChat; diff --git a/src/misc_tools.c b/src/misc_tools.c index b0b884131..956e9e2c8 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -42,9 +42,7 @@ extern struct user_settings *user_settings; void clear_screen(void) { - if (system("clear") != 0) { - fprintf(stderr, "Warning: system() failed to clear screen\n"); - } + printf("\033[2J\033[1;1H"); } void hst_to_net(uint8_t *num, uint16_t numbytes) @@ -241,6 +239,12 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2) return strcasecmp((const char *) str1, (const char *) str2); } +/* case-insensitive string compare function for use with qsort */ +int qsort_ptr_char_array_helper(const void *str1, const void *str2) +{ + return strcasecmp(*(char **)str1, *(char **)str2); +} + /* Returns 1 if nick is valid, 0 if not. A valid toxic nick: - cannot be empty - cannot start with a space @@ -620,30 +624,33 @@ bool is_ip6_address(const char *address) } /* - * Frees `length` members of pointer array `arr` and frees `arr`. + * Frees all members of a pointer array plus `arr`. */ -void free_ptr_array(void **arr, size_t length) +void free_ptr_array(void **arr) { if (arr == NULL) { return; } - for (size_t i = 0; i < length; ++i) { - free(arr[i]); + void **tmp = arr; + + while (*arr) { + free(*arr); + ++arr; } - free(arr); + free(tmp); } /* - * Returns a new array of `length` pointers of size `ptr_size`. Each pointer is allocated `bytes` bytes. + * Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes. * Returns NULL on failure. * * The caller is responsible for freeing the array with `free_ptr_array`. */ -void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size) +void **malloc_ptr_array(size_t length, size_t bytes) { - void **arr = malloc(length * ptr_size); + void **arr = malloc((length + 1) * sizeof(void *)); if (arr == NULL) { return NULL; @@ -653,10 +660,12 @@ void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size) arr[i] = malloc(bytes); if (arr[i] == NULL) { - free_ptr_array(arr, i); + free_ptr_array(arr); return NULL; } } + arr[length] = NULL; + return arr; } diff --git a/src/misc_tools.h b/src/misc_tools.h index 26620d364..dc5e42c00 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -107,6 +107,9 @@ void alert_window(ToxWindow *self, int type, bool is_beep); /* case-insensitive string compare function for use with qsort */ int qsort_strcasecmp_hlpr(const void *str1, const void *str2); +/* case-insensitive string compare function for use with qsort */ +int qsort_ptr_char_array_helper(const void *str1, const void *str2); + /* Returns 1 if nick is valid, 0 if not. A valid toxic nick: - cannot be empty - cannot start with a space @@ -196,16 +199,16 @@ bool is_ip6_address(const char *address); /* - * Frees `length` members of pointer array `arr` and frees `arr`. + * Frees all members of a pointer array plus `arr`. */ -void free_ptr_array(void **arr, size_t length); +void free_ptr_array(void **arr); /* - * Returns a new array of `length` pointers of size `ptr_size`. Each pointer is allocated `bytes` bytes. + * Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes. * Returns NULL on failure. * * The caller is responsible for freeing the array with `free_ptr_array`. */ -void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size); +void **malloc_ptr_array(size_t length, size_t bytes); #endif /* MISC_TOOLS_H */ diff --git a/src/prompt.c b/src/prompt.c index 0ab0c4f5c..74a01185c 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -49,68 +49,47 @@ extern struct Winthread Winthread; extern FriendsList Friends; FriendRequests FrndRequests; -#ifdef AUDIO -#define AC_NUM_GLOB_COMMANDS_AUDIO 2 -#else -#define AC_NUM_GLOB_COMMANDS_AUDIO 0 -#endif /* AUDIO */ -#ifdef VIDEO -#define AC_NUM_GLOB_COMMANDS_VIDEO 2 -#else -#define AC_NUM_GLOB_COMMANDS_VIDEO 0 -#endif /* VIDEO */ -#ifdef PYTHON -#define AC_NUM_GLOB_COMMANDS_PYTHON 1 -#else -#define AC_NUM_GLOB_COMMANDS_PYTHON 0 -#endif /* PYTHON */ -#ifdef QRCODE -#define AC_NUM_GLOB_COMMANDS_QRCODE 1 -#else -#define AC_NUM_GLOB_COMMANDS_QRCODE 0 -#endif /* QRCODE */ -#define AC_NUM_GLOB_COMMANDS (17 + AC_NUM_GLOB_COMMANDS_AUDIO + AC_NUM_GLOB_COMMANDS_VIDEO + AC_NUM_GLOB_COMMANDS_PYTHON + AC_NUM_GLOB_COMMANDS_QRCODE) /* Array of global command names used for tab completion. */ -static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = { - { "/accept" }, - { "/add" }, - { "/avatar" }, - { "/clear" }, - { "/connect" }, - { "/decline" }, - { "/exit" }, - { "/group" }, - { "/help" }, - { "/log" }, - { "/myid" }, +static const char *glob_cmd_list[] = { + "/accept", + "/add", + "/avatar", + "/clear", + "/connect", + "/decline", + "/exit", + "/group", + "/help", + "/log", + "/myid", #ifdef QRCODE - { "/myqr" }, + "/myqr", #endif /* QRCODE */ - { "/nick" }, - { "/note" }, - { "/nospam" }, - { "/quit" }, - { "/requests" }, - { "/status" }, + "/nick", + "/note", + "/nospam", + "/quit", + "/requests", + "/status", #ifdef AUDIO - { "/lsdev" }, - { "/sdev" }, + "/lsdev", + "/sdev", #endif /* AUDIO */ #ifdef VIDEO - { "/lsvdev" }, - { "/svdev" }, + "/lsvdev", + "/svdev", #endif /* VIDEO */ #ifdef PYTHON - { "/run" }, + "/run", #endif /* PYTHON */ @@ -272,14 +251,14 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) #endif else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) { - const char status_cmd_list[3][8] = { - {"online"}, - {"away"}, - {"busy"}, + const char *status_cmd_list[] = { + "online", + "away", + "busy", }; - diff = complete_line(self, status_cmd_list, 3, 8); + diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *)); } else { - diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); + diff = complete_line(self, glob_cmd_list, sizeof(glob_cmd_list) / sizeof(char *)); } if (diff != -1) { diff --git a/src/qr_code.c b/src/qr_code.c index da9286e83..6e957af06 100644 --- a/src/qr_code.c +++ b/src/qr_code.c @@ -142,6 +142,7 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile) if (row == NULL) { fclose(fp); + QRcode_free(qr_obj); return -1; } diff --git a/src/toxic.c b/src/toxic.c index 15d7f799a..d815023a9 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -794,6 +794,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (plain == NULL) { fclose(fp); + free(data); exit_toxic_err("failed in load_tox", FATALERR_MEMORY); return NULL; } @@ -812,6 +813,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (strcasecmp(user_password.pass, "q") == 0) { fclose(fp); free(plain); + free(data); exit(0); } @@ -1294,7 +1296,7 @@ static int rename_old_profile(const char *user_config_dir) return -1; } - snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME); + snprintf(old_data_blocklist, old_block_buf_size, "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME); if (!file_exists(old_data_blocklist)) { free(old_data_blocklist); From e7a0c32a6816bed780f047f3b96588be55271f36 Mon Sep 17 00:00:00 2001 From: jfreegman Date: Sun, 1 Nov 2020 15:55:07 -0500 Subject: [PATCH 3/3] Refactor a few complex functions Also moved some single use functions from misc_tools to their respective files --- src/autocomplete.c | 21 +++++-- src/avatars.c | 31 ++++++++++ src/bootstrap.c | 34 +++++++++++ src/misc_tools.c | 141 ++++++++++++++------------------------------- src/misc_tools.h | 40 ++++--------- src/toxic.c | 8 --- 6 files changed, 133 insertions(+), 142 deletions(-) diff --git a/src/autocomplete.c b/src/autocomplete.c index 51d38849c..1ca7c6ba7 100644 --- a/src/autocomplete.c +++ b/src/autocomplete.c @@ -56,7 +56,7 @@ static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matc * * Returns the length of the match. */ -static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char **matches, size_t n_items, +static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char **matches, size_t n_items, size_t max_size) { UNUSED_VAR(self); @@ -181,7 +181,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t } char match[MAX_STR_SIZE]; - size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches, MAX_STR_SIZE); + size_t match_len = get_str_match(self, match, sizeof(match), (const char **) matches, n_matches, MAX_STR_SIZE); free_ptr_array((void **) matches); @@ -298,6 +298,18 @@ static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const c ctx->len = ctx->pos; } +/* + * Return true if the first `p_len` chars in `s` are equal to `p` and `s` is a valid directory name. + */ +static bool is_partial_match(const char *s, const char *p, size_t p_len) +{ + if (s == NULL || p == NULL) { + return false; + } + + return strncmp(s, p, p_len) == 0 && strcmp(".", s) != 0 && strcmp("..", s) != 0; +} + /* Attempts to match /command "" line to matching directories. * If there is only one match the line is auto-completed. * @@ -336,7 +348,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]); b_path[si + 1] = '\0'; - int b_name_len = strlen(b_name); + size_t b_name_len = strlen(b_name); DIR *dp = opendir(b_path); if (dp == NULL) { @@ -355,8 +367,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) int dircount = 0; while ((entry = readdir(dp)) && dircount < MAX_DIRS) { - if (strncmp(entry->d_name, b_name, b_name_len) == 0 - && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) { + if (is_partial_match(entry->d_name, b_name, b_name_len)) { snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name); ++dircount; } diff --git a/src/avatars.c b/src/avatars.c index d20f561ac..428e62a67 100644 --- a/src/avatars.c +++ b/src/avatars.c @@ -39,6 +39,37 @@ static struct Avatar { off_t size; } Avatar; +/* Compares the first size bytes of fp to signature. + * + * Returns 0 if they are the same + * Returns 1 if they differ + * Returns -1 on error. + * + * On success this function will seek back to the beginning of fp. + */ +static int check_file_signature(const unsigned char *signature, size_t size, FILE *fp) +{ + char *buf = malloc(size); + + if (buf == NULL) { + return -1; + } + + if (fread(buf, size, 1, fp) != 1) { + free(buf); + return -1; + } + + int ret = memcmp(signature, buf, size); + + free(buf); + + if (fseek(fp, 0L, SEEK_SET) == -1) { + return -1; + } + + return ret == 0 ? 0 : 1; +} static void avatar_clear(void) { diff --git a/src/bootstrap.c b/src/bootstrap.c index fd8565cf9..10cedaba0 100644 --- a/src/bootstrap.c +++ b/src/bootstrap.c @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include @@ -105,6 +108,37 @@ static struct DHT_Nodes { time_t last_updated; } Nodes; +/* Return true if address appears to be a valid ipv4 address. */ +static bool is_ip4_address(const char *address) +{ + struct sockaddr_in s_addr; + return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0; +} + +/* Return true if address roughly appears to be a valid ipv6 address. + * + * TODO: Improve this function (inet_pton behaves strangely with ipv6). + * for now the only guarantee is that it won't return true if the + * address is a domain or ipv4 address, and should only be used if you're + * reasonably sure that the address is one of the three (ipv4, ipv6 or a domain). + */ +static bool is_ip6_address(const char *address) +{ + size_t num_colons = 0; + char ch = 0; + + for (size_t i = 0; (ch = address[i]); ++i) { + if (ch == '.') { + return false; + } + + if (ch == ':') { + ++num_colons; + } + } + + return num_colons > 1 && num_colons < 8; +} /* Determine if a node is offline by comparing the age of the nodeslist * to the last time the node was successfully pinged. diff --git a/src/misc_tools.c b/src/misc_tools.c index 956e9e2c8..6d756d662 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -25,10 +25,6 @@ #include #include #include -#include -#include -#include -#include #include #include "toxic.h" @@ -59,7 +55,6 @@ void hst_to_net(uint8_t *num, uint16_t numbytes) } memcpy(num, buff, numbytes); - free(buff); #endif } @@ -146,11 +141,10 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr) return -1; } - int i, res; const char *pos = keystr; - for (i = 0; i < size; ++i) { - res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]); + for (size_t i = 0; i < size; ++i) { + int res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]); pos += 2; if (res == EOF || res < 1) { @@ -172,9 +166,7 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_ return -1; } - size_t i; - - for (i = 0; i < TOX_ADDRESS_SIZE; ++i) { + for (size_t i = 0; i < TOX_ADDRESS_SIZE; ++i) { snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff); } @@ -245,43 +237,59 @@ int qsort_ptr_char_array_helper(const void *str1, const void *str2) return strcasecmp(*(char **)str1, *(char **)str2); } -/* Returns 1 if nick is valid, 0 if not. A valid toxic nick: - - cannot be empty - - cannot start with a space - - must not contain a forward slash (for logfile naming purposes) - - must not contain contiguous spaces - - must not contain a newline or tab seqeunce */ -int valid_nick(const char *nick) +static const char invalid_chars[] = {'/', '\n', '\t', '\v', '\r', '\0'}; + +/* + * Helper function for `valid_nick()`. + * + * Returns true if `ch` is not in the `invalid_chars` array. + */ +static bool is_valid_char(char ch) { - if (!nick[0] || nick[0] == ' ') { - return 0; + char tmp; + + for (size_t i = 0; (tmp = invalid_chars[i]); ++i) { + if (tmp == ch) { + return false; + } } - int i; + return true; +} - for (i = 0; nick[i]; ++i) { - if ((nick[i] == ' ' && nick[i + 1] == ' ') - || nick[i] == '/' - || nick[i] == '\n' - || nick[i] == '\t' - || nick[i] == '\v' - || nick[i] == '\r') +/* Returns true if nick is valid. + * + * A valid toxic nick: + * - cannot be empty + * - cannot start with a space + * - must not contain a forward slash (for logfile naming purposes) + * - must not contain contiguous spaces + * - must not contain a newline or tab seqeunce + */ +bool valid_nick(const char *nick) +{ + if (!nick[0] || nick[0] == ' ') { + return false; + } + + for (size_t i = 0; nick[i]; ++i) { + char ch = nick[i]; - { - return 0; + if ((ch == ' ' && nick[i + 1] == ' ') || !is_valid_char(ch)) { + return false; } } - return 1; + return true; } /* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */ void filter_str(char *str, size_t len) { - size_t i; + for (size_t i = 0; i < len; ++i) { + char ch = str[i]; - for (i = 0; i < len; ++i) { - if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0') { + if (!is_valid_char(ch) || str[i] == '\0') { str[i] = ' '; } } @@ -535,38 +543,6 @@ off_t file_size(const char *path) return st.st_size; } -/* Compares the first size bytes of fp to signature. - * - * Returns 0 if they are the same - * Returns 1 if they differ - * Returns -1 on error. - * - * On success this function will seek back to the beginning of fp. - */ -int check_file_signature(const unsigned char *signature, size_t size, FILE *fp) -{ - char *buf = malloc(size); - - if (buf == NULL) { - return -1; - } - - if (fread(buf, size, 1, fp) != 1) { - free(buf); - return -1; - } - - int ret = memcmp(signature, buf, size); - - free(buf); - - if (fseek(fp, 0L, SEEK_SET) == -1) { - return -1; - } - - return ret == 0 ? 0 : 1; -} - /* sets window title in tab bar. */ void set_window_title(ToxWindow *self, const char *title, int len) { @@ -590,39 +566,6 @@ void set_window_title(ToxWindow *self, const char *title, int len) snprintf(self->name, sizeof(self->name), "%s", cpy); } -/* Return true if address appears to be a valid ipv4 address. */ -bool is_ip4_address(const char *address) -{ - struct sockaddr_in s_addr; - return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0; -} - -/* Return true if address roughly appears to be a valid ipv6 address. - * - * TODO: Improve this function (inet_pton behaves strangely with ipv6). - * for now the only guarantee is that it won't return true if the - * address is a domain or ipv4 address, and should only be used if you're - * reasonably sure that the address is one of the three (ipv4, ipv6 or a domain). - */ -bool is_ip6_address(const char *address) -{ - size_t i; - size_t num_colons = 0; - char ch = 0; - - for (i = 0; (ch = address[i]); ++i) { - if (ch == '.') { - return false; - } - - if (ch == ':') { - ++num_colons; - } - } - - return num_colons > 1 && num_colons < 8; -} - /* * Frees all members of a pointer array plus `arr`. */ diff --git a/src/misc_tools.h b/src/misc_tools.h index dc5e42c00..ea99b3f93 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -110,13 +110,16 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2); /* case-insensitive string compare function for use with qsort */ int qsort_ptr_char_array_helper(const void *str1, const void *str2); -/* Returns 1 if nick is valid, 0 if not. A valid toxic nick: - - cannot be empty - - cannot start with a space - - must not contain a forward slash (for logfile naming purposes) - - must not contain contiguous spaces - - must not contain a newline or tab seqeunce */ -int valid_nick(const char *nick); +/* Returns true if nick is valid. + * + * A valid toxic nick: + * - cannot be empty + * - cannot start with a space + * - must not contain a forward slash (for logfile naming purposes) + * - must not contain contiguous spaces + * - must not contain a newline or tab seqeunce + */ +bool valid_nick(const char *nick); /* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */ void filter_str(char *str, size_t len); @@ -172,32 +175,9 @@ File_Type file_type(const char *path); /* returns file size. If file doesn't exist returns 0. */ off_t file_size(const char *path); -/* Compares the first size bytes of fp to signature. - * - * Returns 0 if they are the same - * Returns 1 if they differ - * Returns -1 on error. - * - * On success this function will seek back to the beginning of fp. - */ -int check_file_signature(const unsigned char *signature, size_t size, FILE *fp); - /* sets window title in tab bar. */ void set_window_title(ToxWindow *self, const char *title, int len); -/* Return true if address appears to be a valid ipv4 address. */ -bool is_ip4_address(const char *address); - -/* Return true if address roughly appears to be a valid ipv6 address. - * - * TODO: Improve this function (inet_pton behaves strangely with ipv6). - * for now the only guarantee is that it won't return true if the - * address is a domain or ipv4 address, and should only be used if you're - * reasonably sure that the address is one of the three (ipv4, ipv6 or a domain). - */ -bool is_ip6_address(const char *address); - - /* * Frees all members of a pointer array plus `arr`. */ diff --git a/src/toxic.c b/src/toxic.c index d815023a9..2e5c44272 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -742,7 +742,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (len == 0) { fclose(fp); exit_toxic_err("failed in load_tox", FATALERR_FILEOP); - return NULL; } char *data = malloc(len); @@ -750,14 +749,12 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (data == NULL) { fclose(fp); exit_toxic_err("failed in load_tox", FATALERR_MEMORY); - return NULL; } if (fread(data, len, 1, fp) != 1) { fclose(fp); free(data); exit_toxic_err("failed in load_tox", FATALERR_FILEOP); - return NULL; } bool is_encrypted = tox_is_data_encrypted((uint8_t *) data); @@ -767,7 +764,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New fclose(fp); free(data); exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT); - return NULL; } if (arg_opts.unencrypt_data && is_encrypted) { @@ -796,7 +792,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New fclose(fp); free(data); exit_toxic_err("failed in load_tox", FATALERR_MEMORY); - return NULL; } while (true) { @@ -853,7 +848,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New free(data); free(plain); exit_toxic_err("tox_pass_decrypt() failed", pwerr); - return NULL; } } @@ -876,7 +870,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New } else { /* Data file does not/should not exist */ if (file_exists(data_path)) { exit_toxic_err("failed in load_tox", FATALERR_FILEOP); - return NULL; } tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_NONE); @@ -889,7 +882,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New if (store_data(m, data_path) == -1) { exit_toxic_err("failed in load_tox", FATALERR_FILEOP); - return NULL; } }