Skip to content

Conversation

@jthomp007c
Copy link

I have been working on a ticket LLAMA-17349 for a while, trying to figure out how a file descriptor used by one thread in controlMgr is being closed by another controlMgr thread.
Finally I found that the call to cat in cacheEventToFile line "fs = popen ("cat /tmp/t2_caching_file | wc -l", "r");" was closing my thread's fd.
Why this happens I can't really explain, but I have proven that replacing the popen() call with standard C to count line numbers makes the problem not happen anymore.

Reason for change: Somehow the execve calling cat in the popen()
function is closing a file descriptor used by another thread

Test Procedure: Standard NSM chamber testing

Risks: Low

Priority: P1

Signed-off-by: Jason Thomson <jason_thomson@comcast.com>
@jthomp007c jthomp007c requested a review from a team as a code owner December 17, 2025 14:40

fs = fopen(T2_CACHE_FILE, "r");
if (fs != NULL) {
while ((ch = fgetc(fs)) != EOF) {
Copy link
Contributor

@rdkcmf-jenkins rdkcmf-jenkins Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverity issue no longer present as of: undefined

Show issue

Coverity Issue - Truncated stdio return value

Assigning the return value of "fgetc" to char "ch" truncates its value.

Medium Impact, CWE-197
CHAR_IO

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a critical file descriptor management issue (LLAMA-17349) where popen() was inadvertently closing file descriptors used by other threads in controlMgr. The fix replaces the shell-based line counting (cat | wc -l) with native C file operations, and improves timestamp precision in debug logging.

Key Changes:

  • Replaced popen-based line counting with fgetc-based implementation to avoid fd interference
  • Enhanced EVENT_DEBUG logging with millisecond-precision timestamps using clock_gettime
  • Switched from localtime to thread-safe localtime_r for time conversion

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 366 to 380
fs = fopen(T2_CACHE_FILE, "r");
if (fs != NULL) {
while ((ch = fgetc(fs)) != EOF) {
if (ch == '\n') {
count++;
}
}

//If the file is not empty and does not contain a newline, call it one line
if (count == 0 && ftell(fs) > 0) {
count++;
}
fclose(fs);
fs = NULL;
}
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static global variable count (declared at line 58) is never reset before counting lines, causing it to accumulate across multiple invocations of this function. Since cacheEventToFile is called as a thread function (line 730), each new thread will continue incrementing from the previous total, eventually causing all caching to be incorrectly disabled when count exceeds MAX_EVENT_CACHE (200). The count should be reset to 0 at the start of this line counting block or made a local variable.

Copilot uses AI. Check for mistakes.
FILE *fs = NULL;
char path[100];
pthread_detach(pthread_self());
int ch;
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of pthread_detach(pthread_self()) may cause resource leaks. When threads are created via pthread_create at line 730 without the detached attribute, they need to either be joined or explicitly detached to release their resources when they terminate. Since this function is meant to run asynchronously and the calling code doesn't join the thread, the thread should either be created with PTHREAD_CREATE_DETACHED attribute or call pthread_detach(pthread_self()) as was done previously.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please retain the thread attribute to detached.

Comment on lines 368 to 375
while ((ch = fgetc(fs)) != EOF) {
if (ch == '\n') {
count++;
}
}

//If the file is not empty and does not contain a newline, call it one line
if (count == 0 && ftell(fs) > 0) {
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading through the file with fgetc until EOF, ftell may not accurately reflect whether the file had content, especially if fgetc consumed all characters. The file position after EOF doesn't reliably indicate the original file size. Consider using fseek to get the file size before reading, or check if any characters were read during the loop instead of relying on ftell after EOF.

Suggested change
while ((ch = fgetc(fs)) != EOF) {
if (ch == '\n') {
count++;
}
}
//If the file is not empty and does not contain a newline, call it one line
if (count == 0 && ftell(fs) > 0) {
long file_size = 0;
/* Determine file size before reading, then rewind to start */
if (fseek(fs, 0, SEEK_END) == 0) {
long pos = ftell(fs);
if (pos > 0) {
file_size = pos;
}
rewind(fs);
}
while ((ch = fgetc(fs)) != EOF) {
if (ch == '\n') {
count++;
}
}
/* If the file is not empty and does not contain a newline, call it one line */
if (count == 0 && file_size > 0) {

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +104
strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeinfo);
snprintf(timeBuffer + strlen(timeBuffer), sizeof(timeBuffer) - strlen(timeBuffer), ".%03ld", msecs);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The snprintf call builds on top of the existing string in timeBuffer by using strlen(timeBuffer) as the offset. While this works, it's more fragile than necessary. Consider using a single snprintf call with a combined format string, or at minimum verify the return value from strftime to ensure it succeeded before appending.

Suggested change
strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeinfo);
snprintf(timeBuffer + strlen(timeBuffer), sizeof(timeBuffer) - strlen(timeBuffer), ".%03ld", msecs);
size_t len = strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeinfo);
if (len > 0 && len < sizeof(timeBuffer)) {
int ret = snprintf(timeBuffer + len, sizeof(timeBuffer) - len, ".%03ld", msecs);
if (ret < 0) {
timeBuffer[len] = '\0';
}
} else {
timeBuffer[0] = '\0';
}

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

@shibu-kv shibu-kv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please apply the formatting as well that got flagged in L2 workflows. Astyle code formatting commands would be -

            find . -name '*.c' -o -name '*.h' | xargs astyle --options=.astylerc
            find . -name '*.orig' -type f -delete

Rest of the changes looks good.

FILE *fs = NULL;
char path[100];
pthread_detach(pthread_self());
int ch;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please retain the thread attribute to detached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants