Skip to content

Feature/rdkemw 8587 dlsym - #186

Open
suppal045 wants to merge 75 commits into
testfrom
feature/RDKEMW-8587-dlsym
Open

Feature/rdkemw 8587 dlsym#186
suppal045 wants to merge 75 commits into
testfrom
feature/RDKEMW-8587-dlsym

Conversation

@suppal045

Copy link
Copy Markdown

No description provided.

* RDKEMW-4848: pass the proper handle to dsEnableHDCP
@suppal045
suppal045 requested a review from a team as a code owner December 11, 2025 16:17
Copilot AI review requested due to automatic review settings December 11, 2025 16:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 refactors the dynamic library loading mechanism for device settings configuration to use a shared library handle instead of opening/closing the library multiple times. The changes introduce a centralized getDLInstance() and releaseDLInstance() pattern, and update all config loading methods to accept a handle parameter.

Key Changes

  • Centralized dynamic library handle management with thread-safe singleton pattern
  • Updated all config load methods to accept a void* pDLHandle parameter
  • Added support for FrontPanelConfig in the initialization flow
  • Removed the parse_opt_flag() function and associated delay logic

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
ds/manager.cpp Added getDLInstance/releaseDLInstance functions, refactored searchConfigs to use provided handle, updated Initialize/load methods to pass handle to configs, removed parse_opt_flag function and delay logic
ds/include/manager.hpp Updated searchConfigs declaration to include pDLHandle parameter, removed parse_opt_flag declaration
ds/videoOutputPortConfig.hpp Updated load method signature to accept pDLHandle parameter
ds/videoOutputPortConfig.cpp Refactored load to accept handle parameter, moved symbol search variables into conditional block, added dynamic vs old config loading logic
ds/videoDeviceConfig.hpp Updated load method signature to accept pDLHandle parameter
ds/videoDeviceConfig.cpp Refactored load to accept handle parameter, added dynamic vs old config loading logic
ds/audioOutputPortConfig.hpp Updated load method signature to accept pDLHandle parameter
ds/audioOutputPortConfig.cpp Refactored load to accept handle parameter, added dynamic vs old config loading logic
ds/include/frontPanelConfig.hpp Moved load method from private to public, added m_isFPConfigLoaded member, updated load signature to accept pDLHandle
ds/frontPanelConfig.cpp Removed load call from getInstance, added load validation checks with m_isFPConfigLoaded, refactored load to accept handle parameter and support dynamic/old config loading

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

Comment thread ds/frontPanelConfig.cpp Outdated
Comment thread ds/frontPanelConfig.cpp
}
m_isFPConfigLoaded = true;
INT_INFO("Exit function\n");
return;

Copilot AI Dec 11, 2025

Copy link

Choose a reason for hiding this comment

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

The explicit return statement at the end of a void function is unnecessary. Since this function returns void, the return statement at line 554 can be removed as the function will automatically return at its end.

Suggested change
return;

Copilot uses AI. Check for mistakes.
Comment thread ds/videoDeviceConfig.cpp Outdated
Comment thread ds/manager.cpp Outdated
Comment thread ds/manager.cpp Outdated
Copilot AI review requested due to automatic review settings December 12, 2025 22:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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.

Copilot AI review requested due to automatic review settings December 16, 2025 16:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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.

Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Reason for change: consume the config variables using dlsym() in MW.
Test Procedure: refer RDKEMW-8587
Risks: High
Signed-off-by:gsanto722 <grandhi_santoshkumar@comcast.com>
Copilot AI review requested due to automatic review settings February 23, 2026 16:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 31 out of 31 changed files in this pull request and generated 22 comments.


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

Comment thread rpc/srv/dsConfigs.c

INT_INFO("Entering capabilityType = 0x%08X\n", capabilityType);
dlerror(); /* clear old error */
pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY);

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

Missing error handling: The function doesn't check for dlopen failures. If pDLHandle is NULL (dlopen failed), the code will pass NULL to LoadDLSymbols, which will fail silently and fall back to static configurations. Consider logging dlerror() message when dlopen fails to help diagnose library loading issues.

Suggested change
pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY);
pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY);
if (NULL == pDLHandle) {
const char* dlErrMsg = dlerror();
if (dlErrMsg != NULL) {
INT_ERROR("Failed to load '%s': %s\n", RDK_DSHAL_NAME, dlErrMsg);
} else {
INT_ERROR("Failed to load '%s': unknown dlopen error\n", RDK_DSHAL_NAME);
}
}

Copilot uses AI. Check for mistakes.
Comment thread ds/videoDeviceConfig.cpp Outdated
: dsVIDEOPORT_TYPE_INTERNAL;
ret = dsGetVideoPort(portType, 0, &handle);
if ((ret == dsERR_NONE) && (handle != -1)) {
ret = dsEnableHDCP(handle, contentProtect, hdcpKey, keySize);

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

Changed API signature: The dsEnableHDCP function call changed from passing a port type (dsVideoPortType_t) to passing a handle (intptr_t). This is a breaking API change that needs to be verified against the HAL library implementation. Ensure that the HAL library's dsEnableHDCP function signature matches this new usage.

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsDisplay.c Outdated
Comment thread rpc/srv/dsVideoPort.c
componentPortPresent = true;;
if (typeConfigs[i].typeId == dsVIDEOPORT_TYPE_COMPONENT)
{
componentPortPresent = true;

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

Unnecessary double semicolon at the end of the statement. Remove one semicolon.

Copilot uses AI. Check for mistakes.
Comment thread ds/videoOutputPortConfig.cpp Outdated
Comment thread rpc/srv/dsVideoPortConfig.c Outdated
Comment thread rpc/srv/dsVideoDeviceConfig.c Outdated
Comment thread rpc/srv/dsAudioConfig.c
int kPortSize;
}audioConfigsLocal_t;

static audioConfigsLocal_t audioConfiguration = {0};

Copilot AI Feb 23, 2026

Copy link

Choose a reason for hiding this comment

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

Potential race condition: The global static variable audioConfiguration is accessed and modified without any mutex protection. Multiple threads could potentially call dsLoadAudioOutputPortConfig or the getter functions concurrently, leading to data races. Consider adding mutex protection around accesses to this shared state.

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsVideoPortConfig.c Outdated
Copilot AI review requested due to automatic review settings February 24, 2026 12:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 41 out of 41 changed files in this pull request and generated 11 comments.

Comments suppressed due to low confidence (1)

rpc/srv/dsVideoPort.c:1968

  • Potential NULL pointer dereference. If kVidoeResolutionsSettings is NULL (which can happen if dsGetVideoPortResolutions fails), the code will attempt to dereference it at line 1959 and in the loop at line 1963. Add a NULL check after line 1946.

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

Comment thread rpc/srv/dsVideoPort.c Outdated
Comment thread rpc/srv/dsVideoPort.c
Comment on lines +1913 to +1922
{
int numResolutions = 0;
dsVideoPortResolution_t* resolutions = NULL;
int defaultIndex = 0;
dsGetVideoPortResolutions(&numResolutions, &resolutions);
dsGetDefaultResolutionIndex(&defaultIndex);
if (resolutions && defaultIndex >= 0 && defaultIndex < numResolutions) {
return resolution.assign(resolutions[defaultIndex].name);
}
}

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

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

Potential NULL pointer dereference. If resolutions is NULL or defaultIndex is out of bounds, the code will attempt to access resolutions[defaultIndex].name which could crash. Add proper NULL and bounds checking before accessing the array.

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsVideoPort.c Outdated
Comment thread rpc/srv/dsDisplay.c Outdated
Comment thread rpc/srv/dsDisplay.c Outdated
Comment thread rpc/srv/dsDisplay.c Outdated
Comment thread rpc/srv/dsAudio.c Outdated
Comment thread ds/videoDevice.cpp
* @return None.
*/
VideoDevice::VideoDevice(int id)
VideoDevice::VideoDevice(int id): _dfc(0)

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

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

Inconsistent member initialization order. The member _dfc is initialized in the initializer list, but _handle is assigned in the constructor body. For consistency and to avoid potential issues with initialization order, consider initializing all members in the initializer list or all in the constructor body. Note that the original code didn't initialize _dfc at all, so this change is adding initialization.

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsVideoPort.c Outdated
Comment thread rpc/srv/dsVideoPortConfig.c Outdated
Copilot AI review requested due to automatic review settings February 26, 2026 15:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 41 out of 41 changed files in this pull request and generated 12 comments.


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

Comment thread rpc/srv/dsAudioConfig.c
Comment on lines +108 to +116
audioConfiguration.pKAudioConfigs = (dsAudioTypeConfig_t*)malloc(numElements * sizeof(dsAudioTypeConfig_t));
if (audioConfiguration.pKAudioConfigs == NULL) {
INT_ERROR("Failed to allocate memory for %s audio configs\n", configType);
return -1;
}

memcpy(audioConfiguration.pKAudioConfigs, source, numElements * sizeof(dsAudioTypeConfig_t));
INT_INFO("Allocated and copied %d audio configs (%s)", numElements, configType);
return numElements;

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

allocateAndCopyAudioConfigs() does a raw memcpy() of dsAudioTypeConfig_t. Those structs contain pointer fields (e.g., name, encodings, compressions, stereoModes in the existing configs), and dsLoadConfigs() closes the HAL dlopen() handle after loading. That makes these pointers dangle (use-after-dlclose) when the configs are later consumed. Deep-copy all pointer members (and any pointed-to arrays) into DSMgr-owned memory, or keep the HAL library loaded for the lifetime of the copied configs.

Copilot uses AI. Check for mistakes.
Comment on lines +315 to +323
if (videoPortConfiguration.pKVideoPortResolutionsSettings != NULL) {
for (int i = 0; i < videoPortConfiguration.kResolutionsSettings_size; ++i) {
if (videoPortConfiguration.pKVideoPortResolutionsSettings[i].name != NULL) {
free(videoPortConfiguration.pKVideoPortResolutionsSettings[i].name);
}
}
free(videoPortConfiguration.pKVideoPortResolutionsSettings);
videoPortConfiguration.pKVideoPortResolutionsSettings = NULL;
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

The error cleanup path attempts to free(videoPortConfiguration.pKVideoPortResolutionsSettings[i].name), but this file explicitly documents that dsVideoPortResolution_t::name is a fixed array (see the comment in allocateAndCopyVideoPortResolutions()), not heap memory. This would be an invalid free if the loop ever runs. Remove the per-element free and only free(pKVideoPortResolutionsSettings) (and make sure kResolutionsSettings_size is set before using it for cleanup).

Copilot uses AI. Check for mistakes.
Comment on lines +350 to +358
if (videoPortConfiguration.pKVideoPortResolutionsSettings != NULL) {
for (int i = 0; i < resolutionSize; ++i) {
if (videoPortConfiguration.pKVideoPortResolutionsSettings[i].name != NULL) {
free(videoPortConfiguration.pKVideoPortResolutionsSettings[i].name);
}
}
free(videoPortConfiguration.pKVideoPortResolutionsSettings);
videoPortConfiguration.pKVideoPortResolutionsSettings = NULL;
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

This second cleanup block also calls free(videoPortConfiguration.pKVideoPortResolutionsSettings[i].name), but dsVideoPortResolution_t::name is treated as a fixed array elsewhere in this file. This would be an invalid free. Only free the containing pKVideoPortResolutionsSettings allocation (and do not attempt to free name).

Copilot uses AI. Check for mistakes.
Comment on lines +457 to +479
void dsVideoPortConfigFree(void)
{
INT_INFO("Freeing VideoPort configuration resources\n");
// Free video port configs
if (videoPortConfiguration.pKVideoPortConfigs != NULL) {
free(videoPortConfiguration.pKVideoPortConfigs);
videoPortConfiguration.pKVideoPortConfigs = NULL;
INT_INFO("Freed pKVideoPortConfigs\n");
}

// Free video port ports
if (videoPortConfiguration.pKVideoPortPorts != NULL) {
free(videoPortConfiguration.pKVideoPortPorts);
videoPortConfiguration.pKVideoPortPorts = NULL;
INT_INFO("Freed pKVideoPortPorts\n");
}

// Free video port resolutions
if (videoPortConfiguration.pKVideoPortResolutionsSettings != NULL) {
free(videoPortConfiguration.pKVideoPortResolutionsSettings);
videoPortConfiguration.pKVideoPortResolutionsSettings = NULL;
INT_INFO("Freed pKVideoPortResolutionsSettings\n");
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

dsVideoPortConfigFree() frees only the top-level arrays but never frees the per-entry heap allocations created earlier (strdup() for dsVideoPortTypeConfig_t::name and dsVideoPortPortConfig_t::defaultResolution). This leaks memory every time configs are loaded/freed. Free those duplicated strings (iterate the arrays) before freeing the arrays themselves.

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +57
void videoDeviceDumpconfig(videoDeviceConfigLocal_t *config)
{
if (NULL == config) {
INT_ERROR("Video config is NULL\n");
return;
}
if ( -1 == access("/opt/dsMgrDumpDeviceConfigs", F_OK) ) {
INT_INFO("Dumping of Device configs is disabled\n");
return;
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

videoDeviceDumpconfig() uses access() but this file does not include a header that declares it (e.g., <unistd.h>). Since the build compiles *.c with $(CXX), this is typically a compile error. Add the proper include in this file.

Copilot uses AI. Check for mistakes.
Comment thread ds/videoOutputPortConfig.cpp Outdated
Comment thread ds/dslogger.cpp

if (nullptr != logCb) {
logCb(priority, tmp_buff);
logCb(priority, formatted);

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

When a log callback is registered (logCb != nullptr), ds_log() forwards only the formatted message string and drops fileName, lineNum, and func. Since the logging macros now always supply this metadata, callback users will lose critical context. Consider including the same prefix in the string passed to logCb (consistent with the stderr path).

Suggested change
logCb(priority, formatted);
char fullMsg[MAX_LOG_BUFF] = {'\0'};
snprintf(fullMsg,
sizeof(fullMsg),
"[DS][%d] %s [%s:%d] %s: %s",
(int)syscall(SYS_gettid),
levelMap[static_cast<int>(priority)],
fileName,
lineNum,
func,
formatted);
logCb(priority, fullMsg);

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +181
if (videoPortConfiguration.pKVideoPortConfigs[j].name != NULL)
{
free((void*)videoPortConfiguration.pKVideoPortConfigs[j].name);
videoPortConfiguration.pKVideoPortConfigs[j].name = "NULL";
}
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

On strdup failure cleanup, the code sets videoPortConfiguration.pKVideoPortConfigs[j].name = "NULL" after freeing. Assigning a string literal here makes the pointer non-NULL but not owned, which is error-prone (and can lead to freeing a literal if future cleanup code is added). Prefer setting it to NULL after free().

Copilot uses AI. Check for mistakes.
Comment thread ds/manager.cpp
Comment on lines +266 to +274
bool needInit = false;

{std::lock_guard<std::mutex> lock(gManagerInitMutex);
printf("Entering %s count %d with thread id %lu\n",__FUNCTION__,IsInitialized,pthread_self());
if (IsInitialized == 0) {
needInit = true;
}
IsInitialized++;
}

Copilot AI Feb 26, 2026

Copy link

Choose a reason for hiding this comment

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

Manager::Initialize() increments IsInitialized under the mutex before performing the one-time initialization work. A second thread entering Initialize() while the first is still initializing will see IsInitialized != 0, skip initialization (needInit == false), and return even though the system may not be ready yet. Consider holding the lock until initialization completes, or introduce a separate "initialization in progress/complete" state (e.g., std::once_flag / call_once, or a condition variable) so other threads block until the first initialization finishes successfully.

Copilot uses AI. Check for mistakes.
Comment thread ds/videoOutputPortConfig.hpp
Copilot AI review requested due to automatic review settings March 2, 2026 17:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 41 out of 41 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (2)

rpc/srv/dsDisplay.c:586

  • filterEDIDResolution allocates edidData but never checks whether malloc succeeded. Also the current NULL check is on edid (with a comment about malloc failure), so a NULL edidData would still be dereferenced by memset/memcpy_s, leading to a crash. Add an explicit if (edidData == NULL) guard (and keep the edid == NULL guard separately).
    rpc/srv/dsVideoPort.c:1973
  • getPixelResolution() overwrites Resn on every loop iteration and always returns Resn->pixelResolution after the loop. If resolution does not match any entry, this returns the last resolution’s pixelResolution rather than the default/fallback resolution, which is incorrect behavior. Track whether a match was found and return the default when not found.

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

Comment thread rpc/srv/dsVideoPort.c
Comment on lines +2441 to +2445

if (_dsGetVideoPortPortConfigs(&numPorts, &pVideoPortPorts) != dsERR_NONE) {
INT_ERROR("Failed to get video port port configurations\n");
return NULL;
}

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

dsGetDefaultPortHandle() returns NULL on error, but the return type is intptr_t (an integer type). Returning 0 (or NULL_HANDLE) is clearer and avoids pointer/integer mismatch warnings.

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsAudioConfig.c
Comment on lines +27 to +62
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dsserverlogger.h"
#include "dsTypes.h"
#include "dsError.h"
#include "dsAudioConfig.h"
#include "dsAudioSettings.h"


#ifdef __cplusplus
extern "C" {
#endif

typedef struct audioConfigsLocal
{
dsAudioTypeConfig_t *pKAudioConfigs;
dsAudioPortConfig_t *pKAudioPorts;
int kConfigSize;
int kPortSize;
}audioConfigsLocal_t;

static audioConfigsLocal_t audioConfiguration = {0};

void audioDumpconfig(audioConfigsLocal_t *config)
{
if (NULL == config) {
INT_ERROR("Audio config is NULL\n");
return;
}
if ( -1 == access("/opt/dsMgrDumpDeviceConfigs", F_OK) ) {
INT_INFO("Dumping of Device configs is disabled\n");
return;
}

int configSize = -1, portSize = -1;

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

This file uses access(..., F_OK) but does not include <unistd.h>, which can trigger implicit-declaration warnings (or build failures under stricter flags). Include <unistd.h> (and any needed feature macros) where access is used.

Copilot uses AI. Check for mistakes.
Comment thread ds/manager.cpp
Comment on lines +270 to +278
bool needInit = false;

{std::lock_guard<std::mutex> lock(gManagerInitMutex);
printf("Entering %s count %d with thread id %lu\n",__FUNCTION__,IsInitialized,pthread_self());
if (IsInitialized == 0) {
needInit = true;
}
IsInitialized++;
}

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

Manager::Initialize() increments IsInitialized and allows subsequent callers to return immediately (needInit == false) even while the first thread is still performing initialization. That creates a race where clients observe the manager as “initialized” before init completes. Consider using std::call_once, or keep a separate “initializing/initialized” state with a condition variable so other threads wait for completion (and only increment the refcount after successful init).

Copilot uses AI. Check for mistakes.
Comment thread ds/manager.cpp
Comment on lines +226 to +242
dsError_t initializeFunctionWithRetry(const char* functionName,
std::function<dsError_t()> initFunc)
{
dsError_t err = dsERR_GENERAL;
unsigned int retryCount = 0;
unsigned int maxRetries = 25;

do {
err = initFunc();
printf("Manager::Initialize:%s result :%d retryCount :%d\n",
functionName, err, retryCount);
if (dsERR_NONE == err) break;
usleep(100000);
} while (retryCount++ < maxRetries);

return err;
}

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

initializeFunctionWithRetry() retries unconditionally for any error code. This can add ~2.5s delay on permanent failures (e.g., NOT_SUPPORTED, INVALID_PARAM) and makes failures slower to surface. If the intent is only to wait for service readiness, limit retries to dsERR_INVALID_STATE (or a clearly defined retryable set) and fail fast for other errors.

Copilot uses AI. Check for mistakes.
Comment thread ds/dslogger.cpp
Comment on lines +47 to 52
int ds_log(LogLevel priority, const char* fileName, int lineNum, const char *func, const char *format, ...)
{
char tmp_buff[MAX_LOG_BUFF] = {'\0'};

int offset = snprintf(tmp_buff, MAX_LOG_BUFF, "[%s:%d] ", fileName, lineNum);
char formatted[MAX_LOG_BUFF] = {'\0'};
enum LogLevel {INFO_LEVEL = 0, WARN_LEVEL, ERROR_LEVEL, DEBUG_LEVEL, TRACE_LEVEL};
const char *levelMap[] = { "INFO", "WARN", "ERROR", "DEBUG", "TRACE"};

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

ds_log() indexes levelMap with priority without validating the value. If an out-of-range value is ever passed (e.g., from external callbacks), this becomes an out-of-bounds read. Add a bounds check (and/or clamp to a default string) and remove the redundant inner enum LogLevel declaration to avoid confusion/shadowing.

Copilot uses AI. Check for mistakes.
Comment on lines +213 to +220
intptr_t handle = -1;

// Assuming isHDMIOutPortPresent() will only be 'true' for Source devices
dsVideoPortType_t portType = device::Host::getInstance().isHDMIOutPortPresent()
? dsVIDEOPORT_TYPE_HDMI
: dsVIDEOPORT_TYPE_INTERNAL;
ret = dsGetVideoPort(portType, 0, &handle);
if ((ret == dsERR_NONE) && (handle != -1)) {

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

enabledHDCP() treats -1 as an invalid handle, but elsewhere in the codebase NULL_HANDLE is defined as 0 for intptr_t handles. If dsGetVideoPort() returns 0 on failure, this check would incorrectly treat it as valid. Prefer initializing to 0 and validating against 0/NULL_HANDLE (or use the HAL-defined invalid-handle contract).

Suggested change
intptr_t handle = -1;
// Assuming isHDMIOutPortPresent() will only be 'true' for Source devices
dsVideoPortType_t portType = device::Host::getInstance().isHDMIOutPortPresent()
? dsVIDEOPORT_TYPE_HDMI
: dsVIDEOPORT_TYPE_INTERNAL;
ret = dsGetVideoPort(portType, 0, &handle);
if ((ret == dsERR_NONE) && (handle != -1)) {
intptr_t handle = 0;
// Assuming isHDMIOutPortPresent() will only be 'true' for Source devices
dsVideoPortType_t portType = device::Host::getInstance().isHDMIOutPortPresent()
? dsVIDEOPORT_TYPE_HDMI
: dsVIDEOPORT_TYPE_INTERNAL;
ret = dsGetVideoPort(portType, 0, &handle);
if ((ret == dsERR_NONE) && (handle != 0)) {

Copilot uses AI. Check for mistakes.
Comment thread ds/host.cpp
Comment on lines +428 to +433
{
cout << " Exception Thrown in getAudioPortHandle().. returning NULL...: " << e.what() << "\n";
}

return NULL;
}

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

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

getAudioPortHandle() returns NULL but the return type is intptr_t. Return 0 (or a named invalid-handle constant) to avoid pointer/integer mismatch and make the invalid-handle semantics explicit.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 3, 2026 02:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 41 out of 41 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

rpc/srv/dsDisplay.c:586

  • edidData is allocated with malloc() but the subsequent NULL-check tests edid instead of edidData. If malloc fails, this will dereference NULL in the following memset/memcpy_s. Check edidData == NULL (and return early) before using it.

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

Comment thread ds/manager.cpp

int Manager::IsInitialized = 0; //!< Indicates the application has initialized with devicettings modules.
static std::mutex gManagerInitMutex;
static dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc);

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

initializeFunctionWithRetry is forward-declared as static (internal linkage) but defined later without static, which will fail to compile due to mismatched linkage. Make the definition static as well, or drop the static from the forward declaration (and keep only one consistent declaration/definition).

Suggested change
static dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc);
dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc);

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsAudioConfig.c Outdated
Comment thread ds/host.cpp
Comment on lines +429 to +432
cout << " Exception Thrown in getAudioPortHandle().. returning NULL...: " << e.what() << "\n";
}

return NULL;

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

getAudioPortHandle() returns intptr_t but returns NULL on failure. Return 0 (or a dedicated invalid-handle value) to avoid pointer-to-integer conversion warnings and make the failure value explicit.

Suggested change
cout << " Exception Thrown in getAudioPortHandle().. returning NULL...: " << e.what() << "\n";
}
return NULL;
cout << " Exception Thrown in getAudioPortHandle().. returning 0 (invalid handle)...: " << e.what() << "\n";
}
return 0;

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 3, 2026 06:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 42 out of 42 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

ds/frontPanelConfig.cpp:103

  • FrontPanelConfig::getInstance() now initializes the HAL but no longer loads the static/dynamic indicator/textDisplay configs, so _indicators/_textDisplays remain empty and subsequent getIndicator/getTextDisplay calls will throw "Bad indicator name". Either restore a load step after successful dsFPInit (for the static default) or make accessors fail with a clear "config not loaded" error until load() is called.
            errorCode = dsFPInit();
            if (dsERR_NONE == errorCode)
            {
                _singleton.m_isFPInitialized = true;
                INT_INFO("dsFPInit success\n");
            }
            else{
                INT_ERROR("dsFPInit failed with error[%d]. Retrying... (%d/20)\n", errorCode, retryCount);
                usleep(50000); // Sleep for 50ms before retrying

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

Comment on lines 67 to 69
public:
std::vector<VideoResolution> _originalSupportedResolutions;
static VideoOutputPortConfig & getInstance();

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

Making _originalSupportedResolutions a public mutable member exposes internal state and lets callers modify the config cache (and bypass locking). Prefer keeping it private and exposing a const accessor (e.g., getOriginalSupportedResolutions() returning const std::vector<VideoResolution>&).

Copilot uses AI. Check for mistakes.
Comment thread rpc/srv/dsVideoPort.c
Comment on lines +2442 to +2445
if (_dsGetVideoPortPortConfigs(&numPorts, &pVideoPortPorts) != dsERR_NONE) {
INT_ERROR("Failed to get video port port configurations\n");
return NULL;
}

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

dsGetDefaultPortHandle() returns NULL on error even though the return type is intptr_t. Since callers treat this as a handle and don't check for failure in some paths, returning 0 can lead to HAL calls with an invalid handle. Prefer returning an explicit invalid sentinel (e.g., -1) and updating call sites to guard against it, or propagate the error to the caller instead of returning a handle.

Copilot uses AI. Check for mistakes.
Comment thread ds/dslogger.cpp
Comment on lines 63 to +72
if (nullptr != logCb) {
logCb(priority, tmp_buff);
logCb(priority, formatted);
} else {
return printf("%s\n", tmp_buff);
fprintf(stderr, "[DS][%d] %s [%s:%d] %s: %s \n",
(int)syscall(SYS_gettid),
levelMap[static_cast<int>(priority)],
fileName,
lineNum,
func,
formatted);

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

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

When a log callback is registered, ds_log forwards only the formatted message to logCb and drops the level + file/line/function context that callers expect from the INT_* macros. This is a functional regression for callback consumers; consider building the full prefixed message (including level + [file:line] func) and passing that to the callback too. Also, levelMap[static_cast<int>(priority)] has no bounds check, so an invalid priority can read out of bounds; clamp/validate before indexing.

Copilot uses AI. Check for mistakes.
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.

8 participants