From d6396c425208fcbd061560d26e6c86b62d63ba66 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 2 Feb 2025 15:39:18 +0800 Subject: [PATCH 01/23] PCPProcessTable_updateCmdline() minor logic adjustment Reorder a conditional to prevent an unnecessary negative array offset access. The compiled behavior should be exactly the same. Signed-off-by: Kang-Che Sung --- pcp/PCPProcessTable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcp/PCPProcessTable.c b/pcp/PCPProcessTable.c index 4999bdc27..024bef55f 100644 --- a/pcp/PCPProcessTable.c +++ b/pcp/PCPProcessTable.c @@ -314,10 +314,10 @@ static void PCPProcessTable_updateCmdline(Process* process, int pid, int offset, if (command[0] != '(') { process->isKernelThread = false; } else { - ++command; - --length; if (command[length - 1] == ')') command[--length] = '\0'; + ++command; + --length; process->isKernelThread = true; } From 97ad9181a1018bde358f34c17668530e01a6ab39 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 03:45:46 +0800 Subject: [PATCH 02/23] Correct code commment in matchCmdlinePrefixWithExeSuffix() No code changes. Fix an error by commit 94a52cb5c9274fe021b3fc114180294cadb598b4 that accidentally replaced a keyword in comment to "cmdlineBasenameEnd". According to the context it should refer to "cmdlineBasenameStart" instead. --- Process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Process.c b/Process.c index 910443e99..d70034668 100644 --- a/Process.c +++ b/Process.c @@ -121,7 +121,7 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseO * that make htop's identification of the basename in cmdline unreliable. * For e.g. /usr/libexec/gdm-session-worker modifies its cmdline to * "gdm-session-worker [pam/gdm-autologin]" and htop ends up with - * proccmdlineBasenameEnd at "gdm-autologin]". This issue could arise with + * cmdlineBasenameStart at "gdm-autologin]". This issue could arise with * chrome as well as it stores in cmdline its concatenated argument vector, * without NUL delimiter between the arguments (which may contain a '/') * From 3ff96b03d4b2fb8e3dfd84673beccb20bbe37442 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 03:56:49 +0800 Subject: [PATCH 03/23] Minor code style adjustment in matchCmdlinePrefixWithExeSuffix() Improve readability of local variables. Signed-off-by: Kang-Che Sung --- Process.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Process.c b/Process.c index d70034668..0ea605708 100644 --- a/Process.c +++ b/Process.c @@ -101,13 +101,12 @@ static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdline static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseOffset, const char* exe, int exeBaseOffset, int exeBaseLen) { int matchLen; /* matching length to be returned */ - char delim; /* delimiter following basename */ /* cmdline prefix is an absolute path: it must match whole exe. */ if (cmdline[0] == '/') { matchLen = exeBaseLen + exeBaseOffset; if (strncmp(cmdline, exe, matchLen) == 0) { - delim = cmdline[matchLen]; + char delim = cmdline[matchLen]; if (delim == 0 || delim == '\n' || delim == ' ') { return matchLen; } @@ -127,13 +126,13 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseO * * So if needed, we adjust cmdlineBaseOffset to the previous (if any) * component of the cmdline relative path, and retry the procedure. */ - bool delimFound; /* if valid basename delimiter found */ + bool delimFound = true; /* if valid basename delimiter found */ do { /* match basename */ matchLen = exeBaseLen + cmdlineBaseOffset; if (cmdlineBaseOffset < exeBaseOffset && strncmp(cmdline + cmdlineBaseOffset, exe + exeBaseOffset, exeBaseLen) == 0) { - delim = cmdline[matchLen]; + char delim = cmdline[matchLen]; if (delim == 0 || delim == '\n' || delim == ' ') { int i, j; /* reverse match the cmdline prefix and exe suffix */ @@ -149,7 +148,8 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseO /* Try to find the previous potential cmdlineBaseOffset - it would be * preceded by '/' or nothing, and delimited by ' ' or '\n' */ - for (delimFound = false, cmdlineBaseOffset -= 2; cmdlineBaseOffset > 0; --cmdlineBaseOffset) { + delimFound = false; + for (cmdlineBaseOffset -= 2; cmdlineBaseOffset > 0; --cmdlineBaseOffset) { if (delimFound) { if (cmdline[cmdlineBaseOffset - 1] == '/') { break; From aa2116ba2d8a12df040df374f1850db48bfef5a3 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 04:26:10 +0800 Subject: [PATCH 04/23] Code simplification in Process_makeCommandStr() Store the "cmdlineBasenameLen" and "commLen" local variables rather than "cmdlineBasenameEnd" and "commEnd". Signed-off-by: Kang-Che Sung --- Process.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Process.c b/Process.c index 0ea605708..a0ee33e83 100644 --- a/Process.c +++ b/Process.c @@ -64,7 +64,7 @@ void Process_fillStarttimeBuffer(Process* this) { */ #define TASK_COMM_LEN 16 -static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdlineBasenameStart, int* pCommStart, int* pCommEnd) { +static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdlineBasenameStart, int* pCommStart, int* pCommLen) { /* Try to find procComm in tokenized cmdline - this might in rare cases * mis-identify a string or fail, if comm or cmdline had been unsuitably * modified by the process */ @@ -86,7 +86,7 @@ static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdline if ((tokenLen == commLen || (tokenLen > commLen && commLen == (TASK_COMM_LEN - 1))) && strncmp(tokenBase, comm, commLen) == 0) { *pCommStart = tokenBase - cmdline; - *pCommEnd = token - cmdline; + *pCommLen = tokenLen; return true; } @@ -310,11 +310,13 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { char* str = strStart; int cmdlineBasenameStart = this->cmdlineBasenameStart; - int cmdlineBasenameEnd = this->cmdlineBasenameEnd; + int cmdlineBasenameLen = 0; + if (this->cmdlineBasenameEnd > this->cmdlineBasenameStart) + cmdlineBasenameLen = this->cmdlineBasenameEnd - this->cmdlineBasenameStart; if (!cmdline) { cmdlineBasenameStart = 0; - cmdlineBasenameEnd = 0; + cmdlineBasenameLen = 0; cmdline = "(zombie)"; } @@ -337,13 +339,13 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { if (shadowDistPathPrefix && showProgramPath) CHECK_AND_MARK_DIST_PATH_PREFIXES(cmdline); - if (cmdlineBasenameEnd > cmdlineBasenameStart) - WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); + if (cmdlineBasenameLen > 0) + WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); if (this->procExeDeleted) - WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); else if (this->usesDeletedLib) - WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); (void)stpcpyWithNewlineConversion(str, cmdline + (showProgramPath ? 0 : cmdlineBasenameStart)); @@ -387,12 +389,12 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { bool haveCommInCmdline = false; int commStart = 0; - int commEnd = 0; + int commLen = 0; /* Try to match procComm with procExe's basename: This is reliable (predictable) */ if (searchCommInCmdline) { - /* commStart/commEnd will be adjusted later along with cmdline */ - haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd); + /* commStart/commLen will be adjusted later along with cmdline */ + haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commLen); } int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen); @@ -412,7 +414,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { cmdline += matchLen; commStart -= matchLen; - commEnd -= matchLen; } else { matchLen = 0; } @@ -427,7 +428,7 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { CHECK_AND_MARK_DIST_PATH_PREFIXES(cmdline); if (!haveCommInExe && haveCommInCmdline && !haveCommField && (!Process_isUserlandThread(this) || showThreadNames)) - WRITE_HIGHLIGHT(commStart, commEnd - commStart, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); + WRITE_HIGHLIGHT(commStart, commLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); /* Display cmdline if it hasn't been consumed by procExe */ if (*cmdline) From 188c6899bf284f3f0269e4ebeda24b859c16df40 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 04:28:00 +0800 Subject: [PATCH 05/23] Don't make highlights of zero-length cmdline basename Adjust logic in Process_makeCommandStr() so that if the process "cmdline" basename has a length of zero, skip creating all of the highlights of that basename. Signed-off-by: Kang-Che Sung --- Process.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Process.c b/Process.c index a0ee33e83..d45245518 100644 --- a/Process.c +++ b/Process.c @@ -339,13 +339,14 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { if (shadowDistPathPrefix && showProgramPath) CHECK_AND_MARK_DIST_PATH_PREFIXES(cmdline); - if (cmdlineBasenameLen > 0) + if (cmdlineBasenameLen > 0) { WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); - if (this->procExeDeleted) - WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); - else if (this->usesDeletedLib) - WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + if (this->procExeDeleted) + WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + else if (this->usesDeletedLib) + WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + } (void)stpcpyWithNewlineConversion(str, cmdline + (showProgramPath ? 0 : cmdlineBasenameStart)); From 6abf1ca635688c8f8f5edf882fb49cb7bbd03d26 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 04:36:43 +0800 Subject: [PATCH 06/23] Improve process cmdline basename matching with procExe path The matchCmdlinePrefixWithExeSuffix() internal function (in Process.c) can match basenames in multiple tries in case the "cmdlineBasenameStart" input value is unreliable. Take advantage of this and update "cmdlineBasenameStart" with the new offset detected by the function. Also make the matching behavior consistent regardless of "showMergedCommand" setting. Signed-off-by: Kang-Che Sung --- Process.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/Process.c b/Process.c index d45245518..b81830e0b 100644 --- a/Process.c +++ b/Process.c @@ -99,7 +99,7 @@ static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdline return false; } -static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseOffset, const char* exe, int exeBaseOffset, int exeBaseLen) { +static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int* cmdlineBasenameStart, const char* exe, int exeBaseOffset, int exeBaseLen) { int matchLen; /* matching length to be returned */ /* cmdline prefix is an absolute path: it must match whole exe. */ @@ -126,6 +126,7 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseO * * So if needed, we adjust cmdlineBaseOffset to the previous (if any) * component of the cmdline relative path, and retry the procedure. */ + int cmdlineBaseOffset = *cmdlineBasenameStart; bool delimFound = true; /* if valid basename delimiter found */ do { /* match basename */ @@ -141,8 +142,10 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseO ; /* full match, with exe suffix being a valid relative path */ - if (i < 0 && j >= 0 && exe[j] == '/') + if (i < 0 && j >= 0 && exe[j] == '/') { + *cmdlineBasenameStart = cmdlineBaseOffset; return matchLen; + } } } @@ -323,6 +326,26 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { assert(cmdlineBasenameStart >= 0); assert(cmdlineBasenameStart <= (int)strlen(cmdline)); + int exeLen = 0; + int exeBasenameOffset = 0; + int exeBasenameLen = 0; + int matchLen = 0; + if (procExe) { + exeLen = strlen(procExe); + exeBasenameOffset = this->procExeBasenameOffset; + exeBasenameLen = exeLen - exeBasenameOffset; + + assert(exeBasenameOffset >= 0); + assert(exeBasenameOffset <= (int)strlen(procExe)); + + if (this->cmdline) { + matchLen = matchCmdlinePrefixWithExeSuffix(this->cmdline, &cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen); + } + if (matchLen) { + cmdlineBasenameLen = exeBasenameLen; + } + } + if (!showMergedCommand || !procExe || !procComm) { /* fall back to cmdline */ if ((showMergedCommand || (Process_isUserlandThread(this) && showThreadNames)) && procComm && strlen(procComm)) { /* set column to or prefix it with comm */ if (strncmp(cmdline + cmdlineBasenameStart, procComm, MINIMUM(TASK_COMM_LEN - 1, strlen(procComm))) != 0) { @@ -353,13 +376,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { return; } - int exeLen = strlen(this->procExe); - int exeBasenameOffset = this->procExeBasenameOffset; - int exeBasenameLen = exeLen - exeBasenameOffset; - - assert(exeBasenameOffset >= 0); - assert(exeBasenameOffset <= (int)strlen(procExe)); - bool haveCommInExe = false; if (procExe && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { haveCommInExe = strncmp(procExe + exeBasenameOffset, procComm, TASK_COMM_LEN - 1) == 0; @@ -398,8 +414,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commLen); } - int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen); - bool haveCommField = false; if (!haveCommInExe && !haveCommInCmdline && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { From c6dad0c278e1f4c857224c36e691780d3331f086 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 04:58:36 +0800 Subject: [PATCH 07/23] Improve "comm" string highlighting in Process_makeCommandStr() Add a special case when the process "comm" string is found in "cmdline", but at the starting basename position that would be stripped by "stripExeFromCmdline" setting. This special case will now highlight the basename of "exe" string as well as the first token of "cmdline" (as the two strings are concatenated together when displaying). Signed-off-by: Kang-Che Sung --- Process.c | 56 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/Process.c b/Process.c index b81830e0b..ccfbbbc22 100644 --- a/Process.c +++ b/Process.c @@ -376,17 +376,48 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { return; } + int commLen = 0; + bool haveCommInExe = false; if (procExe && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { haveCommInExe = strncmp(procExe + exeBasenameOffset, procComm, TASK_COMM_LEN - 1) == 0; } + if (haveCommInExe) { + commLen = exeBasenameLen; + } + + bool haveCommInCmdline = false; + int commStart = 0; + + if (!haveCommInExe && this->cmdline && procComm && searchCommInCmdline && (!Process_isUserlandThread(this) || showThreadNames)) { + haveCommInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commLen); + } + + if (!stripExeFromCmdline) { + matchLen = 0; + } + if (matchLen) { + /* strip the matched exe prefix */ + cmdline += matchLen; + + if (haveCommInCmdline) { + if (commStart == cmdlineBasenameStart) { + haveCommInExe = true; + haveCommInCmdline = false; + commStart = 0; + } else { + assert(commStart >= matchLen); + commStart -= matchLen; + } + } + } /* Start with copying exe */ if (showProgramPath) { if (shadowDistPathPrefix) CHECK_AND_MARK_DIST_PATH_PREFIXES(procExe); if (haveCommInExe) - WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); + WRITE_HIGHLIGHT(exeBasenameOffset, commLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); if (this->procExeDeleted) WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); @@ -395,7 +426,7 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { str = stpcpy(str, procExe); } else { if (haveCommInExe) - WRITE_HIGHLIGHT(0, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); + WRITE_HIGHLIGHT(0, commLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); WRITE_HIGHLIGHT(0, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); if (this->procExeDeleted) WRITE_HIGHLIGHT(0, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); @@ -404,16 +435,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { str = stpcpy(str, procExe + exeBasenameOffset); } - bool haveCommInCmdline = false; - int commStart = 0; - int commLen = 0; - - /* Try to match procComm with procExe's basename: This is reliable (predictable) */ - if (searchCommInCmdline) { - /* commStart/commLen will be adjusted later along with cmdline */ - haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commLen); - } - bool haveCommField = false; if (!haveCommInExe && !haveCommInCmdline && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { @@ -423,17 +444,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { haveCommField = true; } - if (matchLen) { - if (stripExeFromCmdline) { - /* strip the matched exe prefix */ - cmdline += matchLen; - - commStart -= matchLen; - } else { - matchLen = 0; - } - } - if (!matchLen || (haveCommField && *cmdline)) { /* cmdline will be a separate field */ WRITE_SEPARATOR; From 51de96301b700c0ea8a4a445b1ca88cb68a81df1 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 3 Feb 2025 05:37:41 +0800 Subject: [PATCH 08/23] Process: Use size_t for "cmdline" and "procExe" offsets Convert the members "cmdlineBasenameStart", "cmdlineBasenameEnd" and "procExeBasenameOffset" in "Process" to size_t type. Also upgrade many routines that search for "basenames", COMM, and PROC_EXE string to use size_t for iterators. The "cmdlineBasenameEnd" value is no longer allowed to negative. It is now set to 0 during Process_init(). Signed-off-by: Kang-Che Sung --- Process.c | 71 ++++++++++++------------- Process.h | 8 +-- darwin/DarwinProcess.c | 6 +-- dragonflybsd/DragonFlyBSDProcessTable.c | 8 +-- freebsd/FreeBSDProcessTable.c | 8 +-- linux/LinuxProcessTable.c | 50 ++++++++--------- netbsd/NetBSDProcessTable.c | 10 ++-- openbsd/OpenBSDProcessTable.c | 10 ++-- pcp/PCPProcessTable.c | 8 +-- 9 files changed, 88 insertions(+), 91 deletions(-) diff --git a/Process.c b/Process.c index ccfbbbc22..573404056 100644 --- a/Process.c +++ b/Process.c @@ -64,7 +64,7 @@ void Process_fillStarttimeBuffer(Process* this) { */ #define TASK_COMM_LEN 16 -static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdlineBasenameStart, int* pCommStart, int* pCommLen) { +static bool findCommInCmdline(const char* comm, const char* cmdline, size_t cmdlineBasenameStart, size_t* pCommStart, size_t* pCommLen) { /* Try to find procComm in tokenized cmdline - this might in rare cases * mis-identify a string or fail, if comm or cmdline had been unsuitably * modified by the process */ @@ -72,20 +72,17 @@ static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdline size_t tokenLen; const size_t commLen = strlen(comm); - if (cmdlineBasenameStart < 0) - return false; - for (const char* token = cmdline + cmdlineBasenameStart; *token;) { for (tokenBase = token; *token && *token != '\n'; ++token) { if (*token == '/') { tokenBase = token + 1; } } - tokenLen = token - tokenBase; + tokenLen = (size_t)(token - tokenBase); if ((tokenLen == commLen || (tokenLen > commLen && commLen == (TASK_COMM_LEN - 1))) && strncmp(tokenBase, comm, commLen) == 0) { - *pCommStart = tokenBase - cmdline; + *pCommStart = (size_t)(tokenBase - cmdline); *pCommLen = tokenLen; return true; } @@ -99,8 +96,8 @@ static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdline return false; } -static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int* cmdlineBasenameStart, const char* exe, int exeBaseOffset, int exeBaseLen) { - int matchLen; /* matching length to be returned */ +static size_t matchCmdlinePrefixWithExeSuffix(const char* cmdline, size_t* cmdlineBasenameStart, const char* exe, size_t exeBaseOffset, size_t exeBaseLen) { + size_t matchLen; /* matching length to be returned */ /* cmdline prefix is an absolute path: it must match whole exe. */ if (cmdline[0] == '/') { @@ -126,7 +123,7 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int* cmdlineBase * * So if needed, we adjust cmdlineBaseOffset to the previous (if any) * component of the cmdline relative path, and retry the procedure. */ - int cmdlineBaseOffset = *cmdlineBasenameStart; + size_t cmdlineBaseOffset = *cmdlineBasenameStart; bool delimFound = true; /* if valid basename delimiter found */ do { /* match basename */ @@ -135,14 +132,14 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int* cmdlineBase strncmp(cmdline + cmdlineBaseOffset, exe + exeBaseOffset, exeBaseLen) == 0) { char delim = cmdline[matchLen]; if (delim == 0 || delim == '\n' || delim == ' ') { - int i, j; + size_t i, j; /* reverse match the cmdline prefix and exe suffix */ for (i = cmdlineBaseOffset - 1, j = exeBaseOffset - 1; - i >= 0 && j >= 0 && cmdline[i] == exe[j]; --i, --j) + i != (size_t)-1 && j != (size_t)-1 && cmdline[i] == exe[j]; --i, --j) ; /* full match, with exe suffix being a valid relative path */ - if (i < 0 && j >= 0 && exe[j] == '/') { + if (i == (size_t)-1 && j != (size_t)-1 && exe[j] == '/') { *cmdlineBasenameStart = cmdlineBaseOffset; return matchLen; } @@ -152,6 +149,9 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int* cmdlineBase /* Try to find the previous potential cmdlineBaseOffset - it would be * preceded by '/' or nothing, and delimited by ' ' or '\n' */ delimFound = false; + if (cmdlineBaseOffset <= 2) { + return 0; + } for (cmdlineBaseOffset -= 2; cmdlineBaseOffset > 0; --cmdlineBaseOffset) { if (delimFound) { if (cmdline[cmdlineBaseOffset - 1] == '/') { @@ -312,8 +312,8 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { char* strStart = mc->str; char* str = strStart; - int cmdlineBasenameStart = this->cmdlineBasenameStart; - int cmdlineBasenameLen = 0; + size_t cmdlineBasenameStart = this->cmdlineBasenameStart; + size_t cmdlineBasenameLen = 0; if (this->cmdlineBasenameEnd > this->cmdlineBasenameStart) cmdlineBasenameLen = this->cmdlineBasenameEnd - this->cmdlineBasenameStart; @@ -323,20 +323,18 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { cmdline = "(zombie)"; } - assert(cmdlineBasenameStart >= 0); - assert(cmdlineBasenameStart <= (int)strlen(cmdline)); + assert(cmdlineBasenameStart <= strlen(cmdline)); - int exeLen = 0; - int exeBasenameOffset = 0; - int exeBasenameLen = 0; - int matchLen = 0; + size_t exeLen = 0; + size_t exeBasenameOffset = 0; + size_t exeBasenameLen = 0; + size_t matchLen = 0; if (procExe) { exeLen = strlen(procExe); exeBasenameOffset = this->procExeBasenameOffset; exeBasenameLen = exeLen - exeBasenameOffset; - assert(exeBasenameOffset >= 0); - assert(exeBasenameOffset <= (int)strlen(procExe)); + assert(exeBasenameOffset <= strlen(procExe)); if (this->cmdline) { matchLen = matchCmdlinePrefixWithExeSuffix(this->cmdline, &cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen); @@ -376,7 +374,7 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { return; } - int commLen = 0; + size_t commLen = 0; bool haveCommInExe = false; if (procExe && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { @@ -387,7 +385,7 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { } bool haveCommInCmdline = false; - int commStart = 0; + size_t commStart = 0; if (!haveCommInExe && this->cmdline && procComm && searchCommInCmdline && (!Process_isUserlandThread(this) || showThreadNames)) { haveCommInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commLen); @@ -471,7 +469,7 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin const ProcessMergedCommand* mc = &this->mergedCommand; const char* mergedCommand = mc->str; - int strStart = RichString_size(str); + size_t strStart = RichString_size(str); const Settings* settings = this->super.host->settings; const bool highlightBaseName = settings->highlightBaseName; @@ -479,12 +477,12 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin const bool highlightDeleted = settings->highlightDeletedExe; if (!mergedCommand) { - int len = 0; + size_t len = 0; const char* cmdline = this->cmdline; if (highlightBaseName || !settings->showProgramPath) { - int basename = 0; - for (int i = 0; i < this->cmdlineBasenameEnd; i++) { + size_t basename = 0; + for (size_t i = 0; i < this->cmdlineBasenameEnd; i++) { if (cmdline[i] == '/') { basename = i + 1; } else if (cmdline[i] == ':') { @@ -876,7 +874,7 @@ bool Process_rowMatchesFilter(const Row* super, const Table* table) { void Process_init(Process* this, const Machine* host) { Row_init(&this->super, host); - this->cmdlineBasenameEnd = -1; + this->cmdlineBasenameEnd = 0; this->st_uid = (uid_t)-1; } @@ -1028,12 +1026,12 @@ void Process_updateComm(Process* this, const char* comm) { this->mergedCommand.lastUpdate = 0; } -static int skipPotentialPath(const char* cmdline, int end) { +static size_t skipPotentialPath(const char* cmdline, size_t end) { if (cmdline[0] != '/') return 0; - int slash = 0; - for (int i = 1; i < end; i++) { + size_t slash = 0; + for (size_t i = 1; i < end; i++) { if (cmdline[i] == '/' && cmdline[i + 1] != '\0') { slash = i + 1; continue; @@ -1049,11 +1047,10 @@ static int skipPotentialPath(const char* cmdline, int end) { return slash; } -void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd) { - assert(basenameStart >= 0); - assert((cmdline && basenameStart < (int)strlen(cmdline)) || (!cmdline && basenameStart == 0)); +void Process_updateCmdline(Process* this, const char* cmdline, size_t basenameStart, size_t basenameEnd) { + assert((cmdline && basenameStart < strlen(cmdline)) || (!cmdline && basenameStart == 0)); assert((basenameEnd > basenameStart) || (basenameEnd == 0 && basenameStart == 0)); - assert((cmdline && basenameEnd <= (int)strlen(cmdline)) || (!cmdline && basenameEnd == 0)); + assert((cmdline && basenameEnd <= strlen(cmdline)) || (!cmdline && basenameEnd == 0)); if (!this->cmdline && !cmdline) return; @@ -1086,7 +1083,7 @@ void Process_updateExe(Process* this, const char* exe) { if (exe) { this->procExe = xStrdup(exe); const char* lastSlash = strrchr(exe, '/'); - this->procExeBasenameOffset = (lastSlash && *(lastSlash + 1) != '\0' && lastSlash != exe) ? (lastSlash - exe + 1) : 0; + this->procExeBasenameOffset = (lastSlash && *(lastSlash + 1) != '\0' && lastSlash != exe) ? (size_t)(lastSlash - exe + 1) : 0; } else { this->procExe = NULL; this->procExeBasenameOffset = 0; diff --git a/Process.h b/Process.h index b7b48cb1b..38e2711f6 100644 --- a/Process.h +++ b/Process.h @@ -129,10 +129,10 @@ typedef struct Process_ { char* cmdline; /* End Offset in cmdline of the process basename */ - int cmdlineBasenameEnd; + size_t cmdlineBasenameEnd; /* Start Offset in cmdline of the process basename */ - int cmdlineBasenameStart; + size_t cmdlineBasenameStart; /* The process' "command" name */ char* procComm; @@ -144,7 +144,7 @@ typedef struct Process_ { char* procCwd; /* Offset in procExe of the process basename */ - int procExeBasenameOffset; + size_t procExeBasenameOffset; /* Tells if the executable has been replaced in the filesystem since start */ bool procExeDeleted; @@ -326,7 +326,7 @@ int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField const char* Process_getCommand(const Process* this); void Process_updateComm(Process* this, const char* comm); -void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd); +void Process_updateCmdline(Process* this, const char* cmdline, size_t basenameStart, size_t basenameEnd); void Process_updateExe(Process* this, const char* exe); /* This function constructs the string that is displayed by diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c index 882ef768c..39a927cf0 100644 --- a/darwin/DarwinProcess.c +++ b/darwin/DarwinProcess.c @@ -233,7 +233,7 @@ static void DarwinProcess_updateCmdLine(const struct kinfo_proc* k, Process* pro /* Save where the argv[0] string starts. */ sp = cp; - int end = 0; + size_t end = 0; for ( np = NULL; c < nargs && cp < &procargs[size]; cp++ ) { if ( *cp == '\0' ) { c++; @@ -244,7 +244,7 @@ static void DarwinProcess_updateCmdLine(const struct kinfo_proc* k, Process* pro /* Note location of current '\0'. */ np = cp; if (end == 0) { - end = cp - sp; + end = (size_t)(cp - sp); } } } @@ -258,7 +258,7 @@ static void DarwinProcess_updateCmdLine(const struct kinfo_proc* k, Process* pro goto ERROR_B; } if (end == 0) { - end = np - sp; + end = (size_t)(np - sp); } Process_updateCmdline(proc, sp, 0, end); diff --git a/dragonflybsd/DragonFlyBSDProcessTable.c b/dragonflybsd/DragonFlyBSDProcessTable.c index b286219df..7d333862d 100644 --- a/dragonflybsd/DragonFlyBSDProcessTable.c +++ b/dragonflybsd/DragonFlyBSDProcessTable.c @@ -106,18 +106,18 @@ static void DragonFlyBSDProcessTable_updateProcessName(kvm_t* kd, const struct k } size_t len = 0; - for (int i = 0; argv[i]; i++) { + for (size_t i = 0; argv[i]; i++) { len += strlen(argv[i]) + 1; } char* cmdline = xMalloc(len); char* at = cmdline; - int end = 0; - for (int i = 0; argv[i]; i++) { + size_t end = 0; + for (size_t i = 0; argv[i]; i++) { at = stpcpy(at, argv[i]); if (end == 0) { - end = at - cmdline; + end = (size_t)(at - cmdline); } *at++ = ' '; } diff --git a/freebsd/FreeBSDProcessTable.c b/freebsd/FreeBSDProcessTable.c index ce8472594..67f8a445f 100644 --- a/freebsd/FreeBSDProcessTable.c +++ b/freebsd/FreeBSDProcessTable.c @@ -108,17 +108,17 @@ static void FreeBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_ } size_t len = 0; - for (int i = 0; argv[i]; i++) { + for (size_t i = 0; argv[i]; i++) { len += strlen(argv[i]) + 1; } char* cmdline = xMalloc(len); char* at = cmdline; - int end = 0; - for (int i = 0; argv[i]; i++) { + size_t end = 0; + for (size_t i = 0; argv[i]; i++) { at = stpcpy(at, argv[i]); if (end == 0) { - end = at - cmdline; + end = (size_t)(at - cmdline); } *at++ = ' '; } diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c index 3d8dc962e..0e4c7a479 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -1273,15 +1273,15 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro if (amtRead <= 0) return false; - int tokenEnd = -1; - int tokenStart = -1; - int lastChar = 0; + size_t tokenEnd = (size_t)-1; + size_t tokenStart = (size_t)-1; + size_t lastChar = 0; bool argSepNUL = false; bool argSepSpace = false; - for (int i = 0; i < amtRead; i++) { + for (size_t i = 0; i < (size_t)amtRead; i++) { // If this is true, there's a NUL byte in the middle of command - if (tokenEnd >= 0) { + if (tokenEnd != (size_t)-1) { argSepNUL = true; } @@ -1299,7 +1299,7 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro command[i] = '\n'; // Set tokenEnd to the NUL byte - if (tokenEnd < 0) { + if (tokenEnd == (size_t)-1) { tokenEnd = i; } @@ -1313,7 +1313,7 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro /* Detect the last / before the end of the token as * the start of the basename in cmdline, see Process_writeCommand */ - if (argChar == '/' && tokenEnd < 0) { + if (argChar == '/' && tokenEnd == (size_t)-1) { tokenStart = i + 1; } @@ -1336,13 +1336,13 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro * As path names may contain we try to cross-validate if the path we got that way exists. */ - tokenStart = -1; - tokenEnd = -1; + tokenStart = (size_t)-1; + tokenEnd = (size_t)-1; size_t exeLen = process->procExe ? strlen(process->procExe) : 0; if (process->procExe && String_startsWith(command, process->procExe) && - exeLen < (size_t)lastChar && command[exeLen] <= ' ') { + exeLen < lastChar && command[exeLen] <= ' ') { tokenStart = process->procExeBasenameOffset; tokenEnd = exeLen; } @@ -1352,14 +1352,14 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro else if (Compat_faccessat(AT_FDCWD, command, F_OK, AT_SYMLINK_NOFOLLOW) != 0) { // If we reach here the path does not exist. // Thus begin searching for the part of it that actually does. - int tokenArg0Start = -1; + size_t tokenArg0Start = (size_t)-1; - for (int i = 0; i <= lastChar; i++) { + for (size_t i = 0; i <= lastChar; i++) { const char cmdChar = command[i]; /* Any ASCII control or space used as delimiter */ if (cmdChar <= ' ') { - if (tokenEnd >= 0) { + if (tokenEnd != (size_t)-1) { // Split on every further separator, regardless of path correctness command[i] = '\n'; continue; @@ -1375,39 +1375,39 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro if (found) tokenEnd = i; - if (tokenArg0Start < 0) - tokenArg0Start = tokenStart < 0 ? 0 : tokenStart; + if (tokenArg0Start == (size_t)-1) + tokenArg0Start = tokenStart == (size_t)-1 ? 0 : tokenStart; continue; } - if (tokenEnd >= 0) { + if (tokenEnd != (size_t)-1) { continue; } if (cmdChar == '/') { // Normal path separator tokenStart = i + 1; - } else if (cmdChar == '\\' && (tokenStart < 1 || command[tokenStart - 1] == '\\')) { + } else if (cmdChar == '\\' && (tokenStart == (size_t)-1 || tokenStart == 0 || command[tokenStart - 1] == '\\')) { // Windows Path separator (WINE) tokenStart = i + 1; } else if (cmdChar == ':' && (command[i + 1] != '/' && command[i + 1] != '\\')) { // Colon not part of a Windows Path tokenEnd = i; - } else if (tokenStart < 0) { + } else if (tokenStart == (size_t)-1) { // Relative path tokenStart = i; } } - if (tokenEnd < 0) { + if (tokenEnd == (size_t)-1) { tokenStart = tokenArg0Start; // No token delimiter found, forcibly split - for (int i = 0; i <= lastChar; i++) { + for (size_t i = 0; i <= lastChar; i++) { if (command[i] <= ' ') { command[i] = '\n'; - if (tokenEnd < 0) { + if (tokenEnd == (size_t)-1) { tokenEnd = i; } } @@ -1420,16 +1420,16 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro * Reset if start is behind end. */ if (tokenStart >= tokenEnd) { - tokenStart = -1; - tokenEnd = -1; + tokenStart = (size_t)-1; + tokenEnd = (size_t)-1; } } - if (tokenStart < 0) { + if (tokenStart == (size_t)-1) { tokenStart = 0; } - if (tokenEnd < 0) { + if (tokenEnd == (size_t)-1) { tokenEnd = lastChar + 1; } diff --git a/netbsd/NetBSDProcessTable.c b/netbsd/NetBSDProcessTable.c index 71ae53e70..31c966cf9 100644 --- a/netbsd/NetBSDProcessTable.c +++ b/netbsd/NetBSDProcessTable.c @@ -105,7 +105,7 @@ static void NetBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_p } size_t len = 0; - for (int i = 0; arg[i] != NULL; i++) { + for (size_t i = 0; arg[i] != NULL; i++) { len += strlen(arg[i]) + 1; /* room for arg and trailing space or NUL */ } @@ -118,14 +118,14 @@ static void NetBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_p *s = '\0'; - int start = 0; - int end = 0; - for (int i = 0; arg[i] != NULL; i++) { + size_t start = 0; + size_t end = 0; + for (size_t i = 0; arg[i] != NULL; i++) { size_t n = strlcat(s, arg[i], len); if (i == 0) { end = MINIMUM(n, len - 1); /* check if cmdline ended earlier, e.g 'kdeinit5: Running...' */ - for (int j = end; j > 0; j--) { + for (size_t j = end; j > 0; j--) { if (arg[0][j] == ' ' && arg[0][j - 1] != '\\') { end = (arg[0][j - 1] == ':') ? (j - 1) : j; } diff --git a/openbsd/OpenBSDProcessTable.c b/openbsd/OpenBSDProcessTable.c index ded31e596..404701811 100644 --- a/openbsd/OpenBSDProcessTable.c +++ b/openbsd/OpenBSDProcessTable.c @@ -84,7 +84,7 @@ static void OpenBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_ } size_t len = 0; - for (int i = 0; arg[i] != NULL; i++) { + for (size_t i = 0; arg[i] != NULL; i++) { len += strlen(arg[i]) + 1; /* room for arg and trailing space or NUL */ } @@ -97,14 +97,14 @@ static void OpenBSDProcessTable_updateProcessName(kvm_t* kd, const struct kinfo_ *s = '\0'; - int start = 0; - int end = 0; - for (int i = 0; arg[i] != NULL; i++) { + size_t start = 0; + size_t end = 0; + for (size_t i = 0; arg[i] != NULL; i++) { size_t n = strlcat(s, arg[i], len); if (i == 0) { end = MINIMUM(n, len - 1); /* check if cmdline ended earlier, e.g 'kdeinit5: Running...' */ - for (int j = end; j > 0; j--) { + for (size_t j = end; j > 0; j--) { if (arg[0][j] == ' ' && arg[0][j - 1] != '\\') { end = (arg[0][j - 1] == ':') ? (j - 1) : j; } diff --git a/pcp/PCPProcessTable.c b/pcp/PCPProcessTable.c index 024bef55f..3563100eb 100644 --- a/pcp/PCPProcessTable.c +++ b/pcp/PCPProcessTable.c @@ -310,7 +310,7 @@ static void PCPProcessTable_updateCmdline(Process* process, int pid, int offset, } char* command = value.cp; - int length = strlen(command); + size_t length = strlen(command); if (command[0] != '(') { process->isKernelThread = false; } else { @@ -321,11 +321,11 @@ static void PCPProcessTable_updateCmdline(Process* process, int pid, int offset, process->isKernelThread = true; } - int tokenEnd = 0; - int tokenStart = 0; + size_t tokenEnd = 0; + size_t tokenStart = 0; bool argSepSpace = false; - for (int i = 0; i < length; i++) { + for (size_t i = 0; i < length; i++) { /* htop considers the next character after the last / that is before * basenameOffset, as the start of the basename in cmdline - see * Process_writeCommand */ From c7cc032991f1026ddd4988ced4c93a53374a3639 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Mon, 24 Feb 2025 03:59:13 +0800 Subject: [PATCH 09/23] Replace unnecessary RichString_appendnAscii() calls with appendAscii() This slightly reduces code size. Signed-off-by: Kang-Che Sung --- linux/GPUMeter.c | 12 ++++++------ pcp/PCPDynamicMeter.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/linux/GPUMeter.c b/linux/GPUMeter.c index 628d4c71c..531878b92 100644 --- a/linux/GPUMeter.c +++ b/linux/GPUMeter.c @@ -127,27 +127,27 @@ static void GPUMeter_display(const Object* cast, RichString* out) { RichString_writeAscii(out, CRT_colors[METER_TEXT], ":"); written = xSnprintf(buffer, sizeof(buffer), "%4.1f", totalUsage); RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); - RichString_appendnAscii(out, CRT_colors[METER_TEXT], "%(", 2); + RichString_appendAscii(out, CRT_colors[METER_TEXT], "%("); written = humanTimeUnit(buffer, sizeof(buffer), totalGPUTimeDiff); RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); - RichString_appendnAscii(out, CRT_colors[METER_TEXT], ")", 1); + RichString_appendAscii(out, CRT_colors[METER_TEXT], ")"); for (i = 0; i < ARRAYSIZE(GPUMeter_engineData); i++) { if (!GPUMeter_engineData[i].key) break; - RichString_appendnAscii(out, CRT_colors[METER_TEXT], " ", 1); + RichString_appendAscii(out, CRT_colors[METER_TEXT], " "); RichString_appendAscii(out, CRT_colors[METER_TEXT], GPUMeter_engineData[i].key); - RichString_appendnAscii(out, CRT_colors[METER_TEXT], ":", 1); + RichString_appendAscii(out, CRT_colors[METER_TEXT], ":"); if (isNonnegative(this->values[i])) written = xSnprintf(buffer, sizeof(buffer), "%4.1f", this->values[i]); else written = xSnprintf(buffer, sizeof(buffer), " N/A"); RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); - RichString_appendnAscii(out, CRT_colors[METER_TEXT], "%(", 2); + RichString_appendAscii(out, CRT_colors[METER_TEXT], "%("); written = humanTimeUnit(buffer, sizeof(buffer), GPUMeter_engineData[i].timeDiff); RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); - RichString_appendnAscii(out, CRT_colors[METER_TEXT], ")", 1); + RichString_appendAscii(out, CRT_colors[METER_TEXT], ")"); } } diff --git a/pcp/PCPDynamicMeter.c b/pcp/PCPDynamicMeter.c index 311f1af52..57c84dddc 100644 --- a/pcp/PCPDynamicMeter.c +++ b/pcp/PCPDynamicMeter.c @@ -415,7 +415,7 @@ void PCPDynamicMeter_display(PCPDynamicMeter* this, ATTR_UNUSED const Meter* met nodata = 0; /* we will use this metric so *some* data will be added */ if (i > 0) - RichString_appendnAscii(out, CRT_colors[metric->color], " ", 1); + RichString_appendAscii(out, CRT_colors[metric->color], " "); if (metric->label) RichString_appendAscii(out, CRT_colors[METER_TEXT], metric->label); From 4970abbf466fbe9e4a938a3f350ab8780a54210c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:17:39 +0800 Subject: [PATCH 10/23] Use RichString_appendnAscii() for CPU frequency text The text buffer contains no characters outside ASCII range, thus there is no need to use RichString_appendnWide(). Signed-off-by: Kang-Che Sung --- CPUMeter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPUMeter.c b/CPUMeter.c index 015135035..430243681 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -187,7 +187,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A "); } RichString_appendAscii(out, CRT_colors[METER_TEXT], "freq: "); - RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuFrequencyBuffer, len); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], cpuFrequencyBuffer, len); } #ifdef BUILD_WITH_CPU_TEMP From e3bec0d69a698c8538cd001a558795e4f35df72e Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:42:14 +0800 Subject: [PATCH 11/23] Fix mbstowcs_nonfatal() that might convert string shorter than desired The "n" parameter of mbstowcs_nonfatal() refers to number of wide characters. But the logic seemed to be confused with "n" parameter of mbrtowc() (the number of bytes). Signed-off-by: Kang-Che Sung --- RichString.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/RichString.c b/RichString.c index 390beb073..6e84cf3cd 100644 --- a/RichString.c +++ b/RichString.c @@ -69,8 +69,8 @@ static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src mbstate_t ps = { 0 }; bool broken = false; - while (n > 0) { - size_t ret = mbrtowc(dest, src, n, &ps); + while (written < n) { + size_t ret = mbrtowc(dest, src, SIZE_MAX, &ps); if (ret == (size_t)-1 || ret == (size_t)-2) { if (!broken) { broken = true; @@ -78,7 +78,6 @@ static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src written++; } src++; - n--; continue; } @@ -91,7 +90,6 @@ static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src dest++; written++; src += ret; - n -= ret; } return written; From 7e1d68cb4689d2c6dcee684d734f982117c90521 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:18:30 +0800 Subject: [PATCH 12/23] Add an assertion to Row_printLeftAlignedField() `assert(width <= INT_MAX)` even though the "width" argument is unsigned int type. Signed-off-by: Kang-Che Sung --- Row.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Row.c b/Row.c index 13a1313ac..8c6a256d2 100644 --- a/Row.c +++ b/Row.c @@ -494,7 +494,8 @@ void Row_printRate(RichString* str, double rate, bool coloring) { } void Row_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) { - int columns = width; + assert(width <= INT_MAX); + int columns = (int)width; RichString_appendnWideColumns(str, attr, content, strlen(content), &columns); RichString_appendChr(str, attr, ' ', width + 1 - columns); } From b35cf689498bf7324a9d7b467441411194b49f6c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:33:59 +0800 Subject: [PATCH 13/23] Panel.scrollH value clamp logic improvement The Panel.scrollH value should have a minimum of 0 in the KEY_LEFT event. Signed-off-by: Kang-Che Sung --- Panel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel.c b/Panel.c index 4784a6585..c55febf87 100644 --- a/Panel.c +++ b/Panel.c @@ -378,7 +378,7 @@ bool Panel_onKey(Panel* this, int key) { case KEY_LEFT: case KEY_CTRL('B'): if (this->scrollH > 0) { - this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0); + this->scrollH = MAXIMUM(this->scrollH - CRT_scrollHAmount, 0); this->needsRedraw = true; } break; From 6afc7c74a0902e79aa39119b74604f7ac2dba310 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:33:21 +0800 Subject: [PATCH 14/23] Remove redundant length clamping in Panel_draw() Because RichString_printoffnVal() will never print strings beyond their NUL-terminators. Note that the routines in Panel_draw() currently assumes each character occupies one terminal column, which does not hold for Unicode strings. The routines might need to be rewritten in the future to properly support Unicode. Signed-off-by: Kang-Che Sung --- Panel.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Panel.c b/Panel.c index c55febf87..8e862207e 100644 --- a/Panel.c +++ b/Panel.c @@ -244,8 +244,7 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect attrset(header_attr); mvhline(y, x, ' ', this->w); if (scrollH < headerLen) { - RichString_printoffnVal(this->header, y, x, scrollH, - MINIMUM(headerLen - scrollH, this->w)); + RichString_printoffnVal(this->header, y, x, scrollH, this->w); } attrset(CRT_colors[RESET_COLOR]); y++; @@ -283,7 +282,6 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect RichString_begin(item); Object_display(itemObj, &item); int itemLen = RichString_sizeVal(item); - int amt = MINIMUM(itemLen - scrollH, this->w); if (highlightSelected && i == this->selected) { item.highlightAttr = selectionColor; } @@ -293,8 +291,8 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect this->selectedLen = itemLen; } mvhline(y + line, x, ' ', this->w); - if (amt > 0) - RichString_printoffnVal(item, y + line, x, scrollH, amt); + if (scrollH < itemLen) + RichString_printoffnVal(item, y + line, x, scrollH, this->w); if (item.highlightAttr) attrset(CRT_colors[RESET_COLOR]); RichString_delete(&item); @@ -318,13 +316,13 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect mvhline(y + this->oldSelected - first, x + 0, ' ', this->w); if (scrollH < oldLen) RichString_printoffnVal(old, y + this->oldSelected - first, x, - scrollH, MINIMUM(oldLen - scrollH, this->w)); + scrollH, this->w); attrset(selectionColor); mvhline(y + this->selected - first, x + 0, ' ', this->w); RichString_setAttr(&new, selectionColor); if (scrollH < newLen) RichString_printoffnVal(new, y + this->selected - first, x, - scrollH, MINIMUM(newLen - scrollH, this->w)); + scrollH, this->w); attrset(CRT_colors[RESET_COLOR]); RichString_delete(&new); RichString_delete(&old); From 414a627a2da70fc1d8740294e3019fb5bb8baf29 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:14:33 +0800 Subject: [PATCH 15/23] RichString_setLen() minor logic fix Compare "<= RICHSTRING_MAXLEN" rather than "< RICHSTRING_MAXLEN". RICHSTRING_MAXLEN does not include the terminating L'\0' character and the internal buffer of a RichString instance has (RICHSTRING_MAXLEN + 1) elements. Signed-off-by: Kang-Che Sung --- RichString.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RichString.c b/RichString.c index 6e84cf3cd..5f100767d 100644 --- a/RichString.c +++ b/RichString.c @@ -50,7 +50,7 @@ static void RichString_extendLen(RichString* this, int len) { } static void RichString_setLen(RichString* this, int len) { - if (len < RICHSTRING_MAXLEN && this->chlen < RICHSTRING_MAXLEN) { + if (len <= RICHSTRING_MAXLEN && this->chlen <= RICHSTRING_MAXLEN) { RichString_setChar(this, len, 0); this->chlen = len; } else { From a1d4147315ed0cb257d451fd541280da6f6f0884 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:15:40 +0800 Subject: [PATCH 16/23] Prevent length wraparound in RichString_rewind() The computed length could wrap to a negative integer, causing undefined behavior. (Currently it would cause out-of-bound array access due to a signed length property in RichString. The length property should be migrated to an unsigned size_t type, but that would be done in a later commit.) Signed-off-by: Kang-Che Sung --- RichString.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RichString.c b/RichString.c index 5f100767d..d583809b9 100644 --- a/RichString.c +++ b/RichString.c @@ -59,7 +59,7 @@ static void RichString_setLen(RichString* this, int len) { } void RichString_rewind(RichString* this, int count) { - RichString_setLen(this, this->chlen - count); + RichString_setLen(this, this->chlen > count ? this->chlen - count : 0); } #ifdef HAVE_LIBNCURSESW From 1be88d470c2c518f6ff26cba23cd85c45fa9de2b Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:21:32 +0800 Subject: [PATCH 17/23] Add bound checks when changing Panel.cursorX value Limit the maximum of the "cursorX" value to "x + w". In case of integer overflow, cap the value to INT_MAX. This code is written with an assumption that the "selectedLen" and "scrollH" properties may be larger than the type of `int` (for example, `size_t`). Signed-off-by: Kang-Che Sung --- Panel.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Panel.c b/Panel.c index 8e862207e..9d3f232b8 100644 --- a/Panel.c +++ b/Panel.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include #include +#include #include #include #include @@ -79,7 +80,16 @@ void Panel_done(Panel* this) { void Panel_setCursorToSelection(Panel* this) { this->cursorY = this->y + this->selected - this->scrollV + 1; - this->cursorX = this->x + this->selectedLen - this->scrollH; + + int offset = this->w; + if (this->selectedLen - this->scrollH < this->w) { + offset = this->selectedLen - this->scrollH; + } + if ((unsigned int)offset <= INT_MAX - (unsigned int)this->x) { + this->cursorX = this->x + offset; + } else { + this->cursorX = INT_MAX; + } } void Panel_setSelectionColor(Panel* this, ColorElements colorId) { From 001d42e786a2c6737b3fbdaab2037719cffb19e3 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:28:14 +0800 Subject: [PATCH 18/23] Use size_t for Panel.scrollH and Panel.selectedLen --- CRT.c | 2 +- CRT.h | 2 +- MainPanel.c | 3 ++- Panel.c | 25 ++++++++++++++++--------- Panel.h | 5 +++-- Row.c | 6 +++--- Row.h | 2 +- pcp/InDomTable.h | 3 ++- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/CRT.c b/CRT.c index 9c8b841a2..4361fe93f 100644 --- a/CRT.c +++ b/CRT.c @@ -825,7 +825,7 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { static bool CRT_retainScreenOnExit = false; -int CRT_scrollHAmount = 5; +unsigned int CRT_scrollHAmount = 5; int CRT_scrollWheelVAmount = 10; diff --git a/CRT.h b/CRT.h index 00626519b..5076d4038 100644 --- a/CRT.h +++ b/CRT.h @@ -191,7 +191,7 @@ extern const int* CRT_colors; extern int CRT_cursorX; -extern int CRT_scrollHAmount; +extern unsigned int CRT_scrollHAmount; extern int CRT_scrollWheelVAmount; diff --git a/MainPanel.c b/MainPanel.c index 7852c08f3..d0766f522 100644 --- a/MainPanel.c +++ b/MainPanel.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include "MainPanel.h" #include +#include #include #include @@ -81,7 +82,7 @@ static HandlerResult MainPanel_eventHandler(Panel* super, int ch) { if (EVENT_IS_HEADER_CLICK(ch)) { int x = EVENT_HEADER_CLICK_GET_X(ch); - int hx = super->scrollH + x + 1; + size_t hx = super->scrollH + (unsigned int)x + 1; RowField field = RowField_keyAt(settings, hx); if (ss->treeView && ss->treeViewAlwaysByPID) { ss->treeView = false; diff --git a/Panel.c b/Panel.c index 9d3f232b8..bc9de904f 100644 --- a/Panel.c +++ b/Panel.c @@ -82,8 +82,8 @@ void Panel_setCursorToSelection(Panel* this) { this->cursorY = this->y + this->selected - this->scrollV + 1; int offset = this->w; - if (this->selectedLen - this->scrollH < this->w) { - offset = this->selectedLen - this->scrollH; + if (this->selectedLen - this->scrollH < (unsigned int)this->w) { + offset = (int)(this->selectedLen - this->scrollH); } if ((unsigned int)offset <= INT_MAX - (unsigned int)this->x) { this->cursorX = this->x + offset; @@ -232,7 +232,7 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect assert (this != NULL); int size = Vector_size(this->items); - int scrollH = this->scrollH; + size_t scrollH = this->scrollH; int y = this->y; int x = this->x; int h = this->h; @@ -249,7 +249,7 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect else RichString_setAttr(&this->header, header_attr); } - int headerLen = RichString_sizeVal(this->header); + size_t headerLen = RichString_sizeVal(this->header); if (headerLen > 0) { attrset(header_attr); mvhline(y, x, ' ', this->w); @@ -291,7 +291,7 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect const Object* itemObj = Vector_get(this->items, i); RichString_begin(item); Object_display(itemObj, &item); - int itemLen = RichString_sizeVal(item); + size_t itemLen = RichString_sizeVal(item); if (highlightSelected && i == this->selected) { item.highlightAttr = selectionColor; } @@ -317,11 +317,11 @@ void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelect const Object* oldObj = Vector_get(this->items, this->oldSelected); RichString_begin(old); Object_display(oldObj, &old); - int oldLen = RichString_sizeVal(old); + size_t oldLen = RichString_sizeVal(old); const Object* newObj = Vector_get(this->items, this->selected); RichString_begin(new); Object_display(newObj, &new); - int newLen = RichString_sizeVal(new); + size_t newLen = RichString_sizeVal(new); this->selectedLen = newLen; mvhline(y + this->oldSelected - first, x + 0, ' ', this->w); if (scrollH < oldLen) @@ -386,7 +386,11 @@ bool Panel_onKey(Panel* this, int key) { case KEY_LEFT: case KEY_CTRL('B'): if (this->scrollH > 0) { - this->scrollH = MAXIMUM(this->scrollH - CRT_scrollHAmount, 0); + if (this->scrollH > CRT_scrollHAmount) { + this->scrollH = this->scrollH - CRT_scrollHAmount; + } else { + this->scrollH = 0; + } this->needsRedraw = true; } break; @@ -429,7 +433,10 @@ bool Panel_onKey(Panel* this, int key) { case KEY_CTRL('E'): case '$': - this->scrollH = MAXIMUM(this->selectedLen - this->w, 0); + this->scrollH = 0; + if (this->selectedLen > (unsigned int)this->w) { + this->scrollH = this->selectedLen - (unsigned int)this->w; + } this->needsRedraw = true; break; diff --git a/Panel.h b/Panel.h index 286e4464b..9fa8429de 100644 --- a/Panel.h +++ b/Panel.h @@ -9,6 +9,7 @@ in the source distribution for its full text. #include #include +#include #include "CRT.h" #include "FunctionBar.h" @@ -67,10 +68,10 @@ struct Panel_ { Vector* items; int selected; int oldSelected; - int selectedLen; + size_t selectedLen; void* eventHandlerState; int scrollV; - int scrollH; + size_t scrollH; bool needsRedraw; bool cursorOn; bool wasFocus; diff --git a/Row.c b/Row.c index 8c6a256d2..4c4415b64 100644 --- a/Row.c +++ b/Row.c @@ -176,12 +176,12 @@ const char* RowField_alignedTitle(const Settings* settings, RowField field) { return alignedTitleDynamicColumn(settings, field, titleBuffer, sizeof(titleBuffer)); } -RowField RowField_keyAt(const Settings* settings, int at) { +RowField RowField_keyAt(const Settings* settings, size_t at) { const RowField* fields = (const RowField*) settings->ss->fields; RowField field; - int x = 0; + size_t x = 0; for (int i = 0; (field = fields[i]); i++) { - int len = strlen(RowField_alignedTitle(settings, field)); + size_t len = strlen(RowField_alignedTitle(settings, field)); if (at >= x && at <= x + len) { return field; } diff --git a/Row.h b/Row.h index 78629a3a5..8c41c92b6 100644 --- a/Row.h +++ b/Row.h @@ -134,7 +134,7 @@ void Row_printLeftAlignedField(RichString* str, int attr, const char* content, u const char* RowField_alignedTitle(const struct Settings_* settings, RowField field); -RowField RowField_keyAt(const struct Settings_* settings, int at); +RowField RowField_keyAt(const struct Settings_* settings, size_t at); /* Sets the size of the PID column based on the passed PID */ void Row_setPidColumnWidth(pid_t maxPid); diff --git a/pcp/InDomTable.h b/pcp/InDomTable.h index f44a39f64..39dd77fd5 100644 --- a/pcp/InDomTable.h +++ b/pcp/InDomTable.h @@ -9,6 +9,7 @@ in the source distribution for its full text. */ #include +#include #include #include "Platform.h" @@ -27,7 +28,7 @@ InDomTable* InDomTable_new(Machine* host, pmInDom indom, int metricKey); void InDomTable_done(InDomTable* this); -RowField RowField_keyAt(const Settings* settings, int at); +RowField RowField_keyAt(const Settings* settings, size_t at); void InDomTable_scan(Table* super); From 40facba2ad88cc066a58dc7d8ce4eb631bab72df Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 21 Mar 2025 02:59:59 +0800 Subject: [PATCH 19/23] Upgrade all length parameters of RichString class to size_t Signed-off-by: Kang-Che Sung --- CPUMeter.c | 26 +++++----- DiskIOMeter.c | 2 +- FileDescriptorMeter.c | 4 +- LoadAverageMeter.c | 8 ++-- Meter.c | 39 ++++++++------- NetworkIOMeter.c | 2 +- OptionItem.c | 2 +- RichString.c | 94 ++++++++++++++++++------------------- RichString.h | 26 +++++----- Row.c | 62 ++++++++++++------------ TasksMeter.c | 8 ++-- linux/GPUMeter.c | 8 ++-- linux/PressureStallMeter.c | 6 +-- linux/SystemdMeter.c | 8 ++-- pcp/PCPDynamicColumn.c | 12 ++--- pcp/PCPDynamicMeter.c | 2 +- zfs/ZfsCompressedArcMeter.c | 2 +- 17 files changed, 156 insertions(+), 155 deletions(-) diff --git a/CPUMeter.c b/CPUMeter.c index 430243681..232f9f2eb 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -137,44 +137,44 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NORMAL]); RichString_appendAscii(out, CRT_colors[METER_TEXT], ":"); - RichString_appendnAscii(out, CRT_colors[CPU_NORMAL], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_NORMAL], buffer, (unsigned int)len); if (settings->detailedCPUTime) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "sy:"); - RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "ni:"); - RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "hi:"); - RichString_appendnAscii(out, CRT_colors[CPU_IRQ], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_IRQ], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_SOFTIRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "si:"); - RichString_appendnAscii(out, CRT_colors[CPU_SOFTIRQ], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_SOFTIRQ], buffer, (unsigned int)len); if (isNonnegative(this->values[CPU_METER_STEAL])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_STEAL]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "st:"); - RichString_appendnAscii(out, CRT_colors[CPU_STEAL], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_STEAL], buffer, (unsigned int)len); } if (isNonnegative(this->values[CPU_METER_GUEST])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_GUEST]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "gu:"); - RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, (unsigned int)len); } len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IOWAIT]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "wa:"); - RichString_appendnAscii(out, CRT_colors[CPU_IOWAIT], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_IOWAIT], buffer, (unsigned int)len); } else { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_KERNEL]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "sys:"); - RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_SYSTEM], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_NICE]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "low:"); - RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_NICE_TEXT], buffer, (unsigned int)len); if (isNonnegative(this->values[CPU_METER_IRQ])) { len = xSnprintf(buffer, sizeof(buffer), "%5.1f%% ", this->values[CPU_METER_IRQ]); RichString_appendAscii(out, CRT_colors[METER_TEXT], "vir:"); - RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, len); + RichString_appendnAscii(out, CRT_colors[CPU_GUEST], buffer, (unsigned int)len); } } @@ -187,7 +187,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(cpuFrequencyBuffer, sizeof(cpuFrequencyBuffer), "N/A "); } RichString_appendAscii(out, CRT_colors[METER_TEXT], "freq: "); - RichString_appendnAscii(out, CRT_colors[METER_VALUE], cpuFrequencyBuffer, len); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], cpuFrequencyBuffer, (unsigned int)len); } #ifdef BUILD_WITH_CPU_TEMP @@ -202,7 +202,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { len = xSnprintf(cpuTemperatureBuffer, sizeof(cpuTemperatureBuffer), "%5.1f%sC", cpuTemperature, CRT_degreeSign); } RichString_appendAscii(out, CRT_colors[METER_TEXT], "temp:"); - RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer, len); + RichString_appendnWide(out, CRT_colors[METER_VALUE], cpuTemperatureBuffer, (unsigned int)len); } #endif } diff --git a/DiskIOMeter.c b/DiskIOMeter.c index 4bb689fac..0b92f04e7 100644 --- a/DiskIOMeter.c +++ b/DiskIOMeter.c @@ -137,7 +137,7 @@ static void DiskIOMeter_display(ATTR_UNUSED const Object* cast, RichString* out) int color = cached_utilisation_diff > 40.0 ? METER_VALUE_NOTICE : METER_VALUE; int len = xSnprintf(buffer, sizeof(buffer), "%.1f%%", cached_utilisation_diff); - RichString_appendnAscii(out, CRT_colors[color], buffer, len); + RichString_appendnAscii(out, CRT_colors[color], buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " read: "); RichString_appendAscii(out, CRT_colors[METER_VALUE_IOREAD], cached_read_diff_str); diff --git a/FileDescriptorMeter.c b/FileDescriptorMeter.c index cd3baf58c..b1f149fc4 100644 --- a/FileDescriptorMeter.c +++ b/FileDescriptorMeter.c @@ -89,14 +89,14 @@ static void FileDescriptorMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_TEXT], "used: "); len = xSnprintf(buffer, sizeof(buffer), "%.0lf", this->values[0]); - RichString_appendnAscii(out, CRT_colors[FILE_DESCRIPTOR_USED], buffer, len); + RichString_appendnAscii(out, CRT_colors[FILE_DESCRIPTOR_USED], buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " max: "); if (FD_EFFECTIVE_UNLIMITED(this->values[1])) { RichString_appendAscii(out, CRT_colors[FILE_DESCRIPTOR_MAX], "unlimited"); } else { len = xSnprintf(buffer, sizeof(buffer), "%.0lf", this->values[1]); - RichString_appendnAscii(out, CRT_colors[FILE_DESCRIPTOR_MAX], buffer, len); + RichString_appendnAscii(out, CRT_colors[FILE_DESCRIPTOR_MAX], buffer, (unsigned int)len); } } diff --git a/LoadAverageMeter.c b/LoadAverageMeter.c index 6bf13a03e..b5c87007a 100644 --- a/LoadAverageMeter.c +++ b/LoadAverageMeter.c @@ -66,11 +66,11 @@ static void LoadAverageMeter_display(const Object* cast, RichString* out) { int len; len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]); - RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_ONE], buffer, len); + RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_ONE], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[1]); - RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer, len); + RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIVE], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[2]); - RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer, len); + RichString_appendnAscii(out, CRT_colors[LOAD_AVERAGE_FIFTEEN], buffer, (unsigned int)len); } static void LoadMeter_updateValues(Meter* this) { @@ -98,7 +98,7 @@ static void LoadMeter_display(const Object* cast, RichString* out) { int len; len = xSnprintf(buffer, sizeof(buffer), "%.2f ", this->values[0]); - RichString_appendnAscii(out, CRT_colors[LOAD], buffer, len); + RichString_appendnAscii(out, CRT_colors[LOAD], buffer, (unsigned int)len); } const MeterClass LoadAverageMeter_class = { diff --git a/Meter.c b/Meter.c index 4463a90a0..889f127eb 100644 --- a/Meter.c +++ b/Meter.c @@ -96,29 +96,28 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { // The text in the bar is right aligned; // Pad with maximal spaces and then calculate needed starting position offset RichString_begin(bar); - RichString_appendChr(&bar, 0, ' ', w); + RichString_appendChr(&bar, 0, ' ', (unsigned int)w); RichString_appendWide(&bar, 0, this->txtBuffer); - int startPos = RichString_sizeVal(bar) - w; - if (startPos > w) { + size_t startPos = RichString_sizeVal(bar) - (unsigned int)w; + if (startPos > (unsigned int)w) { // Text is too large for bar // Truncate meter text at a space character - for (int pos = 2 * w; pos > w; pos--) { + for (unsigned int pos = 2 * (unsigned int)w; pos > (unsigned int)w; pos--) { if (RichString_getCharVal(bar, pos) == ' ') { - while (pos > w && RichString_getCharVal(bar, pos - 1) == ' ') + while (pos > (unsigned int)w && RichString_getCharVal(bar, pos - 1) == ' ') pos--; - startPos = pos - w; + startPos = pos - (unsigned int)w; break; } } // If still too large, print the start not the end - startPos = MINIMUM(startPos, w); + startPos = MINIMUM(startPos, (unsigned int)w); } - assert(startPos >= 0); - assert(startPos <= w); - assert(startPos + w <= RichString_sizeVal(bar)); + assert(startPos <= (unsigned int)w); + assert(startPos + (unsigned int)w <= RichString_sizeVal(bar)); int blockSizes[10]; @@ -136,12 +135,12 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { // (Control against invalid values) nextOffset = CLAMP(nextOffset, 0, w); for (int j = offset; j < nextOffset; j++) - if (RichString_getCharVal(bar, startPos + j) == ' ') { + if (RichString_getCharVal(bar, startPos + (unsigned int)j) == ' ') { if (CRT_colorScheme == COLORSCHEME_MONOCHROME) { assert(i < strlen(BarMeterMode_characters)); - RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]); + RichString_setChar(&bar, startPos + (unsigned int)j, BarMeterMode_characters[i]); } else { - RichString_setChar(&bar, startPos + j, '|'); + RichString_setChar(&bar, startPos + (unsigned int)j, '|'); } } offset = nextOffset; @@ -151,14 +150,14 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { offset = 0; for (uint8_t i = 0; i < this->curItems; i++) { int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i]; - RichString_setAttrn(&bar, CRT_colors[attr], startPos + offset, blockSizes[i]); - RichString_printoffnVal(bar, y, x + offset, startPos + offset, MINIMUM(blockSizes[i], w - offset)); + RichString_setAttrn(&bar, CRT_colors[attr], startPos + (unsigned int)offset, blockSizes[i]); + RichString_printoffnVal(bar, y, x + offset, startPos + (unsigned int)offset, MINIMUM(blockSizes[i], w - offset)); offset += blockSizes[i]; offset = CLAMP(offset, 0, w); } if (offset < w) { - RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset); - RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset); + RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + (unsigned int)offset, (unsigned int)(w - offset)); + RichString_printoffnVal(bar, y, x + offset, startPos + (unsigned int)offset, w - offset); } RichString_delete(&bar); @@ -319,9 +318,9 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) { attrset(CRT_colors[LED_COLOR]); const char* caption = Meter_getCaption(this); mvaddstr(yText, x, caption); - int xx = x + strlen(caption); - int len = RichString_sizeVal(out); - for (int i = 0; i < len; i++) { + int xx = x + (int)strlen(caption); + size_t len = RichString_sizeVal(out); + for (size_t i = 0; i < len; i++) { int c = RichString_getCharVal(out, i); if (c >= '0' && c <= '9') { if (xx - x + 4 > w) diff --git a/NetworkIOMeter.c b/NetworkIOMeter.c index da3ce71da..9c9bc6ac4 100644 --- a/NetworkIOMeter.c +++ b/NetworkIOMeter.c @@ -158,7 +158,7 @@ static void NetworkIOMeter_display(ATTR_UNUSED const Object* cast, RichString* o RichString_appendAscii(out, CRT_colors[METER_VALUE_IOWRITE], "iB/s"); int len = xSnprintf(buffer, sizeof(buffer), " (%u/%u pkts/s) ", cached_rxp_diff, cached_txp_diff); - RichString_appendnAscii(out, CRT_colors[METER_TEXT], buffer, len); + RichString_appendnAscii(out, CRT_colors[METER_TEXT], buffer, (unsigned int)len); } const MeterClass NetworkIOMeter_class = { diff --git a/OptionItem.c b/OptionItem.c index 728113b9e..d211e0108 100644 --- a/OptionItem.c +++ b/OptionItem.c @@ -62,7 +62,7 @@ static void NumberItem_display(const Object* cast, RichString* out) { } else { written = xSnprintf(buffer, sizeof(buffer), "%d", NumberItem_get(this)); } - RichString_appendnAscii(out, CRT_colors[CHECK_MARK], buffer, written); + RichString_appendnAscii(out, CRT_colors[CHECK_MARK], buffer, (unsigned int)written); RichString_appendAscii(out, CRT_colors[CHECK_BOX], "]"); for (int i = written; i < 5; i++) { RichString_appendAscii(out, CRT_colors[CHECK_BOX], " "); diff --git a/RichString.c b/RichString.c index d583809b9..df5c2b77d 100644 --- a/RichString.c +++ b/RichString.c @@ -21,7 +21,7 @@ in the source distribution for its full text. #define charBytes(n) (sizeof(CharType) * (n)) -static void RichString_extendLen(RichString* this, int len) { +static void RichString_extendLen(RichString* this, size_t len) { if (this->chptr == this->chstr) { // String is in internal buffer if (len > RICHSTRING_MAXLEN) { @@ -49,7 +49,7 @@ static void RichString_extendLen(RichString* this, int len) { this->chlen = len; } -static void RichString_setLen(RichString* this, int len) { +static void RichString_setLen(RichString* this, size_t len) { if (len <= RICHSTRING_MAXLEN && this->chlen <= RICHSTRING_MAXLEN) { RichString_setChar(this, len, 0); this->chlen = len; @@ -58,7 +58,7 @@ static void RichString_setLen(RichString* this, int len) { } } -void RichString_rewind(RichString* this, int count) { +void RichString_rewind(RichString* this, size_t count) { RichString_setLen(this, this->chlen > count ? this->chlen - count : 0); } @@ -95,33 +95,33 @@ static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src return written; } -static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) { +static inline size_t RichString_writeFromWide(RichString* this, int attrs, const char* data_c, size_t from, size_t len) { wchar_t data[len]; len = mbstowcs_nonfatal(data, data_c, len); if (len <= 0) return 0; - int newLen = from + len; + size_t newLen = from + len; RichString_setLen(this, newLen); - for (int i = from, j = 0; i < newLen; i++, j++) { + for (size_t i = from, j = 0; i < newLen; i++, j++) { this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (iswprint(data[j]) ? data[j] : L'\xFFFD') } }; } return len; } -int RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, int len, int* columns) { +size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, size_t len, int* columns) { wchar_t data[len]; len = mbstowcs_nonfatal(data, data_c, len); if (len <= 0) return 0; - int from = this->chlen; - int newLen = from + len; + size_t from = this->chlen; + size_t newLen = from + len; RichString_setLen(this, newLen); int columnsWritten = 0; - int pos = from; - for (int j = 0; j < len; j++) { + size_t pos = from; + for (size_t j = 0; j < len; j++) { wchar_t c = iswprint(data[j]) ? data[j] : L'\xFFFD'; int cwidth = wcwidth(c); if (cwidth > *columns) @@ -140,10 +140,10 @@ int RichString_appendnWideColumns(RichString* this, int attrs, const char* data_ return pos - from; } -static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data, int from, int len) { - int newLen = from + len; +static inline size_t RichString_writeFromAscii(RichString* this, int attrs, const char* data, size_t from, size_t len) { + size_t newLen = from + len; RichString_setLen(this, newLen); - for (int i = from, j = 0; i < newLen; i++, j++) { + for (size_t i = from, j = 0; i < newLen; i++, j++) { assert((unsigned char)data[j] <= SCHAR_MAX); this->chptr[i] = (CharType) { .attr = attrs & 0xffffff, .chars = { (isprint((unsigned char)data[j]) ? data[j] : L'\xFFFD') } }; } @@ -151,39 +151,39 @@ static inline int RichString_writeFromAscii(RichString* this, int attrs, const c return len; } -inline void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) { - int end = CLAMP(start + charcount, 0, this->chlen); - for (int i = start; i < end; i++) { +inline void RichString_setAttrn(RichString* this, int attrs, size_t start, size_t charcount) { + size_t end = CLAMP(start + charcount, 0, this->chlen); + for (size_t i = start; i < end; i++) { this->chptr[i].attr = attrs; } } -void RichString_appendChr(RichString* this, int attrs, char c, int count) { - int from = this->chlen; - int newLen = from + count; +void RichString_appendChr(RichString* this, int attrs, char c, size_t count) { + size_t from = this->chlen; + size_t newLen = from + count; RichString_setLen(this, newLen); - for (int i = from; i < newLen; i++) { + for (size_t i = from; i < newLen; i++) { this->chptr[i] = (CharType) { .attr = attrs, .chars = { c, 0 } }; } } -int RichString_findChar(const RichString* this, char c, int start) { +size_t RichString_findChar(const RichString* this, char c, size_t start) { const wchar_t wc = btowc(c); const cchar_t* ch = this->chptr + start; - for (int i = start; i < this->chlen; i++) { + for (size_t i = start; i < this->chlen; i++) { if (ch->chars[0] == wc) return i; ch++; } - return -1; + return (size_t)-1; } #else /* HAVE_LIBNCURSESW */ -static inline int RichString_writeFromWide(RichString* this, int attrs, const char* data_c, int from, int len) { - int newLen = from + len; +static inline size_t RichString_writeFromWide(RichString* this, int attrs, const char* data_c, size_t from, size_t len) { + size_t newLen = from + len; RichString_setLen(this, newLen); - for (int i = from, j = 0; i < newLen; i++, j++) { + for (size_t i = from, j = 0; i < newLen; i++, j++) { this->chptr[i] = (((unsigned char)data_c[j]) >= 32 ? ((unsigned char)data_c[j]) : '?') | attrs; } this->chptr[newLen] = 0; @@ -191,40 +191,40 @@ static inline int RichString_writeFromWide(RichString* this, int attrs, const ch return len; } -int RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, int len, int* columns) { - int written = RichString_writeFromWide(this, attrs, data_c, this->chlen, MINIMUM(len, *columns)); - *columns = written; +size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, size_t len, int* columns) { + size_t written = RichString_writeFromWide(this, attrs, data_c, this->chlen, MINIMUM(len, (unsigned int)*columns)); + *columns = (int)written; return written; } -static inline int RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, int from, int len) { +static inline size_t RichString_writeFromAscii(RichString* this, int attrs, const char* data_c, size_t from, size_t len) { return RichString_writeFromWide(this, attrs, data_c, from, len); } -void RichString_setAttrn(RichString* this, int attrs, int start, int charcount) { - int end = CLAMP(start + charcount, 0, this->chlen); - for (int i = start; i < end; i++) { +void RichString_setAttrn(RichString* this, int attrs, size_t start, size_t charcount) { + size_t end = CLAMP(start + charcount, 0, this->chlen); + for (size_t i = start; i < end; i++) { this->chptr[i] = (this->chptr[i] & 0xff) | attrs; } } -void RichString_appendChr(RichString* this, int attrs, char c, int count) { - int from = this->chlen; - int newLen = from + count; +void RichString_appendChr(RichString* this, int attrs, char c, size_t count) { + size_t from = this->chlen; + size_t newLen = from + count; RichString_setLen(this, newLen); - for (int i = from; i < newLen; i++) { + for (size_t i = from; i < newLen; i++) { this->chptr[i] = c | attrs; } } -int RichString_findChar(const RichString* this, char c, int start) { +size_t RichString_findChar(const RichString* this, char c, size_t start) { const chtype* ch = this->chptr + start; - for (int i = start; i < this->chlen; i++) { + for (size_t i = start; i < this->chlen; i++) { if ((*ch & 0xff) == (chtype) c) return i; ch++; } - return -1; + return (size_t)-1; } #endif /* HAVE_LIBNCURSESW */ @@ -240,26 +240,26 @@ void RichString_setAttr(RichString* this, int attrs) { RichString_setAttrn(this, attrs, 0, this->chlen); } -int RichString_appendWide(RichString* this, int attrs, const char* data) { +size_t RichString_appendWide(RichString* this, int attrs, const char* data) { return RichString_writeFromWide(this, attrs, data, this->chlen, strlen(data)); } -int RichString_appendnWide(RichString* this, int attrs, const char* data, int len) { +size_t RichString_appendnWide(RichString* this, int attrs, const char* data, size_t len) { return RichString_writeFromWide(this, attrs, data, this->chlen, len); } -int RichString_writeWide(RichString* this, int attrs, const char* data) { +size_t RichString_writeWide(RichString* this, int attrs, const char* data) { return RichString_writeFromWide(this, attrs, data, 0, strlen(data)); } -int RichString_appendAscii(RichString* this, int attrs, const char* data) { +size_t RichString_appendAscii(RichString* this, int attrs, const char* data) { return RichString_writeFromAscii(this, attrs, data, this->chlen, strlen(data)); } -int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len) { +size_t RichString_appendnAscii(RichString* this, int attrs, const char* data, size_t len) { return RichString_writeFromAscii(this, attrs, data, this->chlen, len); } -int RichString_writeAscii(RichString* this, int attrs, const char* data) { +size_t RichString_writeAscii(RichString* this, int attrs, const char* data) { return RichString_writeFromAscii(this, attrs, data, 0, strlen(data)); } diff --git a/RichString.h b/RichString.h index 7783378bc..78f8005c8 100644 --- a/RichString.h +++ b/RichString.h @@ -7,6 +7,8 @@ Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */ +#include + #include "Macros.h" #include "ProvideCurses.h" @@ -40,7 +42,7 @@ in the source distribution for its full text. #define RICHSTRING_MAXLEN 350 typedef struct RichString_ { - int chlen; + size_t chlen; CharType* chptr; CharType chstr[RICHSTRING_MAXLEN + 1]; int highlightAttr; @@ -48,33 +50,33 @@ typedef struct RichString_ { void RichString_delete(RichString* this); -void RichString_rewind(RichString* this, int count); +void RichString_rewind(RichString* this, size_t count); -void RichString_setAttrn(RichString* this, int attrs, int start, int charcount); +void RichString_setAttrn(RichString* this, int attrs, size_t start, size_t charcount); -int RichString_findChar(const RichString* this, char c, int start); +size_t RichString_findChar(const RichString* this, char c, size_t start); void RichString_setAttr(RichString* this, int attrs); -void RichString_appendChr(RichString* this, int attrs, char c, int count); +void RichString_appendChr(RichString* this, int attrs, char c, size_t count); /* All appending and writing functions return the number of written characters (not columns). */ -int RichString_appendWide(RichString* this, int attrs, const char* data); +size_t RichString_appendWide(RichString* this, int attrs, const char* data); ATTR_ACCESS3_R(3, 4) -int RichString_appendnWide(RichString* this, int attrs, const char* data, int len); +size_t RichString_appendnWide(RichString* this, int attrs, const char* data, size_t len); /* columns takes the maximum number of columns to write and contains on return the number of columns written. */ -int RichString_appendnWideColumns(RichString* this, int attrs, const char* data, int len, int* columns); +size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* data, size_t len, int* columns); -int RichString_writeWide(RichString* this, int attrs, const char* data); +size_t RichString_writeWide(RichString* this, int attrs, const char* data); -int RichString_appendAscii(RichString* this, int attrs, const char* data); +size_t RichString_appendAscii(RichString* this, int attrs, const char* data); ATTR_ACCESS3_R(3, 4) -int RichString_appendnAscii(RichString* this, int attrs, const char* data, int len); +size_t RichString_appendnAscii(RichString* this, int attrs, const char* data, size_t len); -int RichString_writeAscii(RichString* this, int attrs, const char* data); +size_t RichString_writeAscii(RichString* this, int attrs, const char* data); #endif diff --git a/Row.c b/Row.c index 4c4415b64..e4722e980 100644 --- a/Row.c +++ b/Row.c @@ -215,16 +215,16 @@ void Row_printKBytes(RichString* str, unsigned long long number, bool coloring) if (number < 1000) { // Plain number, no markings len = xSnprintf(buffer, sizeof(buffer), "%5u ", (unsigned int)number); - RichString_appendnAscii(str, color, buffer, len); + RichString_appendnAscii(str, color, buffer, (unsigned int)len); return; } if (number < 100000) { // 2 digits for M, 3 digits for K len = xSnprintf(buffer, sizeof(buffer), "%2u", (unsigned int)(number / 1000)); - RichString_appendnAscii(str, nextUnitColor, buffer, len); + RichString_appendnAscii(str, nextUnitColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%03u ", (unsigned int)(number % 1000)); - RichString_appendnAscii(str, color, buffer, len); + RichString_appendnAscii(str, color, buffer, (unsigned int)len); return; } @@ -260,16 +260,16 @@ void Row_printKBytes(RichString* str, unsigned long long number, bool coloring) // 1 digit + decimal point + 2 digits // "9.76G", "9.99G", "9.76T", "9.99T", etc. len = xSnprintf(buffer, sizeof(buffer), "%1u", (unsigned int)number); - RichString_appendnAscii(str, color, buffer, len); + RichString_appendnAscii(str, color, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), ".%02u", (unsigned int)hundredths); } else { // 2 digits + decimal point + 1 digit // "97.6M", "99.9M", "10.0G", "99.9G", etc. len = xSnprintf(buffer, sizeof(buffer), "%2u", (unsigned int)number); - RichString_appendnAscii(str, color, buffer, len); + RichString_appendnAscii(str, color, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), ".%1u", (unsigned int)hundredths / 10); } - RichString_appendnAscii(str, prevUnitColor, buffer, len); + RichString_appendnAscii(str, prevUnitColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%c ", unitPrefixes[i]); } else if (number < 1000) { // 3 digits @@ -281,10 +281,10 @@ void Row_printKBytes(RichString* str, unsigned long long number, bool coloring) assert(number < 10000); len = xSnprintf(buffer, sizeof(buffer), "%1u", (unsigned int)number / 1000); - RichString_appendnAscii(str, nextUnitColor, buffer, len); + RichString_appendnAscii(str, nextUnitColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%03u%c ", (unsigned int)number % 1000, unitPrefixes[i]); } - RichString_appendnAscii(str, color, buffer, len); + RichString_appendnAscii(str, color, buffer, (unsigned int)len); return; invalidNumber: @@ -357,14 +357,14 @@ void Row_printTime(RichString* str, unsigned long long totalHundredths, bool col if (totalMinutes < 60) { unsigned int hundredths = totalHundredths % 100; len = xSnprintf(buffer, sizeof(buffer), "%2u:%02u.%02u ", (unsigned int)totalMinutes, seconds, hundredths); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } if (totalHours < 24) { len = xSnprintf(buffer, sizeof(buffer), "%2uh", (unsigned int)totalHours); - RichString_appendnAscii(str, hourColor, buffer, len); + RichString_appendnAscii(str, hourColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%02u:%02u ", minutes, seconds); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } @@ -372,18 +372,18 @@ void Row_printTime(RichString* str, unsigned long long totalHundredths, bool col unsigned int hours = totalHours % 24; if (totalDays < 10) { len = xSnprintf(buffer, sizeof(buffer), "%1ud", (unsigned int)totalDays); - RichString_appendnAscii(str, dayColor, buffer, len); + RichString_appendnAscii(str, dayColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%02uh", hours); - RichString_appendnAscii(str, hourColor, buffer, len); + RichString_appendnAscii(str, hourColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%02um ", minutes); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } if (totalDays < /* Ignore leap years */365) { len = xSnprintf(buffer, sizeof(buffer), "%4ud", (unsigned int)totalDays); - RichString_appendnAscii(str, dayColor, buffer, len); + RichString_appendnAscii(str, dayColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%02uh ", hours); - RichString_appendnAscii(str, hourColor, buffer, len); + RichString_appendnAscii(str, hourColor, buffer, (unsigned int)len); return; } @@ -391,12 +391,12 @@ void Row_printTime(RichString* str, unsigned long long totalHundredths, bool col unsigned int days = totalDays % 365; if (years < 1000) { len = xSnprintf(buffer, sizeof(buffer), "%3uy", (unsigned int)years); - RichString_appendnAscii(str, yearColor, buffer, len); + RichString_appendnAscii(str, yearColor, buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%03ud ", days); - RichString_appendnAscii(str, dayColor, buffer, len); + RichString_appendnAscii(str, dayColor, buffer, (unsigned int)len); } else if (years < 10000000) { len = xSnprintf(buffer, sizeof(buffer), "%7luy ", (unsigned long)years); - RichString_appendnAscii(str, yearColor, buffer, len); + RichString_appendnAscii(str, yearColor, buffer, (unsigned int)len); } else { RichString_appendAscii(str, yearColor, "eternity "); } @@ -416,14 +416,14 @@ void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds, if (totalNanoseconds < 1000000) { len = xSnprintf(buffer, sizeof(buffer), "%6luns ", (unsigned long)totalNanoseconds); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } unsigned long long totalMicroseconds = totalNanoseconds / 1000; if (totalMicroseconds < 1000000) { len = xSnprintf(buffer, sizeof(buffer), ".%06lus ", (unsigned long)totalMicroseconds); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } @@ -437,7 +437,7 @@ void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds, fraction /= 10; } len = xSnprintf(buffer, sizeof(buffer), "%u.%0*lus ", (unsigned int)totalSeconds, width, fraction); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } @@ -446,7 +446,7 @@ void Row_printNanoseconds(RichString* str, unsigned long long totalNanoseconds, unsigned int seconds = totalSeconds % 60; unsigned int milliseconds = microseconds / 1000; len = xSnprintf(buffer, sizeof(buffer), "%u:%02u.%03u ", minutes, seconds, milliseconds); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); return; } @@ -471,25 +471,25 @@ void Row_printRate(RichString* str, double rate, bool coloring) { RichString_appendAscii(str, shadowColor, " N/A "); } else if (rate < 0.005) { int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); - RichString_appendnAscii(str, shadowColor, buffer, len); + RichString_appendnAscii(str, shadowColor, buffer, (unsigned int)len); } else if (rate < ONE_K) { int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); } else if (rate < ONE_M) { int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K); - RichString_appendnAscii(str, baseColor, buffer, len); + RichString_appendnAscii(str, baseColor, buffer, (unsigned int)len); } else if (rate < ONE_G) { int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M); - RichString_appendnAscii(str, megabytesColor, buffer, len); + RichString_appendnAscii(str, megabytesColor, buffer, (unsigned int)len); } else if (rate < ONE_T) { int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G); - RichString_appendnAscii(str, largeNumberColor, buffer, len); + RichString_appendnAscii(str, largeNumberColor, buffer, (unsigned int)len); } else if (rate < ONE_P) { int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T); - RichString_appendnAscii(str, largeNumberColor, buffer, len); + RichString_appendnAscii(str, largeNumberColor, buffer, (unsigned int)len); } else { int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P); - RichString_appendnAscii(str, largeNumberColor, buffer, len); + RichString_appendnAscii(str, largeNumberColor, buffer, (unsigned int)len); } } @@ -497,7 +497,7 @@ void Row_printLeftAlignedField(RichString* str, int attr, const char* content, u assert(width <= INT_MAX); int columns = (int)width; RichString_appendnWideColumns(str, attr, content, strlen(content), &columns); - RichString_appendChr(str, attr, ' ', width + 1 - columns); + RichString_appendChr(str, attr, ' ', width - (unsigned int)columns + 1); } int Row_printPercentage(float val, char* buffer, size_t n, uint8_t width, int* attr) { diff --git a/TasksMeter.c b/TasksMeter.c index fc1e4b0ed..1ab75f152 100644 --- a/TasksMeter.c +++ b/TasksMeter.c @@ -46,21 +46,21 @@ static void TasksMeter_display(const Object* cast, RichString* out) { int len; len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[2]); - RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, len); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, (unsigned int)len); RichString_appendAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], ", "); len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[1]); - RichString_appendnAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[TASKS_RUNNING], buffer, len); + RichString_appendnAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[TASKS_RUNNING], buffer, (unsigned int)len); RichString_appendAscii(out, settings->hideUserlandThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], " thr"); RichString_appendAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], ", "); len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[0]); - RichString_appendnAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[TASKS_RUNNING], buffer, len); + RichString_appendnAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[TASKS_RUNNING], buffer, (unsigned int)len); RichString_appendAscii(out, settings->hideKernelThreads ? CRT_colors[METER_SHADOW] : CRT_colors[METER_TEXT], " kthr"); RichString_appendAscii(out, CRT_colors[METER_TEXT], "; "); len = xSnprintf(buffer, sizeof(buffer), "%d", (int)this->values[3]); - RichString_appendnAscii(out, CRT_colors[TASKS_RUNNING], buffer, len); + RichString_appendnAscii(out, CRT_colors[TASKS_RUNNING], buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " running"); } diff --git a/linux/GPUMeter.c b/linux/GPUMeter.c index 531878b92..e0f6e5032 100644 --- a/linux/GPUMeter.c +++ b/linux/GPUMeter.c @@ -126,10 +126,10 @@ static void GPUMeter_display(const Object* cast, RichString* out) { RichString_writeAscii(out, CRT_colors[METER_TEXT], ":"); written = xSnprintf(buffer, sizeof(buffer), "%4.1f", totalUsage); - RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, (unsigned int)written); RichString_appendAscii(out, CRT_colors[METER_TEXT], "%("); written = humanTimeUnit(buffer, sizeof(buffer), totalGPUTimeDiff); - RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, (unsigned int)written); RichString_appendAscii(out, CRT_colors[METER_TEXT], ")"); for (i = 0; i < ARRAYSIZE(GPUMeter_engineData); i++) { @@ -143,10 +143,10 @@ static void GPUMeter_display(const Object* cast, RichString* out) { written = xSnprintf(buffer, sizeof(buffer), "%4.1f", this->values[i]); else written = xSnprintf(buffer, sizeof(buffer), " N/A"); - RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, (unsigned int)written); RichString_appendAscii(out, CRT_colors[METER_TEXT], "%("); written = humanTimeUnit(buffer, sizeof(buffer), GPUMeter_engineData[i].timeDiff); - RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written); + RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, (unsigned int)written); RichString_appendAscii(out, CRT_colors[METER_TEXT], ")"); } } diff --git a/linux/PressureStallMeter.c b/linux/PressureStallMeter.c index 5010c11d2..899db40b4 100644 --- a/linux/PressureStallMeter.c +++ b/linux/PressureStallMeter.c @@ -60,11 +60,11 @@ static void PressureStallMeter_display(const Object* cast, RichString* out) { int len; len = xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[0]); - RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_TEN], buffer, len); + RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_TEN], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[1]); - RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer, len); + RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_SIXTY], buffer, (unsigned int)len); len = xSnprintf(buffer, sizeof(buffer), "%5.2lf%% ", this->values[2]); - RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer, len); + RichString_appendnAscii(out, CRT_colors[PRESSURE_STALL_THREEHUNDRED], buffer, (unsigned int)len); } const MeterClass PressureStallCPUSomeMeter_class = { diff --git a/linux/SystemdMeter.c b/linux/SystemdMeter.c index a8df75e9e..5db2260a9 100644 --- a/linux/SystemdMeter.c +++ b/linux/SystemdMeter.c @@ -349,7 +349,7 @@ static void _SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* ou } else { len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nFailedUnits); } - RichString_appendnAscii(out, zeroDigitColor(ctx->nFailedUnits), buffer, len); + RichString_appendnAscii(out, zeroDigitColor(ctx->nFailedUnits), buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], "/"); @@ -360,7 +360,7 @@ static void _SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* ou } else { len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nNames); } - RichString_appendnAscii(out, valueDigitColor(ctx->nNames), buffer, len); + RichString_appendnAscii(out, valueDigitColor(ctx->nNames), buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " failed) ("); @@ -371,7 +371,7 @@ static void _SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* ou } else { len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nJobs); } - RichString_appendnAscii(out, zeroDigitColor(ctx->nJobs), buffer, len); + RichString_appendnAscii(out, zeroDigitColor(ctx->nJobs), buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], "/"); @@ -382,7 +382,7 @@ static void _SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* ou } else { len = xSnprintf(buffer, sizeof(buffer), "%u", ctx->nInstalledJobs); } - RichString_appendnAscii(out, valueDigitColor(ctx->nInstalledJobs), buffer, len); + RichString_appendnAscii(out, valueDigitColor(ctx->nInstalledJobs), buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " jobs)"); } diff --git a/pcp/PCPDynamicColumn.c b/pcp/PCPDynamicColumn.c index 6ea7d5108..0643f3f96 100644 --- a/pcp/PCPDynamicColumn.c +++ b/pcp/PCPDynamicColumn.c @@ -368,7 +368,7 @@ void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, if (atomvalue == NULL) { n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, "N/A"); - RichString_appendnAscii(str, CRT_colors[PROCESS_SHADOW], buffer, n); + RichString_appendnAscii(str, CRT_colors[PROCESS_SHADOW], buffer, (unsigned int)n); return; } @@ -404,7 +404,7 @@ void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, } if (dupd1) free(dupd1); - RichString_appendnAscii(str, attr, buffer, n); + RichString_appendnAscii(str, attr, buffer, (unsigned int)n); return; } @@ -412,19 +412,19 @@ void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, double value; if (PCPDynamicColumn_normalize(desc, atomvalue, &value) < 0) { n = xSnprintf(buffer, sizeof(buffer), "%*.*s ", width, abswidth, "no conv"); - RichString_appendnAscii(str, CRT_colors[METER_VALUE_ERROR], buffer, n); + RichString_appendnAscii(str, CRT_colors[METER_VALUE_ERROR], buffer, (unsigned int)n); return; } if (column->format) { if (strcmp(column->format, "percent") == 0) { n = Row_printPercentage(value, buffer, sizeof(buffer), width, &attr); - RichString_appendnAscii(str, attr, buffer, n); + RichString_appendnAscii(str, attr, buffer, (unsigned int)n); return; } if (strcmp(column->format, "process") == 0) { n = xSnprintf(buffer, sizeof(buffer), "%*d ", Row_pidDigits, (int)value); - RichString_appendnAscii(str, attr, buffer, n); + RichString_appendnAscii(str, attr, buffer, (unsigned int)n); return; } } @@ -435,7 +435,7 @@ void PCPDynamicColumn_writeAtomValue(PCPDynamicColumn* column, RichString* str, n = xSnprintf(buffer, sizeof(buffer), "%*.2f ", width, value); else /* display as integer */ n = xSnprintf(buffer, sizeof(buffer), "%*llu ", width, (unsigned long long)value); - RichString_appendnAscii(str, CRT_colors[PROCESS], buffer, n); + RichString_appendnAscii(str, CRT_colors[PROCESS], buffer, (unsigned int)n); return; } diff --git a/pcp/PCPDynamicMeter.c b/pcp/PCPDynamicMeter.c index 57c84dddc..96cb8b527 100644 --- a/pcp/PCPDynamicMeter.c +++ b/pcp/PCPDynamicMeter.c @@ -461,7 +461,7 @@ void PCPDynamicMeter_display(PCPDynamicMeter* this, ATTR_UNUSED const Meter* met } if (len) { - RichString_appendnAscii(out, CRT_colors[metric->color], buffer, len); + RichString_appendnAscii(out, CRT_colors[metric->color], buffer, (unsigned int)len); if (metric->suffix) RichString_appendAscii(out, CRT_colors[METER_TEXT], metric->suffix); } diff --git a/zfs/ZfsCompressedArcMeter.c b/zfs/ZfsCompressedArcMeter.c index 35ab8b379..cea97234c 100644 --- a/zfs/ZfsCompressedArcMeter.c +++ b/zfs/ZfsCompressedArcMeter.c @@ -63,7 +63,7 @@ static void ZfsCompressedArcMeter_display(const Object* cast, RichString* out) { RichString_appendAscii(out, CRT_colors[METER_VALUE], buffer); RichString_appendAscii(out, CRT_colors[METER_TEXT], " Compressed, "); len = ZfsCompressedArcMeter_printRatioString(this, buffer, sizeof(buffer)); - RichString_appendnAscii(out, CRT_colors[ZFS_RATIO], buffer, len); + RichString_appendnAscii(out, CRT_colors[ZFS_RATIO], buffer, (unsigned int)len); RichString_appendAscii(out, CRT_colors[METER_TEXT], " Ratio"); } else { RichString_writeAscii(out, CRT_colors[METER_TEXT], " "); From 265f6813afc850376c865989b19d42f4345f394e Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 21 Jan 2025 03:48:58 +0800 Subject: [PATCH 20/23] Add size limit checks to RichString methods Prevent arithmetic overflows when computing new string sizes. For RichString_appendnWideColumns(), the "*columns" argument is now allowed to be -1 on input, which would be interpreted as "unlimited terminal columns". On output, the "*columns" value will now cap to INT_MAX if the input string is extremely large, and the width counted can overflow an `int` type. (The "*columns" buffer is intentionally not changed to using `size_t` type.) Signed-off-by: Kang-Che Sung --- RichString.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/RichString.c b/RichString.c index df5c2b77d..f79e6efe3 100644 --- a/RichString.c +++ b/RichString.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include #include #include // IWYU pragma: keep +#include #include #include @@ -22,6 +23,10 @@ in the source distribution for its full text. #define charBytes(n) (sizeof(CharType) * (n)) static void RichString_extendLen(RichString* this, size_t len) { + if (len > SIZE_MAX / sizeof(CharType) - 1) { + fail(); + } + if (this->chptr == this->chstr) { // String is in internal buffer if (len > RICHSTRING_MAXLEN) { @@ -101,6 +106,9 @@ static inline size_t RichString_writeFromWide(RichString* this, int attrs, const if (len <= 0) return 0; + if (from > SIZE_MAX - len) { + fail(); + } size_t newLen = from + len; RichString_setLen(this, newLen); for (size_t i = from, j = 0; i < newLen; i++, j++) { @@ -117,6 +125,9 @@ size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* da return 0; size_t from = this->chlen; + if (from > SIZE_MAX - len) { + fail(); + } size_t newLen = from + len; RichString_setLen(this, newLen); int columnsWritten = 0; @@ -124,11 +135,18 @@ size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* da for (size_t j = 0; j < len; j++) { wchar_t c = iswprint(data[j]) ? data[j] : L'\xFFFD'; int cwidth = wcwidth(c); - if (cwidth > *columns) - break; + if (*columns >= 0) { + if (cwidth > *columns) + break; - *columns -= cwidth; - columnsWritten += cwidth; + *columns -= cwidth; + } + + if ((unsigned int)columnsWritten <= INT_MAX - (unsigned int)cwidth) { + columnsWritten += cwidth; + } else { + columnsWritten = INT_MAX; + } this->chptr[pos] = (CharType) { .attr = attrs & 0xffffff, .chars = { c, '\0' } }; pos++; @@ -141,6 +159,9 @@ size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* da } static inline size_t RichString_writeFromAscii(RichString* this, int attrs, const char* data, size_t from, size_t len) { + if (from > SIZE_MAX - len) { + fail(); + } size_t newLen = from + len; RichString_setLen(this, newLen); for (size_t i = from, j = 0; i < newLen; i++, j++) { @@ -152,7 +173,7 @@ static inline size_t RichString_writeFromAscii(RichString* this, int attrs, cons } inline void RichString_setAttrn(RichString* this, int attrs, size_t start, size_t charcount) { - size_t end = CLAMP(start + charcount, 0, this->chlen); + size_t end = start <= SIZE_MAX - charcount ? MINIMUM(start + charcount, this->chlen) : this->chlen; for (size_t i = start; i < end; i++) { this->chptr[i].attr = attrs; } @@ -160,6 +181,9 @@ inline void RichString_setAttrn(RichString* this, int attrs, size_t start, size_ void RichString_appendChr(RichString* this, int attrs, char c, size_t count) { size_t from = this->chlen; + if (from > SIZE_MAX - count) { + fail(); + } size_t newLen = from + count; RichString_setLen(this, newLen); for (size_t i = from; i < newLen; i++) { @@ -181,6 +205,9 @@ size_t RichString_findChar(const RichString* this, char c, size_t start) { #else /* HAVE_LIBNCURSESW */ static inline size_t RichString_writeFromWide(RichString* this, int attrs, const char* data_c, size_t from, size_t len) { + if (from > SIZE_MAX - len) { + fail(); + } size_t newLen = from + len; RichString_setLen(this, newLen); for (size_t i = from, j = 0; i < newLen; i++, j++) { @@ -192,8 +219,12 @@ static inline size_t RichString_writeFromWide(RichString* this, int attrs, const } size_t RichString_appendnWideColumns(RichString* this, int attrs, const char* data_c, size_t len, int* columns) { - size_t written = RichString_writeFromWide(this, attrs, data_c, this->chlen, MINIMUM(len, (unsigned int)*columns)); - *columns = (int)written; + if (*columns >= 0 && (unsigned int)*columns < len) { + len = (unsigned int)*columns; + } + size_t written = RichString_writeFromWide(this, attrs, data_c, this->chlen, len); + + *columns = (int)MINIMUM(INT_MAX, written); return written; } @@ -202,7 +233,7 @@ static inline size_t RichString_writeFromAscii(RichString* this, int attrs, cons } void RichString_setAttrn(RichString* this, int attrs, size_t start, size_t charcount) { - size_t end = CLAMP(start + charcount, 0, this->chlen); + size_t end = start <= SIZE_MAX - charcount ? MINIMUM(start + charcount, this->chlen) : this->chlen; for (size_t i = start; i < end; i++) { this->chptr[i] = (this->chptr[i] & 0xff) | attrs; } @@ -210,6 +241,9 @@ void RichString_setAttrn(RichString* this, int attrs, size_t start, size_t charc void RichString_appendChr(RichString* this, int attrs, char c, size_t count) { size_t from = this->chlen; + if (from > SIZE_MAX - count) { + fail(); + } size_t newLen = from + count; RichString_setLen(this, newLen); for (size_t i = from; i < newLen; i++) { From 65e15d12c1737e8b29ec4577656075a554b925a9 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 21 Mar 2025 02:51:41 +0800 Subject: [PATCH 21/23] Improve BarMeterMode_draw() limit check after data type changes Signed-off-by: Kang-Che Sung --- Meter.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Meter.c b/Meter.c index 889f127eb..fda520cac 100644 --- a/Meter.c +++ b/Meter.c @@ -128,12 +128,11 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { if (isPositive(value) && this->total > 0.0) { value = MINIMUM(value, this->total); blockSizes[i] = ceil((value / this->total) * w); + blockSizes[i] = MINIMUM(blockSizes[i], MINIMUM(INT_MAX - x, w) - offset); } else { blockSizes[i] = 0; } int nextOffset = offset + blockSizes[i]; - // (Control against invalid values) - nextOffset = CLAMP(nextOffset, 0, w); for (int j = offset; j < nextOffset; j++) if (RichString_getCharVal(bar, startPos + (unsigned int)j) == ' ') { if (CRT_colorScheme == COLORSCHEME_MONOCHROME) { @@ -151,9 +150,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { for (uint8_t i = 0; i < this->curItems; i++) { int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i]; RichString_setAttrn(&bar, CRT_colors[attr], startPos + (unsigned int)offset, blockSizes[i]); - RichString_printoffnVal(bar, y, x + offset, startPos + (unsigned int)offset, MINIMUM(blockSizes[i], w - offset)); + RichString_printoffnVal(bar, y, x + offset, startPos + (unsigned int)offset, blockSizes[i]); offset += blockSizes[i]; - offset = CLAMP(offset, 0, w); } if (offset < w) { RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + (unsigned int)offset, (unsigned int)(w - offset)); From 9b47f1931c231d85917a63ed03c2a842b094cfb3 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:39:34 +0800 Subject: [PATCH 22/23] Improve LEDMeterMode_draw() limit check after data type changes Signed-off-by: Kang-Che Sung --- Meter.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Meter.c b/Meter.c index fda520cac..fc46cb02d 100644 --- a/Meter.c +++ b/Meter.c @@ -316,26 +316,28 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) { attrset(CRT_colors[LED_COLOR]); const char* caption = Meter_getCaption(this); mvaddstr(yText, x, caption); - int xx = x + (int)strlen(caption); - size_t len = RichString_sizeVal(out); - for (size_t i = 0; i < len; i++) { - int c = RichString_getCharVal(out, i); - if (c >= '0' && c <= '9') { - if (xx - x + 4 > w) - break; - - LEDMeterMode_drawDigit(xx, y, c - '0'); - xx += 4; - } else { - if (xx - x + 1 > w) - break; + if (strlen(caption) <= INT_MAX - (unsigned int)x) { + int xx = x + (int)strlen(caption); + size_t len = RichString_sizeVal(out); + for (size_t i = 0; i < len; i++) { + int c = RichString_getCharVal(out, i); + if (c >= '0' && c <= '9') { + if (xx - x + 4 > w) + break; + + LEDMeterMode_drawDigit(xx, y, c - '0'); + xx += 4; + } else { + if (xx - x + 1 > w) + break; #ifdef HAVE_LIBNCURSESW - const cchar_t wc = { .chars = { c, '\0' }, .attr = 0 }; /* use LED_COLOR from attrset() */ - mvadd_wch(yText, xx, &wc); + const cchar_t wc = { .chars = { c, '\0' }, .attr = 0 }; /* use LED_COLOR from attrset() */ + mvadd_wch(yText, xx, &wc); #else - mvaddch(yText, xx, c); + mvaddch(yText, xx, c); #endif - xx += 1; + xx += 1; + } } } attrset(CRT_colors[RESET_COLOR]); From e007e80ed613ca2d84c7bf31b5b836c4af5335b8 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 21 Jan 2025 04:46:55 +0800 Subject: [PATCH 23/23] Introduce RichString_append{,n}FormatAscii functions --- RichString.c | 43 +++++++++++++++++++++++++++++++++++++++++++ RichString.h | 6 ++++++ 2 files changed, 49 insertions(+) diff --git a/RichString.c b/RichString.c index f79e6efe3..1189ff146 100644 --- a/RichString.c +++ b/RichString.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include #include #include // IWYU pragma: keep +#include #include #include #include @@ -297,3 +298,45 @@ size_t RichString_appendnAscii(RichString* this, int attrs, const char* data, si size_t RichString_writeAscii(RichString* this, int attrs, const char* data) { return RichString_writeFromAscii(this, attrs, data, 0, strlen(data)); } + +ATTR_FORMAT(printf, 5, 0) ATTR_NONNULL_N(1, 3, 5) +static size_t RichString_appendvnFormatAscii(RichString* this, int attrs, char* buf, size_t len, const char* fmt, va_list vl) { + // The temporary "buf" does not need to be NUL-terminated. + int ret = vsnprintf(buf, len, fmt, vl); + if (ret < 0 || (unsigned int)ret > len) { + fail(); + } + + return RichString_appendnAscii(this, attrs, buf, (unsigned int)ret); +} + +size_t RichString_appendnFormatAscii(RichString* this, int attrs, char* buf, size_t len, const char* fmt, ...) { + va_list vl; + va_start(vl, fmt); + size_t ret = RichString_appendvnFormatAscii(this, attrs, buf, len, fmt, vl); + va_end(vl); + + return ret; +} + +ATTR_FORMAT(printf, 3, 0) ATTR_NONNULL_N(1, 3) +static size_t RichString_appendvFormatAscii(RichString* this, int attrs, const char* fmt, va_list vl) { + char* buf; + int ret = vasprintf(&buf, fmt, vl); + if (ret < 0 || !buf) { + fail(); + } + + size_t len = RichString_appendnAscii(this, attrs, buf, (unsigned int)ret); + free(buf); + return len; +} + +size_t RichString_appendFormatAscii(RichString* this, int attrs, const char* fmt, ...) { + va_list vl; + va_start(vl, fmt); + size_t len = RichString_appendvFormatAscii(this, attrs, fmt, vl); + va_end(vl); + + return len; +} diff --git a/RichString.h b/RichString.h index 78f8005c8..71eee8435 100644 --- a/RichString.h +++ b/RichString.h @@ -79,4 +79,10 @@ size_t RichString_appendnAscii(RichString* this, int attrs, const char* data, si size_t RichString_writeAscii(RichString* this, int attrs, const char* data); +ATTR_FORMAT(printf, 5, 6) ATTR_NONNULL_N(1, 3, 5) +size_t RichString_appendnFormatAscii(RichString* this, int attrs, char* buf, size_t len, const char* fmt, ...); + +ATTR_FORMAT(printf, 3, 4) ATTR_NONNULL_N(1, 3) +size_t RichString_appendFormatAscii(RichString* this, int attrs, const char* fmt, ...); + #endif