From 233c953f08bf0b091fc232df58012be2ec2e4469 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 16 Jan 2025 04:35:08 +0800 Subject: [PATCH 01/22] Fix potential out of bound access in PCPProcessTable_updateCmdline() Signed-off-by: Kang-Che Sung --- pcp/PCPProcessTable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcp/PCPProcessTable.c b/pcp/PCPProcessTable.c index 4999bdc27..d6d7bad95 100644 --- a/pcp/PCPProcessTable.c +++ b/pcp/PCPProcessTable.c @@ -316,7 +316,7 @@ static void PCPProcessTable_updateCmdline(Process* process, int pid, int offset, } else { ++command; --length; - if (command[length - 1] == ')') + if (length > 0 && command[length - 1] == ')') command[--length] = '\0'; process->isKernelThread = true; } From 160c0661a89db01965bdd404364ea23de7a31ec5 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 17 Jan 2025 03:38:45 +0800 Subject: [PATCH 02/22] 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 910443e99..4f4b25f3b 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 f83ab04fb32bcca36c0e00bfbfa56e56f1209036 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 17 Jan 2025 03:58:56 +0800 Subject: [PATCH 03/22] 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 | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Process.c b/Process.c index 4f4b25f3b..80c9090c4 100644 --- a/Process.c +++ b/Process.c @@ -321,6 +321,27 @@ 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) { + cmdlineBasenameStart = matchLen - exeBasenameLen; + cmdlineBasenameEnd = matchLen; + } + } + 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) { @@ -350,13 +371,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; @@ -395,8 +409,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd); } - int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen); - bool haveCommField = false; if (!haveCommInExe && !haveCommInCmdline && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { From 56654dddafbd713470ea3868b62190b7e92b3cba Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 17 Jan 2025 06:28:49 +0800 Subject: [PATCH 04/22] 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 | 63 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/Process.c b/Process.c index 80c9090c4..72aeae279 100644 --- a/Process.c +++ b/Process.c @@ -371,17 +371,52 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { return; } + size_t 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; + int commEnd = 0; + + if (!haveCommInExe && this->cmdline && procComm && searchCommInCmdline && (!Process_isUserlandThread(this) || showThreadNames)) { + haveCommInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd); + } + if (haveCommInCmdline) { + commLen = commEnd - commStart; + } + + 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); @@ -390,7 +425,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); @@ -399,16 +434,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { str = stpcpy(str, procExe + exeBasenameOffset); } - bool haveCommInCmdline = false; - int commStart = 0; - int commEnd = 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); - } - bool haveCommField = false; if (!haveCommInExe && !haveCommInCmdline && procComm && (!Process_isUserlandThread(this) || showThreadNames)) { @@ -418,18 +443,6 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { haveCommField = true; } - if (matchLen) { - if (stripExeFromCmdline) { - /* strip the matched exe prefix */ - cmdline += matchLen; - - commStart -= matchLen; - commEnd -= matchLen; - } else { - matchLen = 0; - } - } - if (!matchLen || (haveCommField && *cmdline)) { /* cmdline will be a separate field */ WRITE_SEPARATOR; @@ -439,7 +452,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 9a395cb33858d15e1df43908058210e8a36b2894 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 17 Jan 2025 06:32:37 +0800 Subject: [PATCH 05/22] 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 72aeae279..346baac40 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, size_t cmdlineBasenameStart, size_t* pCommStart, size_t* pCommEnd) { /* 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,21 +72,18 @@ 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; - *pCommEnd = token - cmdline; + *pCommStart = (size_t)(tokenBase - cmdline); + *pCommEnd = (size_t)(token - cmdline); 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 cmdlineBaseOffset, const char* exe, int exeBaseOffset, int exeBaseLen) { - int matchLen; /* matching length to be returned */ +static size_t matchCmdlinePrefixWithExeSuffix(const char* cmdline, size_t cmdlineBaseOffset, 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] == '/') { @@ -134,14 +131,14 @@ static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseO 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] == '/') return matchLen; } } @@ -149,6 +146,9 @@ 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' */ delimFound = false; + if (cmdlineBaseOffset <= 2) { + return 0; + } for (cmdlineBaseOffset -= 2; cmdlineBaseOffset > 0; --cmdlineBaseOffset) { if (delimFound) { if (cmdline[cmdlineBaseOffset - 1] == '/') { @@ -309,8 +309,8 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { char* strStart = mc->str; char* str = strStart; - int cmdlineBasenameStart = this->cmdlineBasenameStart; - int cmdlineBasenameEnd = this->cmdlineBasenameEnd; + size_t cmdlineBasenameStart = this->cmdlineBasenameStart; + size_t cmdlineBasenameEnd = this->cmdlineBasenameEnd; if (!cmdline) { cmdlineBasenameStart = 0; @@ -318,20 +318,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); @@ -382,8 +380,8 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { } bool haveCommInCmdline = false; - int commStart = 0; - int commEnd = 0; + size_t commStart = 0; + size_t commEnd = 0; if (!haveCommInExe && this->cmdline && procComm && searchCommInCmdline && (!Process_isUserlandThread(this) || showThreadNames)) { haveCommInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd); @@ -470,7 +468,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; @@ -478,12 +476,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] == ':') { @@ -875,7 +873,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; } @@ -1027,12 +1025,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; @@ -1048,11 +1046,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; @@ -1085,7 +1082,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 2ef497a45..77da24a5e 100644 --- a/darwin/DarwinProcess.c +++ b/darwin/DarwinProcess.c @@ -232,7 +232,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++; @@ -243,7 +243,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); } } } @@ -257,7 +257,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 b1705904b..bf66351a8 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -1180,15 +1180,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; } @@ -1206,7 +1206,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; } @@ -1220,7 +1220,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; } @@ -1243,13 +1243,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; } @@ -1259,14 +1259,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; @@ -1282,39 +1282,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; } } @@ -1327,16 +1327,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 d6d7bad95..cdcec6081 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 9eb23432e59d795b1973ae887ea289717910576c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 17 Jan 2025 06:32:53 +0800 Subject: [PATCH 06/22] Simplify an expression in Process_updateExe() Signed-off-by: Kang-Che Sung --- Process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Process.c b/Process.c index 346baac40..7ca234498 100644 --- a/Process.c +++ b/Process.c @@ -1082,7 +1082,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) ? (size_t)(lastSlash - exe + 1) : 0; + this->procExeBasenameOffset = (lastSlash > exe && *(lastSlash + 1) != '\0') ? (size_t)(lastSlash - exe + 1) : 0; } else { this->procExe = NULL; this->procExeBasenameOffset = 0; From 473c8479b9c5ff80186a5066c7f74bce8ee338c8 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Fri, 17 Jan 2025 06:39:40 +0800 Subject: [PATCH 07/22] Simplify findCommInCmdline() logic in Process.c Signed-off-by: Kang-Che Sung --- Process.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Process.c b/Process.c index 7ca234498..9db13a647 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, size_t cmdlineBasenameStart, size_t* pCommStart, size_t* pCommEnd) { +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 */ @@ -83,7 +83,7 @@ static bool findCommInCmdline(const char* comm, const char* cmdline, size_t cmdl if ((tokenLen == commLen || (tokenLen > commLen && commLen == (TASK_COMM_LEN - 1))) && strncmp(tokenBase, comm, commLen) == 0) { *pCommStart = (size_t)(tokenBase - cmdline); - *pCommEnd = (size_t)(token - cmdline); + *pCommLen = tokenLen; return true; } @@ -381,13 +381,9 @@ void Process_makeCommandStr(Process* this, const Settings* settings) { bool haveCommInCmdline = false; size_t commStart = 0; - size_t commEnd = 0; if (!haveCommInExe && this->cmdline && procComm && searchCommInCmdline && (!Process_isUserlandThread(this) || showThreadNames)) { - haveCommInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd); - } - if (haveCommInCmdline) { - commLen = commEnd - commStart; + haveCommInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commLen); } if (!stripExeFromCmdline) { From 7ff906c597032548ab4b9329f4290b60808c6413 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:14:33 +0800 Subject: [PATCH 08/22] 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 390beb073..afdb49b48 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 bd27b7ea1a0595a3d89ab3a61ec35a805f3c926e Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:15:40 +0800 Subject: [PATCH 09/22] 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 afdb49b48..86a1e1860 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 1715ad078bde955e439ea70512dc16f1ee94959c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:15:53 +0800 Subject: [PATCH 10/22] Replace unnecessary RichString_appendnAscii() calls with appendAscii() 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 4ef38cb88001399a1f37222bb6cefadf3edde19c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:17:39 +0800 Subject: [PATCH 11/22] 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 1451ed77a..24c2ce595 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 fd5435588731cafce3bbfbc8ac79b9a00166f31f Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:18:30 +0800 Subject: [PATCH 12/22] 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 39c14cdf5db5a11db0bb6762ff4501adf6fc0641 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:21:32 +0800 Subject: [PATCH 13/22] 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 4784a6585..61af9a6ea 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 521e5635171117d2f19d6bf3545693111f7d4ec5 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:33:21 +0800 Subject: [PATCH 14/22] 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 61af9a6ea..2c14b77a2 100644 --- a/Panel.c +++ b/Panel.c @@ -254,8 +254,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++; @@ -293,7 +292,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; } @@ -303,8 +301,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); @@ -328,13 +326,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 78184a1d00bf47ae12d6ae7101516acbc13b276c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 05:33:59 +0800 Subject: [PATCH 15/22] 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 2c14b77a2..9d3f232b8 100644 --- a/Panel.c +++ b/Panel.c @@ -386,7 +386,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 e1013395eb697e5a1c451d36c1458299528aaaa7 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:28:14 +0800 Subject: [PATCH 16/22] 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 1b2b5742d..ec892bcdb 100644 --- a/CRT.h +++ b/CRT.h @@ -190,7 +190,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 47b2f92fe..298c665d6 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 9af21a7db66a799b3f311b334fc94cb1e7010678 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:28:43 +0800 Subject: [PATCH 17/22] 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 | 43 +++++++++-------- 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, 158 insertions(+), 157 deletions(-) diff --git a/CPUMeter.c b/CPUMeter.c index 24c2ce595..dcdc78cf7 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..04666c43d 100644 --- a/Meter.c +++ b/Meter.c @@ -96,46 +96,45 @@ 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)); - int blockSizes[10]; + unsigned int blockSizes[10]; // First draw in the bar[] buffer... - int offset = 0; + unsigned int offset = 0; for (uint8_t i = 0; i < this->curItems; i++) { double value = this->values[i]; if (isPositive(value) && this->total > 0.0) { value = MINIMUM(value, this->total); - blockSizes[i] = ceil((value / this->total) * w); + blockSizes[i] = (unsigned int)(int)ceil((value / this->total) * w); } else { blockSizes[i] = 0; } - int nextOffset = offset + blockSizes[i]; + unsigned int nextOffset = offset + blockSizes[i]; // (Control against invalid values) - nextOffset = CLAMP(nextOffset, 0, w); - for (int j = offset; j < nextOffset; j++) + nextOffset = CLAMP(nextOffset, 0, (unsigned int)w); + for (unsigned int j = offset; j < nextOffset; j++) if (RichString_getCharVal(bar, startPos + j) == ' ') { if (CRT_colorScheme == COLORSCHEME_MONOCHROME) { assert(i < strlen(BarMeterMode_characters)); @@ -152,13 +151,13 @@ 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 + offset, blockSizes[i]); - RichString_printoffnVal(bar, y, x + offset, startPos + offset, MINIMUM(blockSizes[i], w - offset)); + RichString_printoffnVal(bar, y, x + (int)offset, startPos + offset, MINIMUM((int)blockSizes[i], w - (int)offset)); offset += blockSizes[i]; - offset = CLAMP(offset, 0, w); + offset = CLAMP(offset, 0, (unsigned int)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); + if (offset < (unsigned int)w) { + RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, (unsigned int)w - offset); + RichString_printoffnVal(bar, y, x + (int)offset, startPos + offset, w - (int)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 86a1e1860..f701b45f3 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); } @@ -97,33 +97,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) @@ -142,10 +142,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') } }; } @@ -153,39 +153,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; @@ -193,40 +193,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 */ @@ -242,26 +242,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 4b32769185fd221d5705931e47223ad7465fcff9 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 21 Jan 2025 03:48:58 +0800 Subject: [PATCH 18/22] 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 f701b45f3..70bb81b5d 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) { @@ -103,6 +108,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++) { @@ -119,6 +127,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; @@ -126,11 +137,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++; @@ -143,6 +161,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++) { @@ -154,7 +175,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; } @@ -162,6 +183,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++) { @@ -183,6 +207,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++) { @@ -194,8 +221,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; } @@ -204,7 +235,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; } @@ -212,6 +243,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 5d61426289289dd0540524eec226a77c266b2fc8 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:39:10 +0800 Subject: [PATCH 19/22] Improve BarMeterMode_draw() limit check after data type changes Signed-off-by: Kang-Che Sung --- Meter.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Meter.c b/Meter.c index 04666c43d..c4d58f17a 100644 --- a/Meter.c +++ b/Meter.c @@ -116,8 +116,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { startPos = MINIMUM(startPos, (unsigned int)w); } - assert(startPos <= w); - assert(startPos + w <= RichString_sizeVal(bar)); + assert(startPos <= (unsigned int)w); + assert(startPos + (unsigned int)w <= RichString_sizeVal(bar)); unsigned int blockSizes[10]; @@ -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] = (unsigned int)(int)ceil((value / this->total) * w); + blockSizes[i] = MINIMUM(MINIMUM(INT_MAX - (unsigned int)x, (unsigned int)w) - offset, blockSizes[i]); } else { blockSizes[i] = 0; } unsigned int nextOffset = offset + blockSizes[i]; - // (Control against invalid values) - nextOffset = CLAMP(nextOffset, 0, (unsigned int)w); for (unsigned int j = offset; j < nextOffset; j++) if (RichString_getCharVal(bar, startPos + 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 + offset, blockSizes[i]); - RichString_printoffnVal(bar, y, x + (int)offset, startPos + offset, MINIMUM((int)blockSizes[i], w - (int)offset)); + RichString_printoffnVal(bar, y, x + (int)offset, startPos + offset, (int)blockSizes[i]); offset += blockSizes[i]; - offset = CLAMP(offset, 0, (unsigned int)w); } if (offset < (unsigned int)w) { RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, (unsigned int)w - offset); From 22deed3d6ef2d46ccd925d37e247e9544428dd98 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:39:34 +0800 Subject: [PATCH 20/22] 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 c4d58f17a..b622f57cd 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 1b8f1ab392d4f8362a432ae9304cc43a04f64452 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 19 Jan 2025 06:42:14 +0800 Subject: [PATCH 21/22] 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 70bb81b5d..f79e6efe3 100644 --- a/RichString.c +++ b/RichString.c @@ -74,8 +74,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; @@ -83,7 +83,6 @@ static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src written++; } src++; - n--; continue; } @@ -96,7 +95,6 @@ static size_t mbstowcs_nonfatal(wchar_t* restrict dest, const char* restrict src dest++; written++; src += ret; - n -= ret; } return written; From 005c9b6a473fedd8c861d85d93f4bc2168dddd2c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 21 Jan 2025 04:46:55 +0800 Subject: [PATCH 22/22] 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