From 9feff00eade08b2461fcc76be4c3c9db46f14cc8 Mon Sep 17 00:00:00 2001 From: "jabber.developer2" Date: Mon, 27 Apr 2026 15:03:52 +0300 Subject: [PATCH] refactor: clean narrowing conversions and harden unsigned arithmetic Cleanup of the conversion-safety warnings exposed by enabling -Wconversion / -Wsign-compare in the previous commit, plus guard clauses at the few places where unsigned arithmetic could actually misbehave. Build: - configure.ac drops -Wno-error=conversion and -Wno-error=float-conversion. Only -Wno-error=sign-conversion and -Wno-error=sign-compare remain, gating the ~230 sign warnings inherited from upstream that will be cleaned up in follow-ups. Type / conversion fixes (no behaviour change): - Length-like locals in command/cmd_ac.c, command/cmd_funcs.c, pgp/gpg.c, tools/autocomplete.c, tools/parser.c and ui/mucwin.c switched from int to size_t / glong (matching strlen / g_utf8_strlen return type) so we no longer need an (int) cast and loop counters / array sizes stay in their natural unsigned domain. - g_timer_elapsed / GTimeSpan -> int casts in session.c, iq.c, core.c, server_events.c, window.c. - _win_print_wrapped: indent parameter and local curx/maxx switched from size_t to int to match _win_indent / getcurx / getmaxx. - Port casts (int -> unsigned short) at the libstrophe boundary in connection.c and session.c, each preceded by g_assert(port >= 0 && port <= UINT16_MAX) so the truncation is documented at the call-site. - curl_off_t / fread size_t results cast at usage in http_upload.c, http_download.c, omemo/crypto.c. - strtoul results cast to uint32_t in xmpp/omemo.c and omemo/omemo.c where device/prekey IDs are genuinely 32-bit. - config/color.c: fg/bg/palette indices switched to `short` end-to-end (find_col, color_hash, find_closest_col, _color_pair_cache_get, cache.pairs), so the ncurses init_pair boundary needs at most one (short)i cast for the cache index. Also TODO-noted: init_extended_pair is needed for >15-bit palettes. - xmpp/avatar.c: float arithmetic explicitly casts its int operands. - tests/functionaltests/proftest.c: read() result handling uses size_t for the accumulator, _read_output returns ssize_t, and the buffer-shift check happens before space subtraction so the expression cannot underflow. Real-risk guard clauses (the part that actually fixes bugs): - src/ui/statusbar.c _tabs_width: `end > opened_tabs - 1` rewritten as `end < opened_tabs` so opened_tabs == 0 no longer underflows. - src/ui/statusbar.c _status_bar_draw_extended_tabs: the mirror comparison rewritten as `end >= opened_tabs`. - src/ui/statusbar.c status_bar_draw: replaced `MAX(0, getmaxx - (int)_tabs_width)` with an explicit precheck before subtraction. - src/omemo/omemo.c prekey selection: prekey_index is now uint32_t and randomized into an unsigned buffer, so modulo with prekeys_len cannot yield a negative index for g_list_nth_data. - src/omemo/crypto.c omemo_decrypt_func: PKCS#5/PKCS#7 unpadding reads `plaintext[plaintext_len - 1]`, which would underflow on a malformed empty ciphertext and read past the heap buffer. Reject plaintext_len == 0 before the padding peek and validate the padding byte against the buffer length before the unpad loop. Initialise plaintext = NULL so the early `goto out` cannot free uninitialised memory. - src/ui/inputwin.c (4 mbrlen sites) and src/ui/window.c _win_print_wrapped: mbrlen() returns 0 for the null wide character. The existing checks rejected (size_t)-1 / -2 but treated 0 as a valid step, so the surrounding loops would either advance by SIZE_MAX (i += ch_len - 1) or spin in place (word_pos += 0 forever). Add `|| ch_len == 0` to each guard; inside the spell-check word-emission loop also fall back to a one-byte advance. - Defensive `len > 0 ? len - 1 : 0` prechecks at the strlen-based g_strndup / loop sites in ui/console.c, plugins/c_api.c and plugins/python_plugins.c. --- configure.ac | 11 ++++---- src/command/cmd_ac.c | 4 +-- src/command/cmd_funcs.c | 8 +++--- src/config/color.c | 43 +++++++++++++++++++------------- src/event/server_events.c | 2 +- src/omemo/crypto.c | 21 +++++++++++++--- src/omemo/omemo.c | 27 +++++++++++--------- src/pgp/gpg.c | 4 +-- src/plugins/c_api.c | 3 ++- src/plugins/python_plugins.c | 9 ++++--- src/tools/autocomplete.c | 6 ++--- src/tools/http_download.c | 2 +- src/tools/http_upload.c | 2 +- src/tools/parser.c | 16 ++++++------ src/ui/console.c | 9 ++++--- src/ui/core.c | 2 +- src/ui/inputwin.c | 25 ++++++++++++++----- src/ui/mucwin.c | 10 ++++---- src/ui/statusbar.c | 17 +++++++++---- src/ui/titlebar.c | 4 +-- src/ui/window.c | 33 ++++++++++++------------ src/xmpp/avatar.c | 4 +-- src/xmpp/connection.c | 11 +++++--- src/xmpp/iq.c | 8 +++--- src/xmpp/message.c | 2 +- src/xmpp/omemo.c | 10 ++++---- src/xmpp/session.c | 11 ++++---- tests/functionaltests/proftest.c | 22 ++++++++-------- 28 files changed, 193 insertions(+), 133 deletions(-) diff --git a/configure.ac b/configure.ac index 2b5d770a..35adddb4 100644 --- a/configure.ac +++ b/configure.ac @@ -436,11 +436,12 @@ AS_IF([test "x$enable_sanitizers" = xyes], AS_IF([test "x$PACKAGE_STATUS" = xdevelopment], [AM_CFLAGS="$AM_CFLAGS -Wunused -Werror" - # -Wconversion emits ~240 sign-conversion and ~84 other narrowing - # warnings across the tree (mostly inherited from upstream). Keep - # them visible in build logs but let development builds continue; - # they will be cleaned up incrementally. - AM_CFLAGS="$AM_CFLAGS -Wno-error=sign-conversion -Wno-error=conversion -Wno-error=float-conversion -Wno-error=sign-compare"]) + # -Wsign-conversion and -Wsign-compare still emit ~230 warnings + # across the tree (mostly inherited from upstream). Keep them + # visible in build logs but let development builds continue; + # the plain narrowing / float-conversion categories are already + # clean and are kept as hard errors. + AM_CFLAGS="$AM_CFLAGS -Wno-error=sign-conversion -Wno-error=sign-compare"]) AS_IF([test "x$PLATFORM" = xosx], [AM_CFLAGS="$AM_CFLAGS -Qunused-arguments"]) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 13d2fa6e..804c7bdb 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -1879,9 +1879,9 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ } } - int len = strlen(input); + size_t len = strlen(input); char parsed[len + 1]; - int i = 0; + size_t i = 0; while (i < len) { if (input[i] == ' ') { break; diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 8024d470..69f89f8b 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -1499,11 +1499,11 @@ cmd_win(ProfWin* window, const char* const command, gchar** args) static void _cmd_list_commands(GList* commands) { - int maxlen = 0; + size_t maxlen = 0; GList* curr = commands; while (curr) { gchar* cmd = curr->data; - int len = strlen(cmd); + size_t len = strlen(cmd); if (len > maxlen) maxlen = len; curr = g_list_next(curr); @@ -1520,7 +1520,7 @@ _cmd_list_commands(GList* commands) cmds = g_string_new(""); count = 0; } - g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd); + g_string_append_printf(cmds, "%-*s", (int)(maxlen + 1), cmd); curr = g_list_next(curr); count++; } @@ -3799,7 +3799,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args) break; } - int index = strtol(&value[3], NULL, 10); + int index = (int)strtol(&value[3], NULL, 10); if ((index < 1) || (index > form_get_value_count(form, tag))) { win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:"); confwin_field_help(confwin, tag); diff --git a/src/config/color.c b/src/config/color.c index b66fcfbe..e74629cd 100644 --- a/src/config/color.c +++ b/src/config/color.c @@ -33,7 +33,7 @@ static struct color_pair_cache { struct { - int16_t fg, bg; + short fg, bg; }* pairs; int size; int capacity; @@ -315,14 +315,18 @@ color_distance(const struct color_def* a, const struct color_def* b) return h * h + s * s + l * l; } -static int +/* Indices into the 256-colour palette and ncurses palette IDs are + * 16-bit (the size_t-or-short distinction in ncurses init_pair). + * Use `short` end-to-end so the caller boundaries don't need casts. + */ +static short find_closest_col(int h, int s, int l) { - struct color_def a = { h, s, l, NULL }; - int min = 0; + struct color_def a = { (uint16_t)h, (uint8_t)s, (uint8_t)l, NULL }; + short min = 0; int dmin = color_distance(&a, &color_names[0]); - for (int i = 1; i < COLOR_NAME_SIZE; i++) { + for (short i = 1; i < COLOR_NAME_SIZE; i++) { int d = color_distance(&a, &color_names[i]); if (d < dmin) { dmin = d; @@ -332,8 +336,8 @@ find_closest_col(int h, int s, int l) return min; } -static int -find_col(const char* col_name, int n) +static short +find_col(const char* col_name, size_t n) { char name[32] = { 0 }; @@ -343,9 +347,9 @@ find_col(const char* col_name, int n) * blue. */ - if (n >= (int)sizeof(name)) { + if (n >= sizeof(name)) { /* truncate */ - log_error("Color: <%s,%d> bigger than %zu", col_name, n, sizeof(name)); + log_error("Color: <%s,%zu> bigger than %zu", col_name, n, sizeof(name)); n = sizeof(name) - 1; } memcpy(name, col_name, n); @@ -354,7 +358,7 @@ find_col(const char* col_name, int n) return -1; } - for (int i = 0; i < COLOR_NAME_SIZE; i++) { + for (short i = 0; i < COLOR_NAME_SIZE; i++) { if (g_ascii_strcasecmp(name, color_names[i].name) == 0) { return i; } @@ -363,13 +367,13 @@ find_col(const char* col_name, int n) return COL_ERR; } -static int +static short color_hash(const char* str, color_profile profile) { GChecksum* cs = NULL; guint8 buf[256] = { 0 }; gsize len = 256; - int rc = -1; /* default ncurse color */ + short rc = -1; /* default ncurse color */ cs = g_checksum_new(G_CHECKSUM_SHA1); if (!cs) @@ -438,7 +442,7 @@ color_pair_cache_reset(void) } static int -_color_pair_cache_get(int fg, int bg) +_color_pair_cache_get(short fg, short bg) { if (COLORS < 256) { if (fg > 7 || bg > 7) { @@ -463,10 +467,13 @@ _color_pair_cache_get(int fg, int bg) } int i = cache.size; + // TODO: init_pair uses 15-bit palette indices. Terminals exposing + // extended colour palettes (>32767) need init_extended_pair here. + // Upstream-inherited limitation. cache.pairs[i].fg = fg; cache.pairs[i].bg = bg; /* (re-)define the new pair in curses */ - init_pair(i, fg, bg); + init_pair((short)i, fg, bg); cache.size++; @@ -485,8 +492,8 @@ _color_pair_cache_get(int fg, int bg) int color_pair_cache_hash_str(const char* str, color_profile profile) { - int fg = color_hash(str, profile); - int bg = -1; + short fg = color_hash(str, profile); + short bg = -1; auto_char char* bkgnd = theme_get_bkgnd(); if (bkgnd) { @@ -506,7 +513,7 @@ int color_pair_cache_get(const char* pair_name) { const char* sep; - int fg, bg; + short fg, bg; sep = strchr(pair_name, '_'); if (!sep) { @@ -514,7 +521,7 @@ color_pair_cache_get(const char* pair_name) return -1; } - fg = find_col(pair_name, sep - pair_name); + fg = find_col(pair_name, (size_t)(sep - pair_name)); bg = find_col(sep + 1, strlen(sep)); if (fg == COL_ERR || bg == COL_ERR) { log_error("Color: bad color name %s", pair_name); diff --git a/src/event/server_events.c b/src/event/server_events.c index c5d00f50..83fea6f3 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -154,7 +154,7 @@ sv_ev_roster_received(void) GDateTime* lastdt = g_date_time_new_from_timeval_utc(&lasttv); GTimeSpan diff_micros = g_date_time_difference(nowdt, lastdt); - diff_secs = (diff_micros / 1000) / 1000; + diff_secs = (int)((diff_micros / 1000) / 1000); g_date_time_unref(lastdt); } g_date_time_unref(nowdt); diff --git a/src/omemo/crypto.c b/src/omemo/crypto.c index 66a0bcfe..daca6824 100644 --- a/src/omemo/crypto.c +++ b/src/omemo/crypto.c @@ -233,7 +233,7 @@ omemo_decrypt_func(signal_buffer** output, int cipher, const uint8_t* key, size_ { int ret = SG_SUCCESS; gcry_cipher_hd_t hd; - unsigned char* plaintext; + unsigned char* plaintext = NULL; size_t plaintext_len; int mode; int algo; @@ -268,6 +268,13 @@ omemo_decrypt_func(signal_buffer** output, int cipher, const uint8_t* key, size_ } plaintext_len = ciphertext_len; + // PKCS#5/PKCS#7 padding requires at least one byte of plaintext; + // reject malformed empty ciphertext before any plaintext[len - 1] + // access could underflow / read out-of-bounds. + if (plaintext_len == 0) { + ret = SG_ERR_INVAL; + goto out; + } plaintext = malloc(plaintext_len); gcry_cipher_decrypt(hd, plaintext, plaintext_len, ciphertext, ciphertext_len); @@ -279,6 +286,12 @@ omemo_decrypt_func(signal_buffer** output, int cipher, const uint8_t* key, size_ assert(FALSE); } + // padding byte must address bytes that exist in plaintext. + if (padding == 0 || (size_t)padding > plaintext_len) { + ret = SG_ERR_UNKNOWN; + goto out; + } + for (int i = 0; i < padding; i++) { if (plaintext[plaintext_len - 1 - i] != padding) { ret = SG_ERR_UNKNOWN; @@ -401,7 +414,7 @@ aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size, unsigned char buffer[AES256_GCM_BUFFER_SIZE]; - int bytes = 0; + size_t bytes = 0; off_t bytes_read = 0, bytes_available = 0, read_size = 0; while (bytes_read < file_size) { bytes_available = file_size - bytes_read; @@ -416,8 +429,8 @@ aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size, read_size = AES256_GCM_BUFFER_SIZE; } - bytes = fread(buffer, 1, read_size, in); - bytes_read += bytes; + bytes = fread(buffer, 1, (size_t)read_size, in); + bytes_read += (off_t)bytes; if (encrypt) { res = gcry_cipher_encrypt(hd, buffer, bytes, NULL, 0); diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index b693473b..657266c9 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -708,14 +708,17 @@ omemo_start_device_session(const char* const jid, uint32_t device_id, goto out; } - int prekey_index; + uint32_t prekey_index; size_t prekeys_len = g_list_length(prekeys); if (prekeys_len == 0) { log_error("[OMEMO] No prekeys found for %s device %d", jid, device_id); goto out; } - gcry_randomize(&prekey_index, sizeof(int), GCRY_STRONG_RANDOM); - prekey_index %= prekeys_len; + // Use an unsigned type so the modulo below is unsigned and cannot + // produce a negative index (gcry_randomize writes random bytes, + // including the sign bit of a signed int). + gcry_randomize(&prekey_index, sizeof(prekey_index), GCRY_STRONG_RANDOM); + prekey_index %= (uint32_t)prekeys_len; omemo_key_t* prekey = g_list_nth_data(prekeys, prekey_index); curve_decode_point(&prekey_public, prekey->data, prekey->length, omemo_ctx.signal); @@ -1453,8 +1456,8 @@ _omemo_fingerprint_decode(const char* const fingerprint, size_t* len) continue; } - output[j] = g_ascii_xdigit_value(fingerprint[i++]) << 4; - output[j] |= g_ascii_xdigit_value(fingerprint[i++]); + output[j] = (unsigned char)(g_ascii_xdigit_value(fingerprint[i++]) << 4); + output[j] |= (unsigned char)g_ascii_xdigit_value(fingerprint[i++]); j++; } @@ -1744,7 +1747,7 @@ _load_identity(void) log_info("[OMEMO] Loading OMEMO identity"); /* Device ID */ - omemo_ctx.device_id = g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, &error); + omemo_ctx.device_id = (uint32_t)g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, &error); if (error != NULL) { log_error("[OMEMO] cannot load device id: %s", error->message); return FALSE; @@ -1752,7 +1755,7 @@ _load_identity(void) log_debug("[OMEMO] device id: %d", omemo_ctx.device_id); /* Registration ID */ - omemo_ctx.registration_id = g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, &error); + omemo_ctx.registration_id = (uint32_t)g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, &error); if (error != NULL) { log_error("[OMEMO] cannot load registration id: %s", error->message); return FALSE; @@ -1793,7 +1796,7 @@ _load_identity(void) keys = g_key_file_get_keys(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_PREKEYS, NULL, NULL); if (keys) { for (i = 0; keys[i] != NULL; i++) { - uint32_t id = strtoul(keys[i], NULL, 10); + uint32_t id = (uint32_t)strtoul(keys[i], NULL, 10); if (id > omemo_ctx.max_pre_key_id) { omemo_ctx.max_pre_key_id = id; } @@ -1822,7 +1825,7 @@ _load_identity(void) auto_guchar guchar* signed_pre_key = g_base64_decode(signed_pre_key_b64, &signed_pre_key_len); signal_buffer* buffer = signal_buffer_create(signed_pre_key, signed_pre_key_len); g_hash_table_insert(omemo_ctx.signed_pre_key_store, GINT_TO_POINTER(strtoul(keys[i], NULL, 10)), buffer); - omemo_ctx.signed_pre_key_id = strtoul(keys[i], NULL, 10); + omemo_ctx.signed_pre_key_id = (uint32_t)strtoul(keys[i], NULL, 10); } g_strfreev(keys); } @@ -1863,7 +1866,7 @@ _load_trust(void) size_t key_len; auto_guchar guchar* key = g_base64_decode(key_b64, &key_len); signal_buffer* buffer = signal_buffer_create(key, key_len); - uint32_t device_id = strtoul(keys[j], NULL, 10); + uint32_t device_id = (uint32_t)strtoul(keys[j], NULL, 10); g_hash_table_insert(trusted, GINT_TO_POINTER(device_id), buffer); } } @@ -1889,7 +1892,7 @@ _load_sessions(void) auto_gcharv gchar** keys = g_key_file_get_keys(omemo_ctx.sessions.keyfile, groups[i], NULL, NULL); for (int j = 0; keys[j] != NULL; j++) { - uint32_t id = strtoul(keys[j], NULL, 10); + uint32_t id = (uint32_t)strtoul(keys[j], NULL, 10); auto_gchar gchar* record_b64 = g_key_file_get_string(omemo_ctx.sessions.keyfile, groups[i], keys[j], NULL); size_t record_len; auto_guchar guchar* record = g_base64_decode(record_b64, &record_len); @@ -1919,7 +1922,7 @@ _load_known_devices(void) auto_gcharv gchar** keys = g_key_file_get_keys(omemo_ctx.knowndevices.keyfile, groups[i], NULL, NULL); for (int j = 0; keys[j] != NULL; j++) { - uint32_t device_id = strtoul(keys[j], NULL, 10); + uint32_t device_id = (uint32_t)strtoul(keys[j], NULL, 10); auto_gchar gchar* fingerprint = g_key_file_get_string(omemo_ctx.knowndevices.keyfile, groups[i], keys[j], NULL); g_hash_table_insert(known_identities, strdup(fingerprint), GINT_TO_POINTER(device_id)); } diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c index c32d16d2..ee9d11f6 100644 --- a/src/pgp/gpg.c +++ b/src/pgp/gpg.c @@ -687,8 +687,8 @@ p_gpg_format_fp_str(gchar* fp) } GString* format = g_string_new(""); - int len = strlen(fp); - for (int i = 0; i < len; i++) { + size_t len = strlen(fp); + for (size_t i = 0; i < len; i++) { g_string_append_c(format, fp[i]); if (((i + 1) % 4 == 0) && (i + 1 < len)) { g_string_append_c(format, ' '); diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 5bf8bf11..9949c92a 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -506,7 +506,8 @@ c_api_init(void) static char* _c_plugin_name(const char* filename) { - auto_gchar gchar* name = g_strndup(filename, strlen(filename) - 1); + size_t flen = strlen(filename); + auto_gchar gchar* name = g_strndup(filename, flen > 0 ? flen - 1 : 0); gchar* result = g_strdup_printf("%sso", name); return result; diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 533fb0d1..800b59f8 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -94,7 +94,8 @@ python_plugin_create(const char* const filename) if (p_module) { p_module = PyImport_ReloadModule(p_module); } else { - gchar* module_name = g_strndup(filename, strlen(filename) - 3); + size_t flen = strlen(filename); + gchar* module_name = g_strndup(filename, flen > 3 ? flen - 3 : 0); p_module = PyImport_ImportModule(module_name); if (p_module) { g_hash_table_insert(loaded_modules, strdup(filename), p_module); @@ -856,7 +857,8 @@ static void _python_undefined_error(ProfPlugin* plugin, char* hook, char* type) { GString* err_msg = g_string_new("Plugin error - "); - auto_gchar gchar* module_name = g_strndup(plugin->name, strlen(plugin->name) - 2); + size_t nlen = strlen(plugin->name); + auto_gchar gchar* module_name = g_strndup(plugin->name, nlen > 2 ? nlen - 2 : 0); g_string_append(err_msg, module_name); g_string_append(err_msg, hook); g_string_append(err_msg, "(): return value undefined, expected "); @@ -870,7 +872,8 @@ static void _python_type_error(ProfPlugin* plugin, char* hook, char* type) { GString* err_msg = g_string_new("Plugin error - "); - auto_gchar gchar* module_name = g_strndup(plugin->name, strlen(plugin->name) - 2); + size_t nlen = strlen(plugin->name); + auto_gchar gchar* module_name = g_strndup(plugin->name, nlen > 2 ? nlen - 2 : 0); g_string_append(err_msg, module_name); g_string_append(err_msg, hook); g_string_append(err_msg, "(): incorrect return type, expected "); diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index c99545fa..10ed8c70 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -290,7 +290,7 @@ autocomplete_complete(Autocomplete ac, const gchar* search_str, gboolean quote, static char* _autocomplete_param_common(const char* const input, char* command, autocomplete_func func, Autocomplete ac, gboolean quote, gboolean previous, void* context) { - int len; + size_t len; auto_gchar gchar* command_cpy = g_strdup_printf("%s ", command); if (!command_cpy) { return NULL; @@ -299,14 +299,14 @@ _autocomplete_param_common(const char* const input, char* command, autocomplete_ len = strlen(command_cpy); if (strncmp(input, command_cpy, len) == 0) { - int inp_len = strlen(input); + size_t inp_len = strlen(input); auto_char char* found = NULL; auto_char char* prefix = malloc(inp_len + 1); if (!prefix) { return NULL; } - for (int i = len; i < inp_len; i++) { + for (size_t i = len; i < inp_len; i++) { prefix[i - len] = input[i]; } diff --git a/src/tools/http_download.c b/src/tools/http_download.c index bc561233..8c45c8b6 100644 --- a/src/tools/http_download.c +++ b/src/tools/http_download.c @@ -54,7 +54,7 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot unsigned int dlperc = 0; if (dltotal != 0) { - dlperc = (100 * dlnow) / dltotal; + dlperc = (unsigned int)((100 * dlnow) / dltotal); } if (!download->silent) { diff --git a/src/tools/http_upload.c b/src/tools/http_upload.c index 6c068e14..9d67699a 100644 --- a/src/tools/http_upload.c +++ b/src/tools/http_upload.c @@ -62,7 +62,7 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot unsigned int ulperc = 0; if (ultotal != 0) { - ulperc = (100 * ulnow) / ultotal; + ulperc = (unsigned int)((100 * ulnow) / ultotal); } gchar* msg = NULL; diff --git a/src/tools/parser.c b/src/tools/parser.c index ab5c77cb..a2127c4c 100644 --- a/src/tools/parser.c +++ b/src/tools/parser.c @@ -28,7 +28,7 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb auto_char char* copy = strdup(inp); g_strstrip(copy); - int inp_size = g_utf8_strlen(copy, -1); + glong inp_size = g_utf8_strlen(copy, -1); gboolean in_token = FALSE; gboolean in_freetext = FALSE; gboolean in_quotes = FALSE; @@ -37,7 +37,7 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb GSList* tokens = NULL; // add tokens to GSList - for (int i = 0; i < inp_size; i++) { + for (glong i = 0; i < inp_size; i++) { gchar* curr_ch = g_utf8_offset_to_pointer(copy, i); gunichar curr_uni = g_utf8_get_char(curr_ch); @@ -231,10 +231,10 @@ gchar** parse_args_as_one(const char* const inp, int min, int max, gboolean* result) { gchar** args = g_malloc0(2 * sizeof(*args)); - int length = g_utf8_strlen(inp, -1); + glong length = g_utf8_strlen(inp, -1); gchar* space = g_utf8_strchr(inp, length, ' '); if (space) { - int sub_length = g_utf8_strlen(space, -1); + glong sub_length = g_utf8_strlen(space, -1); if (sub_length > 1) { args[0] = g_strdup(space + 1); *result = TRUE; @@ -253,14 +253,14 @@ parse_args_as_one(const char* const inp, int min, int max, gboolean* result) int count_tokens(const char* const string) { - int length = g_utf8_strlen(string, -1); + glong length = g_utf8_strlen(string, -1); gboolean in_quotes = FALSE; int num_tokens = 0; // include first token num_tokens++; - for (int i = 0; i < length; i++) { + for (glong i = 0; i < length; i++) { gchar* curr_ch = g_utf8_offset_to_pointer(string, i); gunichar curr_uni = g_utf8_get_char(curr_ch); @@ -298,14 +298,14 @@ char* get_start(const char* const string, int tokens) { GString* result = g_string_new(""); - int length = g_utf8_strlen(string, -1); + glong length = g_utf8_strlen(string, -1); gboolean in_quotes = FALSE; int num_tokens = 0; // include first token num_tokens++; - for (int i = 0; i < length; i++) { + for (glong i = 0; i < length; i++) { gchar* curr_ch = g_utf8_offset_to_pointer(string, i); gunichar curr_uni = g_utf8_get_char(curr_ch); diff --git a/src/ui/console.c b/src/ui/console.c index 59cad5c0..f44260b3 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -92,8 +92,11 @@ cons_show_help(const char* const cmd, CommandHelp* help) win_println(console, THEME_HELP_HEADER, "-", "%s", &cmd[1]); win_print(console, THEME_HELP_HEADER, "-", ""); size_t i; - for (i = 0; i < strlen(cmd) - 1; i++) { - win_append(console, THEME_HELP_HEADER, "-"); + size_t cmd_len = strlen(cmd); + if (cmd_len > 0) { + for (i = 0; i < cmd_len - 1; i++) { + win_append(console, THEME_HELP_HEADER, "-"); + } } win_appendln(console, THEME_HELP_HEADER, ""); cons_show(""); @@ -115,7 +118,7 @@ cons_show_help(const char* const cmd, CommandHelp* help) cons_show(""); win_println(console, THEME_HELP_HEADER, "-", "Arguments"); for (i = 0; help->args[i][0] != NULL; i++) { - win_println_indent(console, maxlen + 3, "%-*s: %s", (int)(maxlen + 1), help->args[i][0], help->args[i][1]); + win_println_indent(console, (int)(maxlen + 3), "%-*s: %s", (int)(maxlen + 1), help->args[i][0], help->args[i][1]); } } diff --git a/src/ui/core.c b/src/ui/core.c index 4c0d0739..f755cfa9 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -166,7 +166,7 @@ ui_get_idle_time(void) // if no libxss or xss idle time failed, use profanity idle time #endif gdouble seconds_elapsed = g_timer_elapsed(ui_idle_time, NULL); - unsigned long ms_elapsed = seconds_elapsed * 1000.0; + unsigned long ms_elapsed = (unsigned long)(seconds_elapsed * 1000.0); return ms_elapsed; } diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index e1102a67..c9c4aef8 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -385,7 +385,10 @@ _inp_write(char* line, int offset) char retc[PROF_MB_CUR_MAX] = { 0 }; size_t ch_len = mbrlen(c, MB_CUR_MAX, NULL); - if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) { + // ch_len == 0 means mbrlen consumed the null wide character; + // skipping it here keeps `i += ch_len - 1` below from + // underflowing to SIZE_MAX. + if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) { waddch(inp_win, ' '); continue; } @@ -409,7 +412,9 @@ _inp_write(char* line, int offset) size_t end = start + ch_len; while (line[end] != '\0') { size_t next_ch_len = mbrlen(&line[end], MB_CUR_MAX, NULL); - if (next_ch_len == (size_t)-2 || next_ch_len == (size_t)-1) + // ch_len == 0 means embedded NUL — stop, otherwise + // `end += next_ch_len` loops forever. + if (next_ch_len == (size_t)-2 || next_ch_len == (size_t)-1 || next_ch_len == 0) break; gunichar next_uc = g_utf8_get_char(&line[end]); if (!g_unichar_isalnum(next_uc) && next_uc != '\'') @@ -428,7 +433,13 @@ _inp_write(char* line, int offset) size_t word_pos = start; while (word_pos < end) { size_t cur_ch_len = mbrlen(&line[word_pos], MB_CUR_MAX, NULL); - waddnstr(inp_win, &line[word_pos], cur_ch_len); + // Defensive: invalid or zero-length step would loop + // forever; advance one byte and continue. + if (cur_ch_len == (size_t)-2 || cur_ch_len == (size_t)-1 || cur_ch_len == 0) { + word_pos++; + continue; + } + waddnstr(inp_win, &line[word_pos], (int)cur_ch_len); word_pos += cur_ch_len; } @@ -441,7 +452,7 @@ _inp_write(char* line, int offset) } } - waddnstr(inp_win, c, ch_len); + waddnstr(inp_win, c, (int)ch_len); } wmove(inp_win, 0, col); @@ -494,11 +505,13 @@ _inp_offset_to_col(char* str, int offset) while (i < offset && str[i] != '\0') { gunichar uni = g_utf8_get_char(&str[i]); size_t ch_len = mbrlen(&str[i], MB_CUR_MAX, NULL); - if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) { + // ch_len == 0 (embedded NUL) would freeze the loop on the same + // byte; treat it like an invalid step. + if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) { i++; continue; } - i += ch_len; + i += (int)ch_len; col++; if (g_unichar_iswide(uni)) { col++; diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index 3d372c21..b7944609 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -382,7 +382,7 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len); win_append_highlight(window, THEME_ROOMMENTION_TERM, "%s", mynick_str); - last_pos = pos + mynick_len; + last_pos = pos + (int)mynick_len; curr = g_slist_next(curr); } @@ -400,8 +400,8 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co gint _cmp_trigger_weight(gconstpointer a, gconstpointer b) { - int alen = strlen((char*)a); - int blen = strlen((char*)b); + size_t alen = strlen((char*)a); + size_t blen = strlen((char*)b); if (alen > blen) return -1; @@ -438,10 +438,10 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge } // found, replace vars if earlier than previous - int trigger_pos = trigger_ptr - message_lower; + int trigger_pos = (int)(trigger_ptr - message_lower); if (first_trigger_pos == -1 || trigger_pos < first_trigger_pos) { first_trigger_pos = trigger_pos; - first_trigger_len = strlen(trigger_lower); + first_trigger_len = (int)strlen(trigger_lower); } curr = g_list_next(curr); diff --git a/src/ui/statusbar.c b/src/ui/statusbar.c index 05ad5356..83def1dc 100644 --- a/src/ui/statusbar.c +++ b/src/ui/statusbar.c @@ -304,8 +304,13 @@ _status_bar_draw_tabs(guint pos) gboolean is_static = g_strcmp0(tabmode, "dynamic") != 0; _get_range_bounds(&start, &end, is_static); - // if the result of the calc is negative we take 0 - pos = MAX(0, (getmaxx(stdscr) - (int)_tabs_width(start, end))); + guint tabs_w = _tabs_width(start, end); + int max_x = getmaxx(stdscr); + if (max_x > 0 && (guint)max_x > tabs_w) { + pos = (guint)max_x - tabs_w; + } else { + pos = 0; + } pos = _status_bar_draw_extended_tabs(pos, TRUE, start, end, is_static); @@ -392,7 +397,9 @@ _status_bar_draw_extended_tabs(guint pos, gboolean prefix, guint start, guint en if (prefix && start < 2) { return pos; } - if (!prefix && end > opened_tabs - 1) { + // Guard against underflow when opened_tabs == 0 (reachable if the + // earlier `opened_tabs <= max_tabs` early-return no longer holds). + if (!prefix && end >= opened_tabs) { return pos; } gboolean is_current = is_static && statusbar->current_tab > max_tabs; @@ -504,7 +511,7 @@ _status_bar_draw_time(guint pos) int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); int time_attrs = theme_attrs(THEME_STATUS_TIME); - size_t len = strlen(statusbar->time); + guint len = (guint)strlen(statusbar->time); wattron(statusbar_win, bracket_attrs); mvwaddch(statusbar_win, 0, pos, '['); pos++; @@ -599,7 +606,7 @@ _tabs_width(guint start, guint end) guint opened_tabs = g_hash_table_size(statusbar->tabs); int width = start < 2 ? 1 : 4; - width += end > opened_tabs - 1 ? 0 : 3; + width += (end < opened_tabs) ? 3 : 0; if (show_name && show_number) { for (guint i = start; i <= end; i++) { diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index 748e35dd..93aae5a9 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -224,7 +224,7 @@ _title_bar_draw(void) auto_gchar gchar* title = win_get_title(current); mvwprintw(win, 0, 0, " %s", title); - pos = strlen(title) + 1; + pos = (int)strlen(title) + 1; // presence is written from the right side // calculate it first so we have a maxposition @@ -596,7 +596,7 @@ _show_contact_presence(ProfChatWin* chatwin, int pos, int maxpos) } if (resource && prefs_get_boolean(PREF_RESOURCE_TITLE)) { - int needed = strlen(resource) + 1; + int needed = (int)strlen(resource) + 1; if (pos + needed < maxpos) { wprintw(win, "/"); wprintw(win, "%s", resource); diff --git a/src/ui/window.c b/src/ui/window.c index 53db3745..6fb46ac1 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -75,7 +75,7 @@ static void _win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const char* const message, ...); static void _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const from, const char* const message, DeliveryReceipt* receipt); -static void _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent); +static void _win_print_wrapped(WINDOW* win, const char* const message, int indent, int pad_indent); // Helper: clamp a subwindow width to a sane range [1, cols-1] if possible static int @@ -1048,11 +1048,11 @@ win_show_contact(ProfWin* window, PContact contact) GTimeSpan span = g_date_time_difference(now, last_activity); g_date_time_unref(now); - int hours = span / G_TIME_SPAN_HOUR; + int hours = (int)(span / G_TIME_SPAN_HOUR); span = span - hours * G_TIME_SPAN_HOUR; - int minutes = span / G_TIME_SPAN_MINUTE; + int minutes = (int)(span / G_TIME_SPAN_MINUTE); span = span - minutes * G_TIME_SPAN_MINUTE; - int seconds = span / G_TIME_SPAN_SECOND; + int seconds = (int)(span / G_TIME_SPAN_SECOND); if (hours > 0) { win_append(window, presence_colour, ", idle %dh%dm%ds", hours, minutes, seconds); @@ -1173,11 +1173,11 @@ win_show_info(ProfWin* window, PContact contact) GDateTime* now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); - int hours = span / G_TIME_SPAN_HOUR; + int hours = (int)(span / G_TIME_SPAN_HOUR); span = span - hours * G_TIME_SPAN_HOUR; - int minutes = span / G_TIME_SPAN_MINUTE; + int minutes = (int)(span / G_TIME_SPAN_MINUTE); span = span - minutes * G_TIME_SPAN_MINUTE; - int seconds = span / G_TIME_SPAN_SECOND; + int seconds = (int)(span / G_TIME_SPAN_SECOND); if (hours > 0) { win_println(window, THEME_DEFAULT, "-", "Last activity: %dh%dm%ds", hours, minutes, seconds); @@ -1846,7 +1846,7 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat gboolean me_message = FALSE; int offset = 0; int colour = theme_attrs(THEME_ME); - size_t indent = 0; + int indent = 0; auto_gchar gchar* time_pref = NULL; switch (window->type) { @@ -1879,7 +1879,7 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat assert(date_fmt != NULL); if (strlen(date_fmt) != 0) { - indent = 3 + strlen(date_fmt); + indent = 3 + (int)strlen(date_fmt); } if ((flags & NO_DATE) == 0) { @@ -1975,7 +1975,7 @@ _win_indent(WINDOW* win, int size) } static void -_win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent) +_win_print_wrapped(WINDOW* win, const char* const message, int indent, int pad_indent) { int starty = getcury(win); int wordi = 0; @@ -2002,7 +2002,8 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa int wordlen = 0; while (*curr_ch != ' ' && *curr_ch != '\n' && *curr_ch != '\0') { size_t ch_len = mbrlen(curr_ch, MB_CUR_MAX, NULL); - if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) { + // 0 / invalid step: advance one byte to avoid spinning. + if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) { curr_ch++; continue; } @@ -2015,9 +2016,9 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa word[wordi] = '\0'; wordlen = utf8_display_len(word); - size_t curx = (size_t)getcurx(win); + int curx = getcurx(win); int cury; - size_t maxx = getmaxx(win); + int maxx = getmaxx(win); // wrap required if (curx + wordlen > maxx) { @@ -2027,7 +2028,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa if (wordlen > linelen) { gchar* word_ch = g_utf8_offset_to_pointer(word, 0); while (*word_ch != '\0') { - curx = (size_t)getcurx(win); + curx = getcurx(win); cury = getcury(win); gboolean firstline = cury == starty; @@ -2048,7 +2049,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa // newline and print word } else { waddch(win, '\n'); - curx = (size_t)getcurx(win); + curx = getcurx(win); cury = getcury(win); gboolean firstline = cury == starty; @@ -2063,7 +2064,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa // no wrap required } else { - curx = (size_t)getcurx(win); + curx = getcurx(win); cury = getcury(win); gboolean firstline = cury == starty; diff --git a/src/xmpp/avatar.c b/src/xmpp/avatar.c index a0556df7..3d24d127 100644 --- a/src/xmpp/avatar.c +++ b/src/xmpp/avatar.c @@ -97,12 +97,12 @@ avatar_set(const char* path) int h = gdk_pixbuf_get_height(pixbuf); if (w >= h && w > MAX_PIXEL) { - int dest_height = (int)((float)MAX_PIXEL / w * h); + int dest_height = (int)((float)MAX_PIXEL / (float)w * (float)h); GdkPixbuf* new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, MAX_PIXEL, dest_height, GDK_INTERP_BILINEAR); g_object_unref(pixbuf); pixbuf = new_pixbuf; } else if (h > w && w > MAX_PIXEL) { - int dest_width = (int)((float)MAX_PIXEL / h * w); + int dest_width = (int)((float)MAX_PIXEL / (float)h * (float)w); GdkPixbuf* new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, dest_width, MAX_PIXEL, GDK_INTERP_BILINEAR); g_object_unref(pixbuf); pixbuf = new_pixbuf; diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c index dc72fd67..b0a8c7f4 100644 --- a/src/xmpp/connection.c +++ b/src/xmpp/connection.c @@ -245,10 +245,13 @@ connection_connect(const char* const jid, const char* const passwd, const char* _conn_apply_settings(jid, passwd, tls_policy, auth_policy); + // TCP ports are 16-bit; the account-layer validator must enforce this + // range before we reach libstrophe. + g_assert(port >= 0 && port <= UINT16_MAX); int connect_status = xmpp_connect_client( conn.xmpp_conn, altdomain, - port, + (unsigned short)port, _connection_handler, conn.xmpp_ctx); @@ -503,10 +506,11 @@ connection_register(const char* const altdomain, int port, const char* const tls reg->username = strdup(username); reg->password = strdup(password); + g_assert(port >= 0 && port <= UINT16_MAX); int connect_status = xmpp_connect_raw( conn.xmpp_conn, altdomain, - port, + (unsigned short)port, _register_handler, reg); @@ -1018,7 +1022,8 @@ _connection_handler(xmpp_conn_t* const xmpp_conn, const xmpp_conn_event_t status gchar* host; int port; if (stream_error && stream_error->stanza && _get_other_host(stream_error->stanza, &host, &port)) { - session_reconnect(host, port); + g_assert(port >= 0 && port <= UINT16_MAX); + session_reconnect(host, (unsigned short)port); log_debug("Connection handler: Forcing a re-connect to \"%s\"", host); conn.conn_status = JABBER_RECONNECT; return; diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index adb5b66b..377f444c 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -384,7 +384,7 @@ iq_autoping_check(void) } gdouble elapsed = g_timer_elapsed(autoping_time, NULL); - gint seconds_elapsed = elapsed * 1.0; + gint seconds_elapsed = (gint)elapsed; gint timeout = prefs_get_autoping_timeout(); if (timeout > 0 && seconds_elapsed >= timeout) { cons_show("Autoping response timed out after %u seconds.", timeout); @@ -1138,7 +1138,7 @@ _room_list_id_handler(xmpp_stanza_t* const stanza, void* const userdata) if (item_name) { item_name_lower = g_utf8_strdown(item_name, -1); } - if ((item_jid_lower) && ((glob == NULL) || ((g_pattern_match(glob, strlen(item_jid_lower), item_jid_lower, NULL)) || (item_name_lower && g_pattern_match(glob, strlen(item_name_lower), item_name_lower, NULL))))) { + if ((item_jid_lower) && ((glob == NULL) || ((g_pattern_match(glob, (guint)strlen(item_jid_lower), item_jid_lower, NULL)) || (item_name_lower && g_pattern_match(glob, (guint)strlen(item_name_lower), item_name_lower, NULL))))) { if (glob) { matched = TRUE; @@ -1394,7 +1394,7 @@ _manual_pong_id_handler(xmpp_stanza_t* const stanza, void* const userdata) GDateTime* now = g_date_time_new_now_local(); GTimeSpan elapsed = g_date_time_difference(now, sent); - int elapsed_millis = elapsed / 1000; + int elapsed_millis = (int)(elapsed / 1000); g_date_time_unref(now); @@ -1781,7 +1781,7 @@ _last_activity_get_handler(xmpp_stanza_t* const stanza) } if (prefs_get_boolean(PREF_LASTACTIVITY)) { - int idls_secs = ui_get_idle_time() / 1000; + int idls_secs = (int)(ui_get_idle_time() / 1000); char str[50]; sprintf(str, "%d", idls_secs); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 6abff1c7..047edec8 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -1640,7 +1640,7 @@ _ox_openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const t char rpad_data[randnr]; for (int i = 0; i < randnr; i++) { int rchar = (rand() % 52) + 65; - rpad_data[i] = rchar; + rpad_data[i] = (char)rchar; } rpad_data[randnr - 1] = '\0'; diff --git a/src/xmpp/omemo.c b/src/xmpp/omemo.c index 61343349..840deba5 100644 --- a/src/xmpp/omemo.c +++ b/src/xmpp/omemo.c @@ -194,7 +194,7 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* cons goto out; } - uint32_t device_id = strtoul(++device_id_str, NULL, 10); + uint32_t device_id = (uint32_t)strtoul(++device_id_str, NULL, 10); log_debug("[OMEMO] omemo_start_device_session_handle_bundle: %d", device_id); xmpp_stanza_t* item = xmpp_stanza_get_child_by_name(items, "item"); @@ -227,7 +227,7 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* cons continue; } - key->id = strtoul(prekey_id_text, NULL, 10); + key->id = (uint32_t)strtoul(prekey_id_text, NULL, 10); xmpp_stanza_t* prekey_text = xmpp_stanza_get_children(prekey); if (!prekey_text) { @@ -257,7 +257,7 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* cons goto out; } - uint32_t signed_prekey_id = strtoul(signed_prekey_id_text, NULL, 10); + uint32_t signed_prekey_id = (uint32_t)strtoul(signed_prekey_id_text, NULL, 10); xmpp_stanza_t* signed_prekey_text = xmpp_stanza_get_children(signed_prekey); if (!signed_prekey_text) { goto out; @@ -358,7 +358,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_erro *error = OMEMO_ERR_OTHER; return NULL; } - uint32_t sid = strtoul(sid_text, NULL, 10); + uint32_t sid = (uint32_t)strtoul(sid_text, NULL, 10); xmpp_stanza_t* iv = xmpp_stanza_get_child_by_name(header, "iv"); if (!iv) { @@ -403,7 +403,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_erro } const char* rid_text = xmpp_stanza_get_attribute(key_stanza, "rid"); - key->device_id = strtoul(rid_text, NULL, 10); + key->device_id = (uint32_t)strtoul(rid_text, NULL, 10); if (!key->device_id) { free(key); continue; diff --git a/src/xmpp/session.c b/src/xmpp/session.c index 89dc7412..1cf46554 100644 --- a/src/xmpp/session.c +++ b/src/xmpp/session.c @@ -243,7 +243,7 @@ session_process_events(void) case JABBER_DISCONNECTED: reconnect_sec = prefs_get_reconnect(); if ((reconnect_sec != 0) && reconnect_timer) { - int elapsed_sec = g_timer_elapsed(reconnect_timer, NULL); + int elapsed_sec = (int)g_timer_elapsed(reconnect_timer, NULL); if (elapsed_sec > reconnect_sec) { log_debug("[CONNDBG] session_process_events: auto-reconnect triggered after %d seconds (threshold=%d)", elapsed_sec, reconnect_sec); @@ -437,7 +437,7 @@ session_check_autoaway(void) auto_gchar gchar* message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); connection_set_presence_msg(message); if (prefs_get_boolean(PREF_LASTACTIVITY)) { - cl_ev_presence_send(RESOURCE_AWAY, idle_ms / 1000); + cl_ev_presence_send(RESOURCE_AWAY, (int)(idle_ms / 1000)); } else { cl_ev_presence_send(RESOURCE_AWAY, 0); } @@ -456,7 +456,7 @@ session_check_autoaway(void) // send current presence with last activity connection_set_presence_msg(curr_status); - cl_ev_presence_send(curr_presence, idle_ms / 1000); + cl_ev_presence_send(curr_presence, (int)(idle_ms / 1000)); } } break; @@ -479,7 +479,7 @@ session_check_autoaway(void) auto_gchar gchar* message = prefs_get_string(PREF_AUTOXA_MESSAGE); connection_set_presence_msg(message); if (prefs_get_boolean(PREF_LASTACTIVITY)) { - cl_ev_presence_send(RESOURCE_XA, idle_ms / 1000); + cl_ev_presence_send(RESOURCE_XA, (int)(idle_ms / 1000)); } else { cl_ev_presence_send(RESOURCE_XA, 0); } @@ -560,7 +560,8 @@ session_reconnect_now(void) port = reconnect.altport; } else { server = account->server; - port = account->port; + g_assert(account->port >= 0 && account->port <= UINT16_MAX); + port = (unsigned short)account->port; } log_debug("Attempting reconnect with account %s", account->name); diff --git a/tests/functionaltests/proftest.c b/tests/functionaltests/proftest.c index 525a7d01..1046792b 100644 --- a/tests/functionaltests/proftest.c +++ b/tests/functionaltests/proftest.c @@ -194,34 +194,36 @@ sleep_ms(int ms) * Read available data from fd into output_buffer with timeout. * Returns number of bytes read, 0 on timeout, -1 on error. */ -static int +static ssize_t _read_output(int timeout_ms) { fd_set readfds; struct timeval tv; - + FD_ZERO(&readfds); FD_SET(fd, &readfds); - + tv.tv_sec = timeout_ms / MS_TO_US; tv.tv_usec = (timeout_ms % MS_TO_US) * MS_TO_US; - + int ret = select(fd + 1, &readfds, NULL, NULL, &tv); if (ret <= 0) { return ret; } - - size_t space = OUTPUT_BUF_SIZE - output_len - 1; - if (space <= 0) { + + /* Check size before subtracting so OUTPUT_BUF_SIZE - output_len - 1 + * never goes negative / underflows. Reserves one byte for the + * trailing NUL. */ + if (output_len >= OUTPUT_BUF_SIZE - 1) { /* Buffer full, shift content */ memmove(output_buffer, output_buffer + OUTPUT_BUF_SIZE/2, OUTPUT_BUF_SIZE/2); output_len = OUTPUT_BUF_SIZE/2; - space = OUTPUT_BUF_SIZE - output_len - 1; } - + size_t space = OUTPUT_BUF_SIZE - output_len - 1; + ssize_t n = read(fd, output_buffer + output_len, space); if (n > 0) { - output_len += n; + output_len += (size_t)n; output_buffer[output_len] = '\0'; } return n;