From eaf2e51b0c33226f1acf75323e69cb4c5498d626 Mon Sep 17 00:00:00 2001 From: Peter Keresztes Schmidt Date: Fri, 25 Jun 2021 23:48:35 +0200 Subject: [PATCH] utils: Make sure the compiler can emit format warnings for stringtf Unfortunately the compilers can't emit Wformat warnings for variadic templates and those can't be annotated with the format attribute. Use a variadic function which can be annotated and thus warns on format string-args mismatches. Ref 0796a2262e43936ba50a631bb899a841652c2f76 --- src/zm_event.cpp | 4 ++-- src/zm_eventstream.cpp | 10 +++++----- src/zm_logger.cpp | 4 ++-- src/zm_utils.cpp | 21 +++++++++++++++++++++ src/zm_utils.h | 12 ++---------- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index b0215662a..be9e26a00 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -518,7 +518,7 @@ void Event::AddFrame(Image *image, if (image) { if (save_jpegs & 1) { - std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames); + std::string event_file = stringtf(staticConfig.capture_file_format.c_str(), path.c_str(), frames); Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str()); if (!WriteFrameImage(image, timestamp, event_file.c_str())) { Error("Failed to write frame image"); @@ -548,7 +548,7 @@ void Event::AddFrame(Image *image, } if (alarm_image and (save_jpegs & 2)) { - std::string event_file = stringtf(staticConfig.analyse_file_format, path.c_str(), frames); + std::string event_file = stringtf(staticConfig.analyse_file_format.c_str(), path.c_str(), frames); Debug(1, "Writing analysis frame %d", frames); if (!WriteFrameImage(alarm_image, timestamp, event_file.c_str(), true)) { Error("Failed to write analysis frame image"); diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 0b501149c..6f017c0bc 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -44,7 +44,7 @@ constexpr Milliseconds EventStream::STREAM_PAUSE_WAIT; bool EventStream::loadInitialEventData(int monitor_id, SystemTimePoint event_time) { std::string sql = stringtf("SELECT `Id` FROM `Events` WHERE " "`MonitorId` = %d AND unix_timestamp(`EndDateTime`) > %ld " - "ORDER BY `Id` ASC LIMIT 1", monitor_id, event_time); + "ORDER BY `Id` ASC LIMIT 1", monitor_id, std::chrono::system_clock::to_time_t(event_time)); MYSQL_RES *result = zmDbFetch(sql.c_str()); if (!result) @@ -687,7 +687,7 @@ bool EventStream::checkEventLoaded() { } // void EventStream::checkEventLoaded() Image * EventStream::getImage( ) { - std::string path = stringtf(staticConfig.capture_file_format, event_data->path.c_str(), curr_frame_id); + std::string path = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id); Debug(2, "EventStream::getImage path(%s) from %s frame(%ld) ", path.c_str(), event_data->path.c_str(), curr_frame_id); Image *image = new Image(path.c_str()); return image; @@ -702,12 +702,12 @@ bool EventStream::sendFrame(Microseconds delta_us) { // This needs to be abstracted. If we are saving jpgs, then load the capture file. // If we are only saving analysis frames, then send that. if (event_data->SaveJPEGs & 1) { - filepath = stringtf(staticConfig.capture_file_format, event_data->path.c_str(), curr_frame_id); + filepath = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id); } else if (event_data->SaveJPEGs & 2) { - filepath = stringtf(staticConfig.analyse_file_format, event_data->path.c_str(), curr_frame_id); + filepath = stringtf(staticConfig.analyse_file_format.c_str(), event_data->path.c_str(), curr_frame_id); if (stat(filepath.c_str(), &filestat) < 0) { Debug(1, "analyze file %s not found will try to stream from other", filepath.c_str()); - filepath = stringtf(staticConfig.capture_file_format, event_data->path.c_str(), curr_frame_id); + filepath = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id); if (stat(filepath.c_str(), &filestat) < 0) { Debug(1, "capture file %s not found either", filepath.c_str()); filepath = ""; diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 580043488..993855e35 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -528,8 +528,8 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const "INSERT INTO `Logs` " "( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )" " VALUES " - "( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", - now_sec, now_frac.count(), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, + "( %ld.%06" PRIi64 ", '%s', %d, %d, %d, '%s', '%s', '%s', %d )", + now_sec, static_cast(now_frac.count()), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString.c_str(), file, line); dbQueue.push(std::move(sql_string)); } else { diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index 58726778e..5da5509ff 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -22,6 +22,7 @@ #include "zm_config.h" #include "zm_logger.h" #include +#include #include #include /* Definition of AT_* constants */ #include @@ -116,6 +117,26 @@ std::string Join(const StringVector &values, const std::string &delim) { return ss.str(); } +std::string stringtf(const char* format, ...) { + va_list args; + va_start(args, format); + va_list args2; + va_copy(args2, args); + + int size = vsnprintf(nullptr, 0, format, args) + 1; // Extra space for '\0' + va_end(args); + + if (size <= 0) { + throw std::runtime_error("Error during formatting."); + } + + std::unique_ptr buf(new char[size]); + vsnprintf(buf.get(), size, format, args2); + va_end(args2); + + return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside +} + std::string ByteArrayToHexString(nonstd::span bytes) { static constexpr char lowercase_table[] = "0123456789abcdef"; std::string buf; diff --git a/src/zm_utils.h b/src/zm_utils.h index f4af1f1d4..d5ee88202 100644 --- a/src/zm_utils.h +++ b/src/zm_utils.h @@ -61,16 +61,8 @@ inline bool StartsWith(const std::string &haystack, const std::string &needle) { return (haystack.substr(0, needle.length()) == needle); } -template -std::string stringtf(const std::string &format, Args... args) { - int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' - if (size <= 0) { - throw std::runtime_error("Error during formatting."); - } - std::unique_ptr buf(new char[size]); - snprintf(buf.get(), size, format.c_str(), args...); - return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside -} +__attribute__((format(printf, 1, 2))) +std::string stringtf(const char* format, ...); std::string ByteArrayToHexString(nonstd::span bytes);