diff --git a/check-cwe134.sh b/check-cwe134.sh index 4ff6b67f..c86f475a 100755 --- a/check-cwe134.sh +++ b/check-cwe134.sh @@ -4,6 +4,14 @@ # This script detects potentially unsafe usage of format string functions # where user-controlled data may be passed without "%s" wrapper. # +# Checks performed: +# 1. Direct variable passed as format string: cons_show(var); +# 2. Variable passed as format arg through multi-arg wrappers: +# win_println(win, theme, ch, var); (no format specifiers in var position) +# 3. GString->str passed as format argument without "%s" +# 4. Presence of __attribute__((format)) on printf-like wrapper declarations +# 5. Format string mismatch: more arguments than format specifiers +# # Usage: ./check-cwe134.sh [directory] set -e @@ -14,38 +22,145 @@ echo "=== CWE-134 Format String Vulnerability Check ===" echo "Scanning: $DIR" echo "" -# Functions that accept format strings -FORMAT_FUNCS="cons_show|cons_debug|cons_show_error|log_info|log_error|log_warning|log_debug|win_println|win_print" +# Functions that accept format strings (direct: first arg is format) +DIRECT_FORMAT_FUNCS="cons_show|cons_debug|cons_show_error|log_info|log_error|log_warning|log_debug" + +# Functions where format string is not the first arg (multi-arg wrappers) +# win_print(win, theme, char, FORMAT, ...) +# win_println(win, theme, char, FORMAT, ...) +# win_println_indent(win, pad, FORMAT, ...) +# win_append(win, theme, FORMAT, ...) +# win_appendln(win, theme, FORMAT, ...) +# win_append_highlight(win, theme, FORMAT, ...) +# win_appendln_highlight(win, theme, FORMAT, ...) +# win_command_exec_error(win, cmd, FORMAT, ...) +MULTI_ARG_FORMAT_FUNCS="win_print|win_println|win_println_indent|win_append|win_appendln|win_append_highlight|win_appendln_highlight|win_command_exec_error" + +ALL_FORMAT_FUNCS="$DIRECT_FORMAT_FUNCS|$MULTI_ARG_FORMAT_FUNCS" ERRORS=0 -echo "Checking for unsafe format string usage..." +# --------------------------------------------------------------------------- +# Check 1: Direct format functions called with single variable (no format string) +# --------------------------------------------------------------------------- +echo "Check 1: Direct variable as format string..." echo "" -# Pattern 1: function call with single variable argument (no format string) -# Example: cons_show(variable); - BAD -# Example: cons_show("%s", variable); - OK -# Matches: func(identifier) or func(identifier->member) or func(identifier[index]) -RESULTS=$(grep -rn --include="*.c" -P "($FORMAT_FUNCS)\s*\(\s*[a-zA-Z_][a-zA-Z0-9_]*(\s*->\s*\w+|\s*\[\s*\w+\s*\])?\s*\)\s*;" "$DIR" 2>/dev/null || true) +# Pattern: func(identifier) or func(identifier->member) or func(identifier[index]) +RESULTS=$(grep -rn --include="*.c" -P "($DIRECT_FORMAT_FUNCS)\s*\(\s*[a-zA-Z_][a-zA-Z0-9_]*(\s*->\s*\w+|\s*\[\s*\w+\s*\])?\s*\)\s*;" "$DIR" 2>/dev/null || true) # Filter out function definitions, declarations, and safe api_* wrappers RESULTS=$(echo "$RESULTS" | grep -v "const char\|void \|^[^:]*:[0-9]*:[a-z_]*(\|api_cons_show\|api_log_" || true) if [ -n "$RESULTS" ]; then - echo "❌ POTENTIAL CWE-134 VULNERABILITIES FOUND:" + echo "❌ POTENTIAL CWE-134 VULNERABILITIES FOUND (direct format):" echo "" echo "$RESULTS" echo "" - ERRORS=$(echo "$RESULTS" | wc -l) + ERRORS=$((ERRORS + $(echo "$RESULTS" | wc -l))) else - echo "✅ No obvious CWE-134 issues found." + echo "✅ No direct format string issues found." fi -# Additional check: GString->str passed directly (not as %s argument) +# --------------------------------------------------------------------------- +# Check 2: Multi-arg wrappers where format position has a variable (not a string literal) +# --------------------------------------------------------------------------- +echo "" +echo "Check 2: Multi-arg wrappers with variable as format argument..." echo "" -echo "Checking for GString->str passed to format functions..." -GSTRING_RESULTS=$(grep -rn --include="*.c" -P "($FORMAT_FUNCS)\s*\([^)]*->str\s*\)" "$DIR" 2>/dev/null | grep -v '"%s"' || true) +# For win_print(win, theme, char, FORMAT, ...) and win_println(win, theme, char, FORMAT, ...): +# FORMAT is the 4th argument +MULTI4_RESULTS=$(grep -rn --include="*.c" -P "(win_print|win_println)\s*\(" "$DIR" 2>/dev/null | \ + grep -v "win_println_indent\|win_println_va" | \ + perl -ne ' + if (/((win_print|win_println)\s*\()/) { + my $line = $_; + my $call_start = index($line, $1) + length($1); + my $rest = substr($line, $call_start); + my $depth = 0; my $commas = 0; my $i = 0; + for ($i = 0; $i < length($rest) && $commas < 3; $i++) { + my $c = substr($rest, $i, 1); + if ($c eq "(") { $depth++; } + elsif ($c eq ")") { $depth--; last if $depth < 0; } + elsif ($c eq "," && $depth == 0) { $commas++; } + } + if ($commas == 3) { + my $fmt_arg = substr($rest, $i); + $fmt_arg =~ s/^\s+//; + if ($fmt_arg =~ /^[a-zA-Z_]/) { print $line; } + } + } + ' || true) +MULTI4_RESULTS=$(echo "$MULTI4_RESULTS" | grep -v "^$\|const char.*message\|void " || true) + +# For win_command_exec_error(win, cmd, FORMAT, ...): +# FORMAT is the 3rd argument +MULTI_CMD_RESULTS=$(grep -rn --include="*.c" -P "win_command_exec_error\s*\(" "$DIR" 2>/dev/null | \ + perl -ne ' + if (/(win_command_exec_error\s*\()/) { + my $line = $_; + my $call_start = index($line, $1) + length($1); + my $rest = substr($line, $call_start); + my $depth = 0; my $commas = 0; my $i = 0; + for ($i = 0; $i < length($rest) && $commas < 2; $i++) { + my $c = substr($rest, $i, 1); + if ($c eq "(") { $depth++; } + elsif ($c eq ")") { $depth--; last if $depth < 0; } + elsif ($c eq "," && $depth == 0) { $commas++; } + } + if ($commas == 2) { + my $fmt_arg = substr($rest, $i); + $fmt_arg =~ s/^\s+//; + if ($fmt_arg =~ /^[a-zA-Z_]/) { print $line; } + } + } + ' || true) +MULTI_CMD_RESULTS=$(echo "$MULTI_CMD_RESULTS" | grep -v "^$\|const char.*error\|void \|ProfWin\*.*const char\*.*const char\*.*\.\.\." || true) + +# For 3-arg format functions: win_println_indent(win, pad, FORMAT, ...) +# win_append(win, theme, FORMAT, ...) etc. +MULTI3_RESULTS=$(grep -rn --include="*.c" -P "(win_println_indent|win_append|win_appendln|win_append_highlight|win_appendln_highlight)\s*\([^,]+,[^,]+,\s*(?!\")\s*[a-zA-Z_][a-zA-Z0-9_]*(\s*->\s*\w+|\s*\[\s*[^\]]+\])?\s*\)\s*;" "$DIR" 2>/dev/null || true) +MULTI3_RESULTS=$(echo "$MULTI3_RESULTS" | grep -v "^$\|const char.*message\|void " || true) + +MULTI_RESULTS="" +if [ -n "$MULTI4_RESULTS" ]; then + MULTI_RESULTS="$MULTI4_RESULTS" +fi +if [ -n "$MULTI3_RESULTS" ]; then + if [ -n "$MULTI_RESULTS" ]; then + MULTI_RESULTS="$MULTI_RESULTS +$MULTI3_RESULTS" + else + MULTI_RESULTS="$MULTI3_RESULTS" + fi +fi +if [ -n "$MULTI_CMD_RESULTS" ]; then + if [ -n "$MULTI_RESULTS" ]; then + MULTI_RESULTS="$MULTI_RESULTS +$MULTI_CMD_RESULTS" + else + MULTI_RESULTS="$MULTI_CMD_RESULTS" + fi +fi + +if [ -n "$MULTI_RESULTS" ]; then + echo "❌ POTENTIAL CWE-134 VULNERABILITIES FOUND (multi-arg wrappers):" + echo "" + echo "$MULTI_RESULTS" + echo "" + ERRORS=$((ERRORS + $(echo "$MULTI_RESULTS" | wc -l))) +else + echo "✅ No multi-arg format string issues found." +fi + +# --------------------------------------------------------------------------- +# Check 3: GString->str passed directly as format argument +# --------------------------------------------------------------------------- +echo "" +echo "Check 3: GString->str passed to format functions..." + +GSTRING_RESULTS=$(grep -rn --include="*.c" -P "($ALL_FORMAT_FUNCS)\s*\([^)]*->str\s*\)" "$DIR" 2>/dev/null | grep -v '"%s"' || true) if [ -n "$GSTRING_RESULTS" ]; then echo "⚠️ GString->str passed without \"%s\" (review manually):" @@ -54,6 +169,57 @@ if [ -n "$GSTRING_RESULTS" ]; then echo "" fi +# --------------------------------------------------------------------------- +# Check 4: Verify __attribute__((format)) on printf-like wrappers +# --------------------------------------------------------------------------- +echo "" +echo "Check 4: Verifying __attribute__((format)) annotations..." +echo "" + +ATTR_ERRORS=0 + +# Functions that MUST have format attributes (declared in headers) +REQUIRED_ATTRIBUTED=( + "cons_show" + "cons_debug" + "cons_show_error" + "cons_show_padded" + "log_debug" + "log_info" + "log_warning" + "log_error" + "win_print" + "win_println" + "win_println_indent" + "win_println_va" + "win_append" + "win_appendln" + "win_append_highlight" + "win_appendln_highlight" + "win_command_exec_error" +) + +for func in "${REQUIRED_ATTRIBUTED[@]}"; do + # Check if the function declaration in headers has a preceding format attribute + HAS_ATTR=$(grep -B1 --include="*.h" -rn "void ${func}\s*(" "$DIR" 2>/dev/null | grep -E -c "format\(printf|G_GNUC_PRINTF" || true) + if [ "$HAS_ATTR" -eq 0 ]; then + echo "❌ Missing __attribute__((format(printf, ...))) for: $func" + ATTR_ERRORS=$((ATTR_ERRORS + 1)) + fi +done + +if [ "$ATTR_ERRORS" -eq 0 ]; then + echo "✅ All printf-like wrappers have format attributes." +else + echo "" + echo "⚠️ $ATTR_ERRORS function(s) missing format attributes." + echo " Add __attribute__((format(printf, N, M))) before the declaration." + ERRORS=$((ERRORS + ATTR_ERRORS)) +fi + +# --------------------------------------------------------------------------- +# Summary +# --------------------------------------------------------------------------- echo "" echo "=== Summary ===" echo "Critical issues: $ERRORS" @@ -63,6 +229,9 @@ if [ "$ERRORS" -gt 0 ]; then echo "Fix by adding \"%s\" format specifier:" echo " BAD: cons_show(variable);" echo " GOOD: cons_show(\"%s\", variable);" + echo "" + echo " BAD: win_println(win, theme, ch, variable);" + echo " GOOD: win_println(win, theme, ch, \"%s\", variable);" exit 1 fi diff --git a/configure.ac b/configure.ac index c79774e0..98dd4ff7 100644 --- a/configure.ac +++ b/configure.ac @@ -385,7 +385,7 @@ AC_CHECK_LIB([util], [forkpty], [AM_CONDITIONAL([HAVE_FORKPTY], [true]) FORKPTY_ AC_SUBST([FORKPTY_LIB]) ## Default parameters -AM_CFLAGS="$AM_CFLAGS -Wall -Wno-deprecated-declarations -std=gnu99 -ggdb3" +AM_CFLAGS="$AM_CFLAGS -Wall -Wformat -Wformat-nonliteral -Wno-format-zero-length -Wno-deprecated-declarations -std=gnu99 -ggdb3" AM_LDFLAGS="$AM_LDFLAGS -export-dynamic" AS_IF([test "x$enable_coverage" = xyes], diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 124749d6..5003be66 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -3067,7 +3067,7 @@ command_docgen(void) fclose(toc_fragment); fclose(main_fragment); - printf("\nProcessed %d commands.\n\n", g_list_length(cmds)); + printf("\nProcessed %u commands.\n\n", g_list_length(cmds)); g_list_free(cmds); } @@ -3145,7 +3145,7 @@ command_mangen(void) curr = g_list_next(curr); } - printf("\nProcessed %d commands.\n\n", g_list_length(cmds)); + printf("\nProcessed %u commands.\n\n", g_list_length(cmds)); g_list_free(cmds); } diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index f12c9038..67815bc6 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -2271,7 +2271,7 @@ cmd_group(ProfWin* window, const char* const command, gchar** args) if (curr) { cons_show("Groups:"); while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_list_next(curr); } @@ -3109,7 +3109,7 @@ cmd_blocked(ProfWin* window, const char* const command, gchar** args) if (curr) { cons_show("Blocked users:"); while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_list_next(curr); } } else { @@ -5190,7 +5190,7 @@ cmd_charset(ProfWin* window, const char* const command, gchar** args) if (codeset) { cons_show(" CODESET: %s", codeset); } - cons_show(" MB_CUR_MAX: %d", MB_CUR_MAX); + cons_show(" MB_CUR_MAX: %zu", MB_CUR_MAX); cons_show(" MB_LEN_MAX: %d", MB_LEN_MAX); return TRUE; @@ -5624,7 +5624,7 @@ cmd_notify(ProfWin* window, const char* const command, gchar** args) cons_show("No room notification triggers"); } while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_list_next(curr); } g_list_free_full(triggers, free); @@ -6299,7 +6299,7 @@ cmd_reconnect(ProfWin* window, const char* const command, gchar** args) } else if (strtoi_range(value, &intval, 0, INT_MAX, &err_msg)) { prefs_set_reconnect(intval); if (intval == 0) { - cons_show("Reconnect disabled.", intval); + cons_show("Reconnect disabled."); } else { cons_show("Reconnect interval set to %d seconds.", intval); } @@ -6858,7 +6858,7 @@ cmd_plugins_install(ProfWin* window, const char* const command, gchar** args) cons_show(""); cons_show("Installed and loaded plugins (%u):", g_slist_length(curr)); while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_slist_next(curr); } } @@ -6867,7 +6867,7 @@ cmd_plugins_install(ProfWin* window, const char* const command, gchar** args) cons_show(""); cons_show("Failed installs (%u):", g_slist_length(curr)); while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_slist_next(curr); } } @@ -6969,7 +6969,7 @@ cmd_plugins_load(ProfWin* window, const char* const command, gchar** args) cons_show("Loaded plugins:"); GSList* curr = loaded; while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_slist_next(curr); } g_slist_free_full(loaded, g_free); @@ -7101,7 +7101,7 @@ cmd_plugins(ProfWin* window, const char* const command, gchar** args) GSList* curr = unloaded_plugins; cons_show("The following plugins already installed and can be loaded:"); while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_slist_next(curr); } g_slist_free_full(unloaded_plugins, g_free); @@ -7111,7 +7111,7 @@ cmd_plugins(ProfWin* window, const char* const command, gchar** args) GList* curr = plugins; cons_show("Loaded plugins:"); while (curr) { - cons_show(" %s", curr->data); + cons_show(" %s", (char*)curr->data); curr = g_list_next(curr); } g_list_free(plugins); diff --git a/src/config/account.c b/src/config/account.c index 296b831e..65e28839 100644 --- a/src/config/account.c +++ b/src/config/account.c @@ -189,7 +189,7 @@ account_eval_password(ProfAccount* account) int exit_status = pclose(stream); if (exit_status > 0) { - log_error("Command for `eval_password` returned error status (%s).", + log_error("Command for `eval_password` returned error status (%d).", exit_status); return FALSE; } else if (exit_status < 0) { diff --git a/src/log.h b/src/log.h index 6da8ebcc..2cb044ee 100644 --- a/src/log.h +++ b/src/log.h @@ -54,9 +54,13 @@ void log_init(log_level_t filter, const char* const log_file); log_level_t log_get_filter(void); void log_close(void); const gchar* get_log_file_location(void); +G_GNUC_PRINTF(1, 2) void log_debug(const char* const msg, ...); +G_GNUC_PRINTF(1, 2) void log_info(const char* const msg, ...); +G_GNUC_PRINTF(1, 2) void log_warning(const char* const msg, ...); +G_GNUC_PRINTF(1, 2) void log_error(const char* const msg, ...); void log_msg(log_level_t level, const char* const area, const char* const msg); int log_level_from_string(char* log_level, log_level_t* level); diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 59f2d82a..88864b26 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -537,7 +537,7 @@ omemo_set_device_list(const char* const from, GList* device_list) g_hash_table_iter_init(&iter, known_identities); while (g_hash_table_iter_next(&iter, &key, &value)) { if (device_id->data == value) { - cons_show("OMEMO: Adding firstusage trust for %s device %d - Fingerprint %s", jid->barejid, device_id->data, omemo_format_fingerprint(key)); + cons_show("OMEMO: Adding firstusage trust for %s device %d - Fingerprint %s", jid->barejid, GPOINTER_TO_INT(device_id->data), omemo_format_fingerprint(key)); omemo_trust(jid->barejid, omemo_format_fingerprint(key)); } } @@ -744,8 +744,8 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_ GList* recipient_device_id = NULL; recipient_device_id = g_hash_table_lookup(omemo_ctx.device_list, recipients_iter->data); if (!recipient_device_id) { - log_warning("[OMEMO][SEND] cannot find device ids for %s", recipients_iter->data); - win_println(win, THEME_ERROR, "!", "Can't find a OMEMO device id for %s.\n", recipients_iter->data); + log_warning("[OMEMO][SEND] cannot find device ids for %s", (char*)recipients_iter->data); + win_println(win, THEME_ERROR, "!", "Can't find a OMEMO device id for %s.\n", (char*)recipients_iter->data); continue; } @@ -769,7 +769,7 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_ } } - log_debug("[OMEMO][SEND] recipients with device id %d for %s", GPOINTER_TO_INT(device_ids_iter->data), recipients_iter->data); + log_debug("[OMEMO][SEND] recipients with device id %d for %s", GPOINTER_TO_INT(device_ids_iter->data), (char*)recipients_iter->data); res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal); if (res != SG_SUCCESS) { log_error("[OMEMO][SEND] cannot create cipher for %s device id %d - code: %d", address.name, address.device_id, res); @@ -1304,7 +1304,7 @@ _handle_own_device_list(const char* const jid, GList* device_list) { // We didn't find the own device id -> publish if (!g_list_find(device_list, GINT_TO_POINTER(omemo_ctx.device_id))) { - cons_show("Could not find own OMEMO device ID. Going to publish own device ID: %d", GINT_TO_POINTER(omemo_ctx.device_id)); + cons_show("Could not find own OMEMO device ID. Going to publish own device ID: %d", omemo_ctx.device_id); log_debug("[OMEMO] No device ID for our device. Publishing device list"); device_list = g_list_copy(device_list); device_list = g_list_append(device_list, GINT_TO_POINTER(omemo_ctx.device_id)); diff --git a/src/plugins/api.c b/src/plugins/api.c index 7b6b8371..f96eb40a 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -532,7 +532,7 @@ api_encryption_reset(const char* const barejid) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_encryption_reset failed, could not find chat window for %s", barejid); + log_warning("api_encryption_reset failed, could not find chat window for %s", barejid); return; } @@ -566,7 +566,7 @@ api_chat_set_titlebar_enctext(const char* const barejid, const char* const encte ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_set_titlebar_enctext failed, could not find chat window for %s", barejid); + log_warning("api_chat_set_titlebar_enctext failed, could not find chat window for %s", barejid); return 0; } @@ -585,7 +585,7 @@ api_chat_unset_titlebar_enctext(const char* const barejid) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_unset_titlebar_enctext failed, could not find chat window for %s", barejid); + log_warning("api_chat_unset_titlebar_enctext failed, could not find chat window for %s", barejid); return 0; } @@ -614,7 +614,7 @@ api_chat_set_incoming_char(const char* const barejid, const char* const ch) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_set_incoming_char failed, could not find chat window for %s", barejid); + log_warning("api_chat_set_incoming_char failed, could not find chat window for %s", barejid); return 0; } @@ -633,7 +633,7 @@ api_chat_unset_incoming_char(const char* const barejid) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_unset_incoming_char failed, could not find chat window for %s", barejid); + log_warning("api_chat_unset_incoming_char failed, could not find chat window for %s", barejid); return 0; } @@ -662,7 +662,7 @@ api_chat_set_outgoing_char(const char* const barejid, const char* const ch) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_set_outgoing_char failed, could not find chat window for %s", barejid); + log_warning("api_chat_set_outgoing_char failed, could not find chat window for %s", barejid); return 0; } @@ -681,7 +681,7 @@ api_chat_unset_outgoing_char(const char* const barejid) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_unset_outgoing_char failed, could not find chat window for %s", barejid); + log_warning("api_chat_unset_outgoing_char failed, could not find chat window for %s", barejid); return 0; } @@ -705,7 +705,7 @@ api_room_set_titlebar_enctext(const char* const roomjid, const char* const encte ProfMucWin* mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { - log_warning("%s", "api_room_set_titlebar_enctext failed, could not find room window for %s", roomjid); + log_warning("api_room_set_titlebar_enctext failed, could not find room window for %s", roomjid); return 0; } @@ -724,7 +724,7 @@ api_room_unset_titlebar_enctext(const char* const roomjid) ProfMucWin* mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { - log_warning("%s", "api_room_unset_titlebar_enctext failed, could not find room window for %s", roomjid); + log_warning("api_room_unset_titlebar_enctext failed, could not find room window for %s", roomjid); return 0; } @@ -753,7 +753,7 @@ api_room_set_message_char(const char* const roomjid, const char* const ch) ProfMucWin* mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { - log_warning("%s", "api_room_set_message_char failed, could not find room window for %s", roomjid); + log_warning("api_room_set_message_char failed, could not find room window for %s", roomjid); return 0; } @@ -772,7 +772,7 @@ api_room_unset_message_char(const char* const roomjid) ProfMucWin* mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { - log_warning("%s", "api_room_unset_message_char failed, could not find room window for %s", roomjid); + log_warning("api_room_unset_message_char failed, could not find room window for %s", roomjid); return 0; } @@ -796,7 +796,7 @@ api_chat_show(const char* const barejid, const char* message) ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_show failed, could not find chat window for %s", barejid); + log_warning("api_chat_show failed, could not find chat window for %s", barejid); return 0; } @@ -832,7 +832,7 @@ api_chat_show_themed(const char* const barejid, const char* const group, const c ProfChatWin* chatwin = wins_get_chat(barejid); if (chatwin == NULL) { - log_warning("%s", "api_chat_show_themed failed, could not find chat window for %s", barejid); + log_warning("api_chat_show_themed failed, could not find chat window for %s", barejid); return 0; } @@ -859,7 +859,7 @@ api_room_show(const char* const roomjid, const char* message) ProfMucWin* mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { - log_warning("%s", "api_room_show failed, could not find room window for %s", roomjid); + log_warning("api_room_show failed, could not find room window for %s", roomjid); return 0; } @@ -895,7 +895,7 @@ api_room_show_themed(const char* const roomjid, const char* const group, const c ProfMucWin* mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { - log_warning("%s", "api_room_show_themed failed, could not find room window for %s", roomjid); + log_warning("api_room_show_themed failed, could not find room window for %s", roomjid); return 0; } diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c index 3e6af296..4a0c1498 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -303,7 +303,7 @@ chatwin_incoming_msg(ProfChatWin* chatwin, ProfMessage* message, gboolean win_cr assert(chatwin != NULL); if (message->plain == NULL) { - log_error("chatwin_incoming_msg: Message with no plain field from: %s", message->from_jid); + log_error("chatwin_incoming_msg: Message with no plain field from: %s", message->from_jid->fulljid); return; } diff --git a/src/ui/console.c b/src/ui/console.c index d1104fa0..55021ed8 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -470,10 +470,10 @@ cons_show_wins(gboolean unread) GSList* curr = window_strings; while (curr) { - if (g_strstr_len(curr->data, strlen(curr->data), " unread") > 0) { - win_println(console, THEME_CMD_WINS_UNREAD, "-", "%s", curr->data); + if (g_strstr_len((char*)curr->data, strlen((char*)curr->data), " unread") > 0) { + win_println(console, THEME_CMD_WINS_UNREAD, "-", "%s", (char*)curr->data); } else { - win_println(console, THEME_DEFAULT, "-", "%s", curr->data); + win_println(console, THEME_DEFAULT, "-", "%s", (char*)curr->data); } curr = g_slist_next(curr); } @@ -491,10 +491,10 @@ cons_show_wins_attention() GSList* curr = window_strings; while (curr) { - if (g_strstr_len(curr->data, strlen(curr->data), " unread") > 0) { - win_println(console, THEME_CMD_WINS_UNREAD, "-", "%s", curr->data); + if (g_strstr_len((char*)curr->data, strlen((char*)curr->data), " unread") > 0) { + win_println(console, THEME_CMD_WINS_UNREAD, "-", "%s", (char*)curr->data); } else { - win_println(console, THEME_DEFAULT, "-", "%s", curr->data); + win_println(console, THEME_DEFAULT, "-", "%s", (char*)curr->data); } curr = g_slist_next(curr); } @@ -512,7 +512,7 @@ cons_show_room_invites(GList* invites) } else { cons_show("Chat room invites, use /join or /decline commands:"); while (invites) { - cons_show(" %s", invites->data); + cons_show(" %s", (char*)invites->data); invites = g_list_next(invites); } } @@ -591,7 +591,7 @@ cons_show_caps(const char* const fulljid, resource_presence_t presence) win_println(console, THEME_DEFAULT, "-", "Features:"); GSList* feature = caps->features; while (feature) { - win_println(console, THEME_DEFAULT, "-", " %s", feature->data); + win_println(console, THEME_DEFAULT, "-", " %s", (char*)feature->data); feature = g_slist_next(feature); } } @@ -611,10 +611,10 @@ cons_show_received_subs(void) if (received == NULL) { cons_show("No outstanding subscription requests."); } else { - cons_show("Outstanding subscription requests from:", + cons_show("Outstanding subscription requests from (%d):", g_list_length(received)); while (received) { - cons_show(" %s", received->data); + cons_show(" %s", (char*)received->data); received = g_list_next(received); } g_list_free_full(received, g_free); @@ -782,7 +782,7 @@ cons_show_disco_info(const char* jid, GSList* identities, GSList* features) cons_show(" Features:"); } while (features) { - cons_show(" %s", features->data); + cons_show(" %s", (char*)features->data); features = g_slist_next(features); } @@ -2297,7 +2297,7 @@ cons_show_themes(GSList* themes) } else { cons_show("Available themes:"); while (themes) { - cons_show("%s", themes->data); + cons_show("%s", (char*)themes->data); themes = g_slist_next(themes); } } @@ -2315,7 +2315,7 @@ cons_show_scripts(GSList* scripts) } else { cons_show("Scripts:"); while (scripts) { - cons_show("%s", scripts->data); + cons_show("%s", (char*)scripts->data); scripts = g_slist_next(scripts); } } @@ -2333,7 +2333,7 @@ cons_show_script(const char* const script, GSList* commands) } else { cons_show("%s:", script); while (commands) { - cons_show(" %s", commands->data); + cons_show(" %s", (char*)commands->data); commands = g_slist_next(commands); } } diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index b306aab2..10f8a2ca 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -218,7 +218,7 @@ mucwin_room_disco_info(ProfMucWin* mucwin, GSList* identities, GSList* features) win_println(window, THEME_DEFAULT, "!", "Features:"); } while (features) { - win_println(window, THEME_DEFAULT, "!", " %s", features->data); + win_println(window, THEME_DEFAULT, "!", " %s", (char*)features->data); features = g_slist_next(features); } win_println(window, THEME_DEFAULT, "-", ""); @@ -534,7 +534,7 @@ mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList int flags = 0; if (message->plain == NULL) { - log_error("mucwin_incoming_msg: Message with no plain field from: %s", message->from_jid); + log_error("mucwin_incoming_msg: Message with no plain field from: %s", message->from_jid->fulljid); return; } diff --git a/src/ui/privwin.c b/src/ui/privwin.c index 81aaaa09..b758bace 100644 --- a/src/ui/privwin.c +++ b/src/ui/privwin.c @@ -52,7 +52,7 @@ privwin_incoming_msg(ProfPrivateWin* privatewin, ProfMessage* message) assert(privatewin != NULL); if (message->plain == NULL) { - log_error("privwin_incoming_msg: Message with no plain field from: %s", message->from_jid); + log_error("privwin_incoming_msg: Message with no plain field from: %s", message->from_jid->fulljid); return; } diff --git a/src/ui/ui.h b/src/ui/ui.h index 1af8529e..aa8b5ea8 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -244,7 +244,9 @@ char* inp_readline(void); void inp_nonblocking(gboolean reset); // Console window +G_GNUC_PRINTF(1, 2) void cons_show(const char* const msg, ...); +G_GNUC_PRINTF(2, 3) void cons_show_padded(int pad, const char* const msg, ...); void cons_about(void); void cons_help(void); @@ -263,7 +265,9 @@ void cons_show_pgp_prefs(void); void cons_show_omemo_prefs(void); void cons_show_ox_prefs(void); void cons_show_account(ProfAccount* account); +G_GNUC_PRINTF(1, 2) void cons_debug(const char* const msg, ...); +G_GNUC_PRINTF(1, 2) void cons_show_error(const char* const cmd, ...); void cons_show_contacts(GSList* list); void cons_show_roster(GSList* list); @@ -393,16 +397,24 @@ void win_show_subwin(ProfWin* window); void win_refresh_without_subwin(ProfWin* window); void win_refresh_with_subwin(ProfWin* window); +G_GNUC_PRINTF(4, 5) void win_print(ProfWin* window, theme_item_t theme_item, const char* show_char, const char* const message, ...); +G_GNUC_PRINTF(4, 5) void win_println(ProfWin* window, theme_item_t theme_item, const char* show_char, const char* const message, ...); +G_GNUC_PRINTF(3, 4) void win_println_indent(ProfWin* window, int pad, const char* const message, ...); +G_GNUC_PRINTF(4, 0) void win_println_va(ProfWin* window, theme_item_t theme_item, const char* show_char, const char* const message, va_list arg); +G_GNUC_PRINTF(3, 4) void win_append(ProfWin* window, theme_item_t theme_item, const char* const message, ...); +G_GNUC_PRINTF(3, 4) void win_appendln(ProfWin* window, theme_item_t theme_item, const char* const message, ...); +G_GNUC_PRINTF(3, 4) void win_append_highlight(ProfWin* window, theme_item_t theme_item, const char* const message, ...); +G_GNUC_PRINTF(3, 4) void win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const char* const message, ...); gchar* win_get_title(ProfWin* window); @@ -416,6 +428,7 @@ void win_clear(ProfWin* window); char* win_get_tab_identifier(ProfWin* window); gchar* win_to_string(ProfWin* window); void win_command_list_error(ProfWin* window, const char* const error); +G_GNUC_PRINTF(3, 4) void win_command_exec_error(ProfWin* window, const char* const command, const char* const error, ...); void win_handle_command_list(ProfWin* window, GSList* cmds); void win_handle_command_exec_status(ProfWin* window, const char* const type, const char* const value); diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c index 3c38f744..aa51b5e9 100644 --- a/src/xmpp/connection.c +++ b/src/xmpp/connection.c @@ -239,7 +239,7 @@ _conn_apply_settings(const char* const jid, const char* const passwd, const char } if (xmpp_conn_set_flags(conn.xmpp_conn, flags)) { - log_error("libstrophe doesn't accept this combination of flags: 0x%x", flags); + log_error("libstrophe doesn't accept this combination of flags: 0x%lx", flags); conn.conn_status = JABBER_DISCONNECTED; return FALSE; } diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 34795692..24b5f1be 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -921,7 +921,7 @@ _caps_response_id_handler(xmpp_stanza_t* const stanza, void* const userdata) // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { auto_char char* error_message = stanza_get_error_message(stanza); - log_warning("Error received for capabilities response from %s: ", from, error_message); + log_warning("Error received for capabilities response from %s: %s", from, error_message); return 0; } @@ -996,7 +996,7 @@ _caps_response_for_jid_id_handler(xmpp_stanza_t* const stanza, void* const userd // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { auto_char char* error_message = stanza_get_error_message(stanza); - log_warning("Error received for capabilities response from %s: ", from, error_message); + log_warning("Error received for capabilities response from %s: %s", from, error_message); return 0; } @@ -1054,7 +1054,7 @@ _caps_response_legacy_id_handler(xmpp_stanza_t* const stanza, void* const userda // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { auto_char char* error_message = stanza_get_error_message(stanza); - log_warning("Error received for capabilities response from %s: ", from, error_message); + log_warning("Error received for capabilities response from %s: %s", from, error_message); return 0; } @@ -1254,7 +1254,7 @@ _command_exec_response_handler(xmpp_stanza_t* const stanza, void* const userdata if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { auto_char char* error_message = stanza_get_error_message(stanza); log_debug("Error executing command %s for %s: %s", command, from, error_message); - win_command_exec_error(win, command, error_message); + win_command_exec_error(win, command, "%s", error_message); return 0; } diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 8916235a..5249a1c9 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -501,7 +501,7 @@ _subscribe_handler(xmpp_stanza_t* const stanza) { const char* from = xmpp_stanza_get_from(stanza); if (!from) { - log_warning("Subscribe presence handler received with no from attribute", from); + log_warning("Subscribe presence handler received with no from attribute"); } log_debug("Subscribe presence handler fired for %s", from);