From 454e98a4a40c41b77a7e3dd8b19bc93720d27d4a Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Mon, 4 May 2020 19:53:00 +0200
Subject: [PATCH] Using a 'safe' snprintf

---
 inc/common/common.h     |  2 ++
 src/commands.c          | 14 ++++++--------
 src/common.c            | 12 ++++++++++++
 src/database/config.c   |  6 ++----
 src/database/find.c     |  8 ++------
 src/database/open.c     |  6 ++----
 src/database/playlist.c |  9 +++------
 src/database/queue.c    | 17 ++++++-----------
 src/database/stickers.c |  3 +--
 src/database/update.c   |  4 ++--
 src/main/lkt.c          | 18 ++++++------------
 src/module/mpv.c        |  2 +-
 src/net/downloader.c    | 12 ++++--------
 src/net/listen.c        |  3 +--
 src/uri.c               | 10 +++++-----
 15 files changed, 55 insertions(+), 71 deletions(-)

diff --git a/inc/common/common.h b/inc/common/common.h
index 501996fc..074fd87b 100644
--- a/inc/common/common.h
+++ b/inc/common/common.h
@@ -36,3 +36,5 @@ char *trim(char *str, size_t len, char c);
 int get_stdin_line(const char *prompt, char *buf, size_t len);
 
 int read_self_exe(char *path, size_t len);
+
+int safe_snprintf(char *dest, const size_t max_len, const char *format, ...);
diff --git a/src/commands.c b/src/commands.c
index 1b18a65a..d8d890ab 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -84,7 +84,7 @@ command_currentsong(struct lkt_state *srv, size_t c)
         LOG_ERROR_SCT("COMMAND", "%s", "Failed to get information about the current kara");
 
     out = lkt_message_new();
-    idx = snprintf(out->data, LKT_MESSAGE_MAX,
+    idx = safe_snprintf(out->data, LKT_MESSAGE_MAX,
                    "Title: %s\n"
                    "Author: %s\n"
                    "Source: %s\n"
@@ -119,7 +119,7 @@ command_status(struct lkt_state *srv, size_t c)
     play_state = queue_state.current <= 0
                  ? "stop"
                  : (queue_state.paused ? "pause" : "play");
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX,
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX,
                              "volume: %d\n"
                              "repeat: %d\n"
                              "random: %d\n"
@@ -312,10 +312,8 @@ bool
 command_help(struct lkt_state *srv, size_t c)
 {
     struct lkt_message *out;
-    int idx;
     out = lkt_message_new();
-    idx = snprintf(out->data, LKT_MESSAGE_MAX, "HELP\n");
-    out->data_len = idx;
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX, "HELP\n");
     lkt_state_send(srv, c, out);
     return true;
 }
@@ -380,7 +378,7 @@ lkt_callback_send_row_v1(void *_args, int pos_len, int pos, int id, int id_len,
     struct lkt_callback *args = (struct lkt_callback *) _args;
     struct lkt_message *out;
     out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%*d: %*d %s\n", pos_len, pos, id_len, id, sql_row);
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX, "%*d: %*d %s\n", pos_len, pos, id_len, id, sql_row);
     lkt_state_send(args->srv, args->c, out);
     return true;
 }
@@ -389,7 +387,7 @@ bool
 lkt_callback_send_row_v2(struct lkt_state *srv, size_t c, int id, int id_len, const char *sql_row)
 {
     struct lkt_message *out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%*d %s\n", id_len, id, sql_row);
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX, "%*d %s\n", id_len, id, sql_row);
     lkt_state_send(srv, c, out);
     return true;
 }
@@ -723,7 +721,7 @@ static bool
 sticker_send(struct lkt_state *srv, size_t c, char *name, int id, int value)
 {
     struct lkt_message *msg = lkt_message_new();
-    msg->data_len = snprintf(msg->data, LKT_MESSAGE_ARGS_MAX, "%d: %s . %d", id, name, value);
+    msg->data_len = safe_snprintf(msg->data, LKT_MESSAGE_ARGS_MAX, "%d: %s . %d", id, name, value);
     lkt_state_send(srv, c, msg);
     return true;
 }
diff --git a/src/common.c b/src/common.c
index f301ac07..636bf3d5 100644
--- a/src/common.c
+++ b/src/common.c
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 #include <sys/stat.h>
 
 void
@@ -157,3 +158,14 @@ read_self_exe(char *path, size_t len)
            (readlink(SELF_EXECUTABLE_FREEBSD, path, len - 1) > 0) ||
            (readlink(SELF_EXECUTABLE_SOLARIS, path, len - 1) > 0);
 }
+
+int
+safe_snprintf(char *dest, const size_t max_len, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    int ret = vsnprintf(dest, max_len, format, ap);
+    dest[max_len - 1] = '\0';
+    va_end(ap);
+    return ret;
+}
diff --git a/src/database/config.c b/src/database/config.c
index 00c82c62..eb09db85 100644
--- a/src/database/config.c
+++ b/src/database/config.c
@@ -119,8 +119,7 @@ database_config_queue(volatile sqlite3 *db, const char *option, int value)
     if (value > 100)
         value = 100;
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TMP, option);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TMP, option);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     SQLITE_BIND_INT(db, stmt, 1, value, error);
 
@@ -162,8 +161,7 @@ database_get_config(volatile sqlite3 *db, const char *option, int *value)
     sqlite3_stmt *stmt = 0;
     bool ret = false;
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TMP, option);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TMP, option);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     SQLITE_STEP_ROW(db, stmt, error);
     *value = sqlite3_column_int(stmt, 0);
diff --git a/src/database/find.c b/src/database/find.c
index c31a1ab6..8cab8488 100644
--- a/src/database/find.c
+++ b/src/database/find.c
@@ -22,9 +22,7 @@ database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret)
     ret->type = lkt_search_database;
 
     /* Search part */
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TEMPLATE, ret->name,
-             ret->msg_count, ret->continuation);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TEMPLATE, ret->name, ret->msg_count, ret->continuation);
     SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error);
     SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->ka_rgx, error);
     ret->db = db;
@@ -89,9 +87,7 @@ database_search_queue_init(volatile sqlite3 *db, struct lkt_search *ret)
     ret->type = lkt_search_queue;
 
     /* Search part */
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TEMPLATE, ret->name,
-             ret->msg_count, ret->continuation);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TEMPLATE, ret->name, ret->msg_count, ret->continuation);
     SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error);
     SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->ka_rgx, error);
     ret->db = db;
diff --git a/src/database/open.c b/src/database/open.c
index 24b9fec3..9c288868 100644
--- a/src/database/open.c
+++ b/src/database/open.c
@@ -78,8 +78,7 @@ __attach(volatile sqlite3 *db, const char *name, const char *path)
     char SQL_ATTACH[LKT_MAX_SQLITE_STATEMENT];
     bool ret = false;
 
-    snprintf(SQL_ATTACH, LKT_MAX_SQLITE_STATEMENT - 1, SQL_ATTACH_TEMPLATE, path, name);
-    SQL_ATTACH[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_ATTACH, LKT_MAX_SQLITE_STATEMENT, SQL_ATTACH_TEMPLATE, path, name);
     SQLITE_EXEC(db, SQL_ATTACH, err_no_attach);
     LOG_INFO_SCT("DB", "Attached database '%s' with path '%s'", name, path);
     ret = true;
@@ -94,8 +93,7 @@ __detach(volatile sqlite3 *db, const char *name)
     char SQL_DETACH[LKT_MAX_SQLITE_STATEMENT];
     bool ret = false;
 
-    snprintf(SQL_DETACH, LKT_MAX_SQLITE_STATEMENT - 1, SQL_DETACH_TEMPLATE, name);
-    SQL_DETACH[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_DETACH, LKT_MAX_SQLITE_STATEMENT, SQL_DETACH_TEMPLATE, name);
     SQLITE_EXEC(db, SQL_DETACH, err_no_detach);
     LOG_INFO_SCT("DB", "Detached database '%s'", name);
     ret = true;
diff --git a/src/database/playlist.c b/src/database/playlist.c
index 96f704f0..a805e47b 100644
--- a/src/database/playlist.c
+++ b/src/database/playlist.c
@@ -108,8 +108,7 @@ database_plt_export(volatile sqlite3 *db, const char *name)
     GOTO_UNLESS(strcasecmp(name, PROTECTED_DATABASE), "Name '"PROTECTED_DATABASE
                 "' is protected, you can't use it for a playlist name", error);
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_SCHEM, name);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_SCHEM, name);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     code = sqlite3_step(stmt);
 
@@ -141,8 +140,7 @@ database_plt_import(volatile sqlite3 *db, const char *name)
     GOTO_UNLESS(strcasecmp(name, PROTECTED_DATABASE), "Name '"PROTECTED_DATABASE
                 "' is protected, you can't use it for a playlist name", error);
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_SCHEM, name, name, name);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_SCHEM, name, name, name);
     SQLITE_EXEC(db, SQL_STMT, error);
     ret = true;
 error:
@@ -184,8 +182,7 @@ database_plt_add_uri(volatile sqlite3 *db, const char *name, struct lkt_uri *uri
         return false;
     }
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL, column);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL, column);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     SQLITE_BIND_TEXT(db, stmt, 1, name, error);
     SQLITE_BIND_TEXT(db, stmt, 2, (char *) uri->value, error);
diff --git a/src/database/queue.c b/src/database/queue.c
index c0cf57fd..9de49722 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -126,8 +126,7 @@ queue_add_with_col_like_str(volatile sqlite3 *db, const char *col, const char *v
     SQLITE_EXEC(db, "BEGIN TRANSACTION;", error);
 
     /* Insert at the end of the queue */
-    snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT, col);
-    SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_STMT, col);
     SQLITE_PREPARE(db, stmt, SQL, error);
     SQLITE_BIND_INT(db, stmt, 1, priority, error);
     SQLITE_BIND_TEXT(db, stmt, 2, val, error);
@@ -262,8 +261,7 @@ database_queue_del_id(volatile sqlite3 *db, int id)
         "COMMIT TRANSACTION;";
 #undef POS_OF_ID
     char SQL[LKT_MAX_SQLITE_STATEMENT];
-    snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_TEMPLATE, id, id, id, id);
-    SQL[LKT_MAX_SQLITE_STATEMENT - 1] = '\0';
+    safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE, id, id, id, id);
     SQLITE_EXEC(db, SQL, error);
     return true;
 error:
@@ -295,8 +293,7 @@ database_queue_next(volatile sqlite3 *db, char filepath[PATH_MAX])
 
     if (code == SQLITE_ROW) {
         id = MAX(1, sqlite3_column_int(stmt, 1));
-        snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT - 1, "UPDATE queue_state SET current = %d;", id);
-        SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+        safe_snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT, "UPDATE queue_state SET current = %d;", id);
 
         if (filepath != NULL)
             strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
@@ -355,8 +352,7 @@ database_queue_prev(volatile sqlite3 *db, char filepath[PATH_MAX])
 
     if (code == SQLITE_ROW) {
         id = MAX(1, sqlite3_column_int(stmt, 1));
-        snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT - 1, "UPDATE queue_state SET current = %d;", id);
-        SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+        safe_snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT, "UPDATE queue_state SET current = %d;", id);
 
         if (filepath != NULL)
             strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
@@ -490,9 +486,8 @@ database_queue_set_current_index(volatile sqlite3 *db, int idx)
         return false;
     }
 
-    RETURN_IF(snprintf(SQL_GET, LKT_MAX_SQLITE_STATEMENT - 1, SQL_GET_TEMPLATE, idx) < 0, "Snprintf failed",
-              false);
-    SQL_GET[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    RETURN_IF(safe_snprintf(SQL_GET, LKT_MAX_SQLITE_STATEMENT, SQL_GET_TEMPLATE, idx) < 0,
+              "Snprintf failed", false);
     SQLITE_EXEC(db, SQL_GET, error);
     return true;
 error:
diff --git a/src/database/stickers.c b/src/database/stickers.c
index bc49c603..a0a7c7f0 100644
--- a/src/database/stickers.c
+++ b/src/database/stickers.c
@@ -99,9 +99,8 @@ database_sticker_delete_specify(volatile sqlite3 *db, const char *type, int uri,
         return false;
     }
 
-    snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, "DELETE FROM 'stickers.%s' "
+    safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, "DELETE FROM 'stickers.%s' "
              "WHERE 'stickers.%s' = ? ", type, type);
-    SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
 
     /* If there is a name specified. */
     if (!name) {
diff --git a/src/database/update.c b/src/database/update.c
index 9f5e840e..145a6019 100644
--- a/src/database/update.c
+++ b/src/database/update.c
@@ -27,7 +27,7 @@ database_add_kara(volatile sqlite3 *db, const char *filename)
     time_t the_time = time(NULL);
     struct tm *the_local_time = localtime(&the_time);
     char year[10];
-    code = snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
+    code = safe_snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
     RETURN_IF(code < 0 || code >= 10, "Failed to get the year of the current date", false);
 
     if (kara_metadata_read(&data, filename) != 0) {
@@ -89,7 +89,7 @@ database_update_add(volatile sqlite3 *db, const char *kara_path, struct kara_met
     time_t the_time = time(NULL);
     struct tm *the_local_time = localtime(&the_time);
     char year[10];
-    code = snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
+    code = safe_snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
     GOTO_IF(code < 0 || code >= 10, "Failed to get the year of the current date", error_no_sqlite);
 
     /* From here we initialize the sqlite stmt. */
diff --git a/src/main/lkt.c b/src/main/lkt.c
index 0d27efe2..87282296 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -59,19 +59,14 @@ static const char *LKT_QUEUE_DEFAULT[] = { "10" };
 static int
 lkt_valid_type(const char *type)
 {
-    return (STR_MATCH(type, "all")      ||
-            STR_MATCH(type, "any")      ||
-            STR_MATCH(type, "query")    ||
+    return (STR_MATCH(type, "all") || STR_MATCH(type, "any") || STR_MATCH(type, "query")    ||
+            STR_MATCH(type, "cat") || STR_MATCH(type, "category")                           ||
+            STR_MATCH(type, "author") || STR_MATCH(type, "auth")                            ||
+            STR_MATCH(type, "lang") || STR_MATCH(type, "language")                          ||
             STR_MATCH(type, "id")       ||
             STR_MATCH(type, "title")    ||
             STR_MATCH(type, "type")     ||
-            STR_MATCH(type, "cat")      ||
-            STR_MATCH(type, "category") ||
-            STR_MATCH(type, "author")   ||
-            STR_MATCH(type, "auth")     ||
-            STR_MATCH(type, "source")   ||
-            STR_MATCH(type, "lang")     ||
-            STR_MATCH(type, "language"));
+            STR_MATCH(type, "source"));
 }
 
 static int
@@ -665,8 +660,7 @@ queue_list__(struct lkt_cmd_args *args)
 
     continuation = labs(continuation);
     song_index = MAX(song_index + 1, 1);
-    snprintf(buff, LKT_MESSAGE_MAX - 1, "%ld:%ld", song_index, song_index + continuation - 1);
-    buff[LKT_MESSAGE_MAX - 1] = '\0';
+    safe_snprintf(buff, LKT_MESSAGE_MAX, "%ld:%ld", song_index, song_index + continuation - 1);
     args->argc = 1;
     args->argv[0] = buff;
     queue_pos__(args);
diff --git a/src/module/mpv.c b/src/module/mpv.c
index 30c8d5a7..3f101b9c 100644
--- a/src/module/mpv.c
+++ b/src/module/mpv.c
@@ -89,7 +89,7 @@ lmpv_set_volume(mpv_handle *ctx, int vol)
     int status;
     char str[5];
     memset(str, 0, 5);
-    snprintf(str, 4, "%d", vol);
+    safe_snprintf(str, 4, "%d", vol);
     const char *cmd[] = {"set", "ao-volume", str, NULL};
     if ((status = mpv_command_async(ctx, 0, cmd)) < 0) {
         LOG_ERROR_SCT("WINDOW", "Failed to execute command: %s", mpv_error_string(status));
diff --git a/src/net/downloader.c b/src/net/downloader.c
index 9df9b1ba..9645a50b 100644
--- a/src/net/downloader.c
+++ b/src/net/downloader.c
@@ -184,8 +184,7 @@ repo_get_id(struct lkt_repo *const repo, const uint64_t id, struct kara_metadata
     };
 
     memset(url, 0, URL_MAX_LEN * sizeof(char));
-    snprintf(url, URL_MAX_LEN - 1, repo->get_id_json, id);
-    url[URL_MAX_LEN - 1] = 0;
+    safe_snprintf(url, URL_MAX_LEN, repo->get_id_json, id);
     curl_handle = curl_easy_init();
     curl_easy_setopt(curl_handle, CURLOPT_URL, url);
     curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_mem__);
@@ -315,8 +314,7 @@ repo_download_id_sync(struct lkt_repo *const repo, const uint64_t id, const char
     }
 
     memset(url, 0, URL_MAX_LEN * sizeof(char));
-    snprintf(url, URL_MAX_LEN - 1, repo->get_id_file, id);
-    url[URL_MAX_LEN - 1] = 0;
+    safe_snprintf(url, URL_MAX_LEN, repo->get_id_file, id);
 
     if (__download_kara(url, kara_path, false)) {
         LOG_ERROR_SCT("REPO", "Failed to download kara '%s' with url '%s'", kara_path, url);
@@ -363,8 +361,7 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec
             strncat(kara->filename, "/", PATH_MAX - 1);
             kara->filename[++kara_dir_len] = 0;
         }
-        snprintf(kara->filename + kara_dir_len, PATH_MAX - kara_dir_len, "%d.mkv", integer);
-        kara->filename[PATH_MAX - 1] = 0;
+        safe_snprintf(kara->filename + kara_dir_len, PATH_MAX - kara_dir_len, "%d.mkv", integer);
         LOG_INFO_SCT("REPO", "Crafted filename is '%s'", kara->filename);
 
         /* Timestamp verification */
@@ -397,8 +394,7 @@ do_it:
             continue;
         }
 
-        snprintf(url, URL_MAX_LEN - 1, repo->get_id_file, kara->id);
-        url[URL_MAX_LEN - 1] = '\0';
+        safe_snprintf(url, URL_MAX_LEN, repo->get_id_file, kara->id);
 
         if (__download_kara(url, kara->filename, true)) {
             LOG_WARN_SCT("REPO", "Could not download kara %ld at path '%s'", kara->id, kara->filename);
diff --git a/src/net/listen.c b/src/net/listen.c
index 2e6da642..84ec3db3 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -86,8 +86,7 @@ static inline void
 send_continue(struct lkt_state *srv, size_t c, int i)
 {
     struct lkt_message *cont = lkt_message_new();
-    cont->data_len = snprintf(cont->data, LKT_MESSAGE_MAX, "continue: %d\n", i);
-    cont->data[LKT_MESSAGE_MAX - 1] = '\0';
+    cont->data_len = safe_snprintf(cont->data, LKT_MESSAGE_MAX, "continue: %d\n", i);
     lkt_state_send(srv, c, cont);
 }
 
diff --git a/src/uri.c b/src/uri.c
index ec076ed2..4f6fe569 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -98,19 +98,19 @@ __lkt_to_str(struct lkt_uri *uri, char *ret, size_t len)
 {
     switch (uri->type) {
     case uri_id:
-        snprintf(ret, len - 1, "id=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "id=%s", (char *) uri->value);
         break;
     case uri_type:
-        snprintf(ret, len - 1, "type=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "type=%s", (char *) uri->value);
         break;
     case uri_author:
-        snprintf(ret, len - 1, "author=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "author=%s", (char *) uri->value);
         break;
     case uri_category:
-        snprintf(ret, len - 1, "cat=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "cat=%s", (char *) uri->value);
         break;
     case uri_query:
-        snprintf(ret, len - 1, "search=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "search=%s", (char *) uri->value);
         break;
     default:
         LOG_ERROR("URI type %d may not be supported by kurisu, generate an error", uri->type);
-- 
GitLab