-
Notifications
You must be signed in to change notification settings - Fork 20
RDK-60291 [telemetry] RDK Coverity Defect Resolution for Device Management #235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
15ccf65 to
b9475ed
Compare
Coverity Issue - Data race conditionA wait is performed without a loop. If there is a spurious wakeup, the condition may not be satisfied. Medium Impact, CWE-none How to fixCheck the wait condition in a loop, with the lock held. The lock must not be released between the condition and the wait. Issue locationThis issue was discovered outside the diff for this Pull Request. You can find it at: |
| // Release reuseThreadMutex before acquiring reportInProgressMutex to maintain lock order | ||
| pthread_mutex_unlock(&profile->reuseThreadMutex); | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = true; |
There was a problem hiding this comment.
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 - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
source/xconf-client/xconfclient.c
Outdated
| pthread_mutex_lock(&xcThreadMutex); | ||
| stopFetchRemoteConfiguration = true; | ||
| T2Debug("%s while Loop -- END; wait for restart event\n", __FUNCTION__); | ||
| pthread_cond_wait(&xcThreadCond, &xcThreadMutex); |
There was a problem hiding this comment.
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 - Data race condition
A wait is performed without a loop. If there is a spurious wakeup, the condition may not be satisfied.
Medium Impact, CWE-none
BAD_CHECK_OF_WAIT_COND
How to fix
Check the wait condition in a loop, with the lock held. The lock must not be released between the condition and the wait.
b9475ed to
e1a0e6a
Compare
e1a0e6a to
ddb6710
Compare
There was a problem hiding this 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 pull request addresses Coverity static analysis defects in the telemetry Device Management component, focusing on improving thread safety, error handling, and security practices.
Changes:
- Enhanced thread synchronization with proper mutex lock/unlock patterns and condition variable handling
- Added error checking for system calls (write, stat, fread, system) with appropriate error logging
- Fixed potential memory leaks in realloc usage by using temporary pointers
- Improved integer overflow protection when converting uint32_t to int
- Enhanced security by setting secure umask before mkstemp calls
- Replaced insecure rand() with /dev/urandom for better random number generation
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 28 comments.
Show a summary per file
| File | Description |
|---|---|
| source/xconf-client/xconfclient.c | Improved mutex locking patterns for thread safety, added error handling for pipe write operations |
| source/utils/t2collection.c | Fixed potential integer underflow by checking for zero count before subtraction |
| source/utils/persistence.c | Added error checking for stat and fread system calls |
| source/scheduler/scheduler.c | Enhanced thread termination logic and improved mutex handling around sleep operations |
| source/reportgen/reportgen.c | Fixed potential memory leak in realloc by using temporary pointer |
| source/protocol/rbusMethod/rbusmethodinterface.c | Added missing mutex lock for thread-safe access to shared variable |
| source/dcautil/dca.c | Implemented secure temporary file creation with restrictive umask |
| source/commonlib/telemetry_busmessage_sender.c | Added null pointer check before string operations and proper variable initialization |
| source/bulkdata/t2eventreceiver.c | Improved thread synchronization and condition variable handling |
| source/bulkdata/reportprofiles.c | Added integer overflow protection when converting hashmap count to signed int |
| source/bulkdata/profile.c | Fixed lock ordering to prevent deadlocks and replaced rand() with /dev/urandom |
| source/bulkdata/datamodel.c | Enhanced thread safety with improved condition variable and mutex handling |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
source/xconf-client/xconfclient.c
Outdated
| do { | ||
| n = pthread_cond_timedwait(&xcCond, &xcMutex, &_ts); | ||
| } while(n != ETIMEDOUT && n != 0); |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The do-while loop here will continue retrying even after pthread_cond_timedwait succeeds (returns 0). This breaks the intended behavior where the thread should wake up when signaled via pthread_cond_signal. The loop should only retry on spurious wakeups (when the return value is neither ETIMEDOUT nor 0), not when the call succeeds. Consider using while(n != ETIMEDOUT && n != 0 && n == EINTR) if you only want to handle spurious wakeups, or remove this do-while wrapper if spurious wakeup handling isn't necessary.
| hashmap_count = hash_map_count(profileHashMap); | ||
| if (hashmap_count == 0 || hashmap_count == UINT32_MAX) | ||
| { | ||
| count = -1; | ||
| } | ||
| else | ||
| { | ||
| count = (int)(hashmap_count - 1); | ||
| } |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for hashmap_count == UINT32_MAX is checking for an edge case that is unlikely to occur in practice and may not be the correct way to detect an error from hash_map_count. If hash_map_count returns UINT32_MAX to indicate an error (which would be unusual), this should be documented or verified. More importantly, when hashmap_count == 0, setting count = -1 is correct for the while loop condition while(count >= 0) to immediately exit, but the check should ensure this is the intended behavior. Consider adding a comment explaining why UINT32_MAX is checked.
source/scheduler/scheduler.c
Outdated
| break; | ||
| } | ||
|
|
||
| if( clock_gettime(CLOCK_MONOTONIC, &_now) == -1 ) |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is inconsistent indentation here. The line uses a tab character instead of spaces. This should be indented with spaces to match the project's coding style.
| if( clock_gettime(CLOCK_MONOTONIC, &_now) == -1 ) | |
| if( clock_gettime(CLOCK_MONOTONIC, &_now) == -1 ) |
source/scheduler/scheduler.c
Outdated
|
|
||
| // Unlock scMutex before sleeping to avoid holding lock during sleep | ||
| if(pthread_mutex_unlock(&scMutex) != 0) | ||
| { | ||
| T2Error("scMutex unlock failed\n"); | ||
| return T2ERROR_FAILURE; | ||
| } | ||
|
|
||
| int count = 0; |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is inconsistent indentation here. Lines 666-674 use tab characters instead of spaces. This should be indented with spaces to match the project's coding style.
| // Unlock scMutex before sleeping to avoid holding lock during sleep | |
| if(pthread_mutex_unlock(&scMutex) != 0) | |
| { | |
| T2Error("scMutex unlock failed\n"); | |
| return T2ERROR_FAILURE; | |
| } | |
| int count = 0; | |
| // Unlock scMutex before sleeping to avoid holding lock during sleep | |
| if(pthread_mutex_unlock(&scMutex) != 0) | |
| { | |
| T2Error("scMutex unlock failed\n"); | |
| return T2ERROR_FAILURE; | |
| } | |
| int count = 0; |
| ret = report_or_cache_data(strvalue, marker); | ||
| if(strvalue != NULL) | ||
| { | ||
| { |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are trailing whitespace characters at the end of this line. Trailing whitespace should be removed to maintain code cleanliness.
| { | |
| { |
source/scheduler/scheduler.c
Outdated
| do { | ||
| n = pthread_cond_timedwait(&tProfile->tCond, &tProfile->tMutex, &_ts); | ||
| } while(n != ETIMEDOUT && n != 0); |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The do-while loop here will continue retrying even after pthread_cond_timedwait succeeds (returns 0). This breaks the intended behavior where the thread should wake up when signaled via pthread_cond_signal. The loop should only retry on spurious wakeups (when the return value is neither ETIMEDOUT nor 0), not when the call succeeds. Consider using while(n != ETIMEDOUT && n != 0 && n == EINTR) if you only want to handle spurious wakeups, or remove this do-while wrapper if spurious wakeup handling isn't necessary.
source/bulkdata/profile.c
Outdated
| n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &profile->maxlatencyTime); | ||
| do { | ||
| n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &profile->maxlatencyTime); | ||
| } while(n != ETIMEDOUT && n != 0); |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The do-while loop here will continue retrying even after pthread_cond_timedwait succeeds (returns 0). This breaks the intended behavior where the thread should wake up when signaled via pthread_cond_signal. The loop should only retry on spurious wakeups (when the return value is neither ETIMEDOUT nor 0), not when the call succeeds. Consider using while(n != ETIMEDOUT && n != 0 && n == EINTR) if you only want to handle spurious wakeups, or remove this do-while wrapper if spurious wakeup handling isn't necessary.
| } while(n != ETIMEDOUT && n != 0); | |
| } while (n == EINTR); |
source/xconf-client/xconfclient.c
Outdated
| stopFetchRemoteConfiguration = false; | ||
| pthread_cond_signal(&xcThreadCond); | ||
| pthread_mutex_unlock(&xcThreadMutex); | ||
| //pthread_create(&xcrThread, NULL, getUpdatedConfigurationThread, NULL); |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is inconsistent indentation here. The line uses a tab character instead of spaces. This should be indented with spaces to match the project's coding style.
| //pthread_create(&xcrThread, NULL, getUpdatedConfigurationThread, NULL); | |
| //pthread_create(&xcrThread, NULL, getUpdatedConfigurationThread, NULL); |
source/bulkdata/t2eventreceiver.c
Outdated
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) | ||
| { | ||
| shouldSignal = !stopDispatchThread; | ||
| pthread_mutex_unlock(&sTDMutex); | ||
| } | ||
| if(shouldSignal) |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is inconsistent indentation here. Lines 208-214 use tab characters instead of spaces. This should be indented with spaces to match the project's coding style.
| bool shouldSignal = false; | |
| if(pthread_mutex_lock(&sTDMutex) == 0) | |
| { | |
| shouldSignal = !stopDispatchThread; | |
| pthread_mutex_unlock(&sTDMutex); | |
| } | |
| if(shouldSignal) | |
| bool shouldSignal = false; | |
| if(pthread_mutex_lock(&sTDMutex) == 0) | |
| { | |
| shouldSignal = !stopDispatchThread; | |
| pthread_mutex_unlock(&sTDMutex); | |
| } | |
| if(shouldSignal) |
source/bulkdata/profile.c
Outdated
| FILE *urandom = fopen("/dev/urandom", "r"); | ||
| if(urandom != NULL && fread(&random_value, sizeof(random_value), 1, urandom) == 1) | ||
| { | ||
| maxuploadinmilliSec = random_value % (profile->maxUploadLatency - 1); | ||
| fclose(urandom); | ||
| } | ||
| else | ||
| { | ||
| if(urandom != NULL) fclose(urandom); | ||
| maxuploadinmilliSec = (unsigned int)(time(0) % (profile->maxUploadLatency - 1)); |
Copilot
AI
Jan 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is inconsistent indentation here. Lines 556, 557, 559, 560, 564, and 565 use tab characters instead of spaces. This should be indented with spaces to match the project's coding style.
| while(!stopProcessing) | ||
| while(!shouldContinue) | ||
| { | ||
| pthread_mutex_lock(&tmpRpMutex); |
There was a problem hiding this comment.
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 - Logically dead code
Execution cannot reach this statement: "pthread_mutex_lock(&tmpRpMu...".
Medium Impact, CWE-561
DEADCODE
| T2Error("Unable to allocate %d bytes of memory for URL at Line %d on %s \n", modified_url_len, __LINE__, __FILE__); | ||
| free(httpUrl); | ||
| free(url_params); | ||
| return NULL; |
There was a problem hiding this comment.
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 - Resource leak
Variable "curl" going out of scope leaks the storage it points to.
High Impact, CWE-404
RESOURCE_LEAK
source/bulkdata/t2eventreceiver.c
Outdated
| if(!stopDispatchThread) | ||
|
|
||
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Thread deadlock
Calling "pthread_mutex_lock" acquires lock "sTDMutex" while holding lock "erMutex" (count: 1 / 2).
Medium Impact, CWE-833
ORDER_REVERSAL
ddb6710 to
0ca5ee5
Compare
Coverity Issue - Waiting while holding a lockCall to "sendCachedReportsOverRBUSMethod" might sleep while holding lock "profile->reuseThreadMutex". Medium Impact, CWE-667 Issue locationThis issue was discovered outside the diff for this Pull Request. You can find it at: |
source/bulkdata/t2eventreceiver.c
Outdated
| if(!stopDispatchThread) | ||
|
|
||
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Thread deadlock
Calling "pthread_mutex_lock" acquires lock "sTDMutex" while holding lock "erMutex" (count: 1 / 2).
Medium Impact, CWE-833
ORDER_REVERSAL
0ca5ee5 to
421dbea
Compare
source/bulkdata/t2eventreceiver.c
Outdated
| if(!stopDispatchThread) | ||
|
|
||
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Thread deadlock
Calling "pthread_mutex_lock" acquires lock "sTDMutex" while holding lock "erMutex" (count: 1 / 2).
Medium Impact, CWE-833
ORDER_REVERSAL
421dbea to
b7306d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
source/bulkdata/profile.c
Outdated
| T2Info("TIMEOUT for maxUploadLatency of profile %s\n", profile->name); | ||
| ret = sendReportsOverRBUSMethod(profile->t2RBUSDest->rbusMethodName, profile->t2RBUSDest->rbusMethodParamList, jsonReport); | ||
| } | ||
| else if(n == 0) |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of tabs for indentation. The code appears to use spaces for indentation elsewhere. This should be consistent with the rest of the codebase.
| else if(n == 0) | |
| else if(n == 0) |
| while(t2_queue_count(tmpRpQueue) == 0 && shouldContinue) | ||
| { | ||
| pthread_cond_wait(&tmpRpCond, &tmpRpMutex); | ||
| } |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to process_rp_thread, the condition variable wait loop checks shouldContinue but doesn't re-evaluate it after pthread_cond_wait returns. If stopProcessing is set while waiting, the thread will continue processing instead of exiting. The shouldContinue variable should be re-checked after pthread_cond_wait returns.
source/xconf-client/xconfclient.c
Outdated
| { | ||
| n = pthread_cond_timedwait(&xcCond, &xcMutex, &_ts); | ||
| } | ||
| while(n == EINTR); |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of tabs and spaces for indentation. The code appears to use spaces for indentation elsewhere, but tabs are used here. This should be consistent with the rest of the codebase.
| { | |
| n = pthread_cond_timedwait(&xcCond, &xcMutex, &_ts); | |
| } | |
| while(n == EINTR); | |
| { | |
| n = pthread_cond_timedwait(&xcCond, &xcMutex, &_ts); | |
| } | |
| while(n == EINTR); |
source/reportgen/reportgen.c
Outdated
| if(temp_url == NULL) | ||
| { | ||
| T2Error("Unable to allocate %d bytes of memory for URL at Line %d on %s \n", modified_url_len, __LINE__, __FILE__); | ||
| free(httpUrl); | ||
| free(url_params); | ||
| return NULL; | ||
| } | ||
| httpUrl = temp_url; |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of tabs for indentation. The code appears to use spaces for indentation elsewhere. This should be consistent with the rest of the codebase.
source/bulkdata/t2eventreceiver.c
Outdated
| T2Error("%s pthread_mutex_lock for sTDMutex failed\n", __FUNCTION__); | ||
| return; | ||
| } | ||
| if(!stopDispatchThread) | ||
| { | ||
| if(pthread_mutex_lock(&sTDMutex) != 0) // mutex lock failed so return from T2ER_Uninit | ||
| { | ||
| T2Error("%s pthread_mutex_lock for sTDMutex failed\n", __FUNCTION__); | ||
| return; | ||
| } | ||
| stopDispatchThread = true; | ||
| threadToJoin = erThread; // Save thread handle while holding lock |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of tabs for indentation. The code appears to use spaces for indentation elsewhere. This should be consistent with the rest of the codebase.
source/scheduler/scheduler.c
Outdated
|
|
||
| // Unlock scMutex before sleeping to avoid holding lock during sleep | ||
| if(pthread_mutex_unlock(&scMutex) != 0) | ||
| { | ||
| T2Error("scMutex unlock failed\n"); | ||
| return T2ERROR_FAILURE; |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of tabs for indentation. The code appears to use spaces for indentation elsewhere. This should be consistent with the rest of the codebase.
source/bulkdata/profile.c
Outdated
| FILE *urandom = fopen("/dev/urandom", "r"); | ||
| if(urandom != NULL && fread(&random_value, sizeof(random_value), 1, urandom) == 1) | ||
| { | ||
| maxuploadinmilliSec = random_value % (profile->maxUploadLatency - 1); | ||
| fclose(urandom); | ||
| } | ||
| else | ||
| { | ||
| if(urandom != NULL) fclose(urandom); | ||
| maxuploadinmilliSec = (unsigned int)(time(0) % (profile->maxUploadLatency - 1)); | ||
| } |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential division by zero error if profile->maxUploadLatency is 1. The expression (profile->maxUploadLatency - 1) would be 0, causing a modulo by zero which results in undefined behavior. Similar issue exists at line 565. Add a check to ensure maxUploadLatency is greater than 1 before performing the modulo operation.
| FILE *urandom = fopen("/dev/urandom", "r"); | |
| if(urandom != NULL && fread(&random_value, sizeof(random_value), 1, urandom) == 1) | |
| { | |
| maxuploadinmilliSec = random_value % (profile->maxUploadLatency - 1); | |
| fclose(urandom); | |
| } | |
| else | |
| { | |
| if(urandom != NULL) fclose(urandom); | |
| maxuploadinmilliSec = (unsigned int)(time(0) % (profile->maxUploadLatency - 1)); | |
| } | |
| if (profile->maxUploadLatency > 1) | |
| { | |
| FILE *urandom = fopen("/dev/urandom", "r"); | |
| if(urandom != NULL && fread(&random_value, sizeof(random_value), 1, urandom) == 1) | |
| { | |
| maxuploadinmilliSec = random_value % (profile->maxUploadLatency - 1); | |
| fclose(urandom); | |
| } | |
| else | |
| { | |
| if(urandom != NULL) fclose(urandom); | |
| maxuploadinmilliSec = (unsigned int)(time(0) % (profile->maxUploadLatency - 1)); | |
| } | |
| } | |
| else | |
| { | |
| /* For maxUploadLatency == 1, avoid modulo by zero and use no additional delay */ | |
| maxuploadinmilliSec = 0; | |
| } |
| while(t2_queue_count(eQueue) == 0 && shouldContinue) | ||
| { | ||
| T2Debug("Event Queue size is 0, Waiting events from T2ER_Push\n"); | ||
| int ret = pthread_cond_wait(&erCond, &erMutex); | ||
| if(ret != 0) // pthread cond wait failed return after unlock | ||
| { | ||
| T2Error("%s pthread_cond_wait failed with error code: %d\n", __FUNCTION__, ret); | ||
| } | ||
| T2Debug("Received signal from T2ER_Push\n"); | ||
| } |
Copilot
AI
Jan 14, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition variable wait loop checks shouldContinue but doesn't re-evaluate it after pthread_cond_wait returns. If stopDispatchThread is set while waiting on the condition, the thread will continue processing the event instead of exiting. The shouldContinue variable should be re-checked after pthread_cond_wait returns at line 257.
source/bulkdata/t2eventreceiver.c
Outdated
| if(!stopDispatchThread) | ||
|
|
||
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Thread deadlock
Calling "pthread_mutex_lock" acquires lock "sTDMutex" while holding lock "erMutex" (count: 1 / 2).
Medium Impact, CWE-833
ORDER_REVERSAL
b7306d4 to
958bb14
Compare
source/bulkdata/t2eventreceiver.c
Outdated
| if(!stopDispatchThread) | ||
|
|
||
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Thread deadlock
Calling "pthread_mutex_lock" acquires lock "sTDMutex" while holding lock "erMutex" (count: 1 / 2).
Medium Impact, CWE-833
ORDER_REVERSAL
28c66a1 to
ac77f39
Compare
source/bulkdata/t2eventreceiver.c
Outdated
| if(!stopDispatchThread) | ||
|
|
||
| bool shouldSignal = false; | ||
| if(pthread_mutex_lock(&sTDMutex) == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Thread deadlock
Calling "pthread_mutex_lock" acquires lock "sTDMutex" while holding lock "erMutex" (count: 1 / 2).
Medium Impact, CWE-833
ORDER_REVERSAL
| T2Debug(" profile->triggerReportOnCondition is not set \n"); | ||
| } | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
| T2Debug(" profile->triggerReportOnCondition is not set \n"); | ||
| } | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
4a7c56c to
faaa414
Compare
| pthread_mutex_unlock(&profile->reuseThreadMutex); | ||
| T2Info("%s --out Exiting collect and report Thread\n", __FUNCTION__); | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
faaa414 to
2698b7b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| while (profile->enable && n != ETIMEDOUT) | ||
| { | ||
| n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); | ||
| } |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue in the RBUS_METHOD maxUploadLatency path: the while(profile->enable && n != ETIMEDOUT) loop won't break on n==0, so a signal won't cause an early exit as the subsequent logging suggests. Use a single timedwait (retry only on EINTR) or introduce a predicate and break appropriately.
| while (profile->enable && n != ETIMEDOUT) | |
| { | |
| n = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); | |
| } | |
| int waitResult; | |
| do | |
| { | |
| waitResult = pthread_cond_timedwait(&profile->reportcond, &profile->reportMutex, &timeout); | |
| } while (waitResult == EINTR); | |
| n = waitResult; |
| if (write(sharedPipeFdStatus[1], &ret, sizeof(T2ERROR)) != sizeof(T2ERROR)) | ||
| { | ||
| T2Error("Failed to write status to pipe\n"); | ||
| } |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The status pipe write() result is checked, but a short/failed write is only logged and the child still exits normally. This can cause the parent to read an uninitialized/partial T2ERROR value. Consider treating a short/failed write as fatal (set a fallback failure code and exit), and have the parent verify it read exactly sizeof(T2ERROR).
| if (filestat.st_size < 0 || (size_t)filestat.st_size >= sizeof(data)) | ||
| { | ||
| T2Error("File size %ld exceeds buffer capacity %zu for file : %s\n", filestat.st_size, sizeof(data) - 1, filePath); | ||
| fclose(fp); |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filestat.st_size is off_t, but the new error message prints it with %ld. On some platforms off_t is not long (e.g., long long), which can cause incorrect logs/UB. Use a portable format (e.g., cast to intmax_t and print with %jd) or cast to long long and use %lld consistently.
| T2Debug(" profile->triggerReportOnCondition is not set \n"); | ||
| } | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
| T2Debug(" profile->triggerReportOnCondition is not set \n"); | ||
| } | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
7fa136e to
a4705e4
Compare
| { | ||
| T2Error("Failed to initialize JSON Report\n"); | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
| { | ||
| T2Error("Failed to initialize JSON Report\n"); | ||
| pthread_mutex_lock(&profile->reportInProgressMutex); | ||
| profile->reportInProgress = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverity Issue - Data race condition
Accessing "profile->reportInProgress" without holding lock "_Profile.reuseThreadMutex". Elsewhere, "_Profile.reportInProgress" is written to with "_Profile.reuseThreadMutex" held 11 out of 11 times.
Medium Impact, CWE-366
MISSING_LOCK
b4ab956 to
0468ad0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
source/bulkdata/profile.c:645
- In this error path, reportcond is destroyed but reportMutex (initialized earlier when maxUploadLatency > 0) is not destroyed before jumping to reportThreadEnd. This can leak resources and make subsequent pthread_mutex_init on reportMutex undefined. Ensure reportMutex is destroyed on this error path as well.
T2Error("Profile : %s pthread_cond_timedwait ERROR!!!\n", profile->name);
pthread_mutex_unlock(&profile->reportMutex);
pthread_cond_destroy(&profile->reportcond);
if(httpUrl)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| T2Error("Profile : %s pthread_cond_timedwait ERROR!!!\n", profile->name); | ||
| pthread_mutex_unlock(&profile->reportMutex); | ||
| pthread_cond_destroy(&profile->reportcond); | ||
| pthread_mutex_lock(&profile->reuseThreadMutex); |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this RBUS_METHOD timedwait error path, reportcond is destroyed but reportMutex (initialized earlier when maxUploadLatency > 0) is not destroyed before jumping to reportThreadEnd. This can leak resources and make subsequent pthread_mutex_init on reportMutex undefined. Ensure reportMutex is destroyed on this error path (and consistently on all paths that destroy reportcond).
| if (write(sharedPipeFdStatus[1], &ret, sizeof(T2ERROR)) != sizeof(T2ERROR)) | ||
| { | ||
| T2Error("Failed to write status to pipe\n"); |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If writing the status to the pipe fails (short write or -1), the parent may read an uninitialized/partial status and take the wrong code path. Consider making pipe write failure fatal (e.g., log, set an error status, and exit) rather than continuing with an unreliable IPC result.
| if (write(sharedPipeFdStatus[1], &ret, sizeof(T2ERROR)) != sizeof(T2ERROR)) | |
| { | |
| T2Error("Failed to write status to pipe\n"); | |
| { | |
| size_t totalWritten = 0; | |
| unsigned char *buf = (unsigned char *)&ret; | |
| while (totalWritten < sizeof(T2ERROR)) | |
| { | |
| ssize_t bytes = write(sharedPipeFdStatus[1], buf + totalWritten, sizeof(T2ERROR) - totalWritten); | |
| if (bytes < 0) | |
| { | |
| T2Error("Failed to write status to pipe: write error\n"); | |
| close(sharedPipeFdStatus[1]); | |
| exit(EXIT_FAILURE); | |
| } | |
| if (bytes == 0) | |
| { | |
| T2Error("Failed to write status to pipe: wrote 0 bytes\n"); | |
| close(sharedPipeFdStatus[1]); | |
| exit(EXIT_FAILURE); | |
| } | |
| totalWritten += (size_t)bytes; | |
| } |
| do | ||
| { | ||
| n = pthread_cond_timedwait(&xcCond, &xcMutex, &_ts); | ||
| } | ||
| while(n == EINTR); |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same pattern here: xcThreadMutex is held while doing pthread_cond_timedwait on xcCond with xcMutex. This can prevent stop/uninit from acquiring xcThreadMutex to signal the condition, causing long delays/hangs. Consider not holding xcThreadMutex across the timed wait (use a single mutex for the stop flag + condition, or unlock/relock around the wait).
ffa76d4 to
d13151d
Compare
6543d9c to
4d518e1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
source/bulkdata/profile.c:1293
- deleteAllProfiles() writes tempProfile->threadExists = false without holding reuseThreadMutex (or any other lock consistently protecting threadExists). Since CollectAndReport() updates/destroys reuseThreadMutex based on threadExists, this unsynchronized write can race with the worker thread and lead to signaling/joining the wrong state. Update threadExists under reuseThreadMutex (or make it atomic) consistently.
if (tempProfile->threadExists)
{
pthread_mutex_lock(&tempProfile->reuseThreadMutex);
tempProfile->restartRequested = true;
pthread_cond_signal(&tempProfile->reuseThread);
pthread_mutex_unlock(&tempProfile->reuseThreadMutex);
pthread_join(tempProfile->reportThread, NULL);
tempProfile->threadExists = false;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pthread_mutex_init(&profile->reportMutex, NULL); | ||
| pthread_cond_init(&profile->reportcond, NULL); | ||
| unsigned int random_value = 0; |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CollectAndReport() initializes profile->reportMutex/profile->reportcond when maxUploadLatency > 0, but teardown is not symmetric across all branches (e.g., the HTTP path destroys both, while the RBUS_METHOD maxUploadLatency path later only destroys the cond var). This can leak pthread resources across repeated reports. Ensure reportMutex is destroyed on every path that initializes it (success, error, and both protocol branches).
| params_len += snprintf(url_params + params_len, new_params_len - params_len, "%s=%s&", httpParam->HttpName, httpParamVal); | ||
|
|
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prepareHttpUrl() calls snprintf with httpParamVal using a "%s" format, but httpParamVal can be NULL if curl_easy_escape fails (OOM) or returns NULL. Passing NULL to "%s" is undefined behavior and can crash. Add an explicit check for httpParamVal == NULL and skip/abort building that parameter before calling snprintf.
36e7ae5 to
d651aee
Compare
dd817ae to
72d176a
Compare
15adbac to
4774200
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| T2Error("Failed to create /tmp/.t2ReadyToReceiveEvents flag file \n"); | ||
| } | ||
| setT2EventReceiveState(T2_STATE_COMPONENT_READY); | ||
| T2Info("T2 is now Ready to Recieve Events\n"); |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in log message: "Recieve" -> "Receive".
| T2Info("T2 is now Ready to Recieve Events\n"); | |
| T2Info("T2 is now Ready to Receive Events\n"); |
| pthread_mutex_lock(&tmpRpMutex); | ||
| pthread_mutex_lock(&rpMutex); | ||
| shouldContinue = !stopProcessing; | ||
| pthread_mutex_unlock(&rpMutex); | ||
| if(!shouldContinue) |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tmpRpQueue operations are protected by tmpRpMutex in this thread, but producers push to tmpRpQueue under rpMutex (see datamodel_processProfile using pthread_mutex_lock(&rpMutex) before t2_queue_push(tmpRpQueue, ...)). This means tmpRpQueue is accessed under different mutexes, which is a data race and can corrupt the queue. Use a single mutex consistently for tmpRpQueue (and pair tmpRpCond with that same mutex), or remove the extra mutex.
| T2Info("%s: Waiting for event from tr-181 \n", __FUNCTION__); | ||
| pthread_cond_wait(&tmpRpCond, &tmpRpMutex); | ||
| while(t2_queue_count(tmpRpQueue) == 0 && shouldContinue) | ||
| { | ||
| pthread_cond_wait(&tmpRpCond, &tmpRpMutex); | ||
| pthread_mutex_lock(&rpMutex); |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This thread waits on tmpRpCond, but datamodel_unInit() never signals tmpRpCond when setting stopProcessing = true. If tmpRpQueue is empty, pthread_join(tmpRpThread, ...) can hang indefinitely. Ensure datamodel_unInit() signals/broadcasts tmpRpCond during shutdown so this wait can be released and the thread can exit.
No description provided.