Skip to content

Feature/rdkemw 8587 dlsym - Test#187

Open
yuvaramachandran-gurusamy wants to merge 75 commits intofeature/RDKEMW-8587-config-dlsymfrom
feature/RDKEMW-8587-dlsym
Open

Feature/rdkemw 8587 dlsym - Test#187
yuvaramachandran-gurusamy wants to merge 75 commits intofeature/RDKEMW-8587-config-dlsymfrom
feature/RDKEMW-8587-dlsym

Conversation

@yuvaramachandran-gurusamy
Copy link
Copy Markdown
Contributor

No description provided.

* RDKEMW-4848: pass the proper handle to dsEnableHDCP
@yuvaramachandran-gurusamy yuvaramachandran-gurusamy requested a review from a team as a code owner December 11, 2025 17:35
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>
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>
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Signed-off-by: grandhi_santoshkumar <grandhi_santoshkumar@comcast.com>
Copilot AI review requested due to automatic review settings February 23, 2026 16:51
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 31 out of 31 changed files in this pull request and generated 16 comments.

Comments suppressed due to low confidence (1)

ds/frontPanelConfig.cpp:108

  • The frontPanelConfig.load() method was removed from the getInstance() method but is now expected to be called separately via loadDeviceCapabilities(). However, there's no guard to prevent operations before load() is called. If code tries to use front panel functionality before loadDeviceCapabilities() is invoked, it will fail because _colors, _indicators, and _textDisplays vectors will be empty. Consider adding a check in getter methods or documenting this initialization requirement.
FrontPanelConfig & FrontPanelConfig::getInstance()
{
    static FrontPanelConfig _singleton;
    if (!_singleton.m_isFPInitialized)
    {
        dsError_t errorCode = dsERR_NONE;
        unsigned int retryCount = 1;
        do
        {
            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
            }
        }
        while ((!_singleton.m_isFPInitialized) && (retryCount++ < 20));
    }
	return _singleton;

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

Comment on lines +1944 to +1963
dsVideoPortResolution_t *kVidoeResolutionsSettings = NULL;
int iCount = 0;
dsGetVideoPortResolutions(&iCount, &kVidoeResolutionsSettings);

// Print kVidoeResolutionsSettings array
INT_INFO("[DsMgr] ========== Dumping kVidoeResolutionsSettings Array in getPixelResolution ==========\r\n");
INT_INFO("[DsMgr] Total resolutions retrieved: %d\r\n", iCount);
for (int k = 0; k < iCount; k++) {
dsVideoPortResolution_t *res = &kVidoeResolutionsSettings[k];
INT_INFO("[DsMgr] [%d] name=%s, pixelRes=%d, aspectRatio=%d, stereoMode=%d, frameRate=%d, interlaced=%d\r\n",
k, res->name, res->pixelResolution, res->aspectRatio,
res->stereoScopicMode, res->frameRate, res->interlaced);
}
INT_INFO("[DsMgr] ========== End of kVidoeResolutionsSettings Dump ==========\r\n");

for (unsigned int i = 0; i < dsUTL_DIM(kResolutions); i++)
dsVideoPortResolution_t *Resn = &kVidoeResolutionsSettings[0];

for (int i = 0; i < iCount; i++)
{
Resn = &kResolutions[i];
Resn = &kVidoeResolutionsSettings[i];
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Typo in variable name 'kVidoeResolutionsSettings' - should be 'kVideoResolutionsSettings' (missing 'd' in 'Video'). This typo appears multiple times in the file and affects code readability.

Copilot uses AI. Check for mistakes.
Comment on lines +138 to +144
videoPortConfiguration.pKVideoPortConfigs = (dsVideoPortTypeConfig_t*)malloc(numElements * sizeof(dsVideoPortTypeConfig_t));
if (videoPortConfiguration.pKVideoPortConfigs == NULL) {
INT_ERROR("Failed to allocate memory for %s video port configs\n", configType);
return -1;
}

memcpy(videoPortConfiguration.pKVideoPortConfigs, source, numElements * sizeof(dsVideoPortTypeConfig_t));
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Shallow copy of structures with pointer members. The memcpy operation performs a shallow copy of dsVideoPortTypeConfig_t structures. Based on the stub definition at stubs/dsVideoPortSettings.h:93-103, these structures contain pointer members like 'supportedResolutions' (line 101). When copying from dynamic configs loaded via dlsym, the pointers will reference memory in the dynamically loaded library. If the library is unloaded (as it is at line 168 of dsConfigs.c), these pointers become dangling, leading to undefined behavior when accessed later. Consider either keeping the library loaded or performing deep copies of the data.

Copilot uses AI. Check for mistakes.
Comment on lines +107 to +113
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));
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Shallow copy of structures with pointer members. The memcpy operation performs a shallow copy of dsAudioTypeConfig_t structures which likely contain pointer members (encodings, compressions, stereoModes arrays based on usage at audioOutputPortConfig.cpp:229-241). When copying from dynamic configs loaded via dlsym, the pointers reference memory in the dynamically loaded library. If the library is unloaded (as it is at line 168 of dsConfigs.c), these pointers become dangling, leading to undefined behavior. Consider either keeping the library loaded or performing deep copies.

Copilot uses AI. Check for mistakes.

void audioDumpconfig(audioConfigsLocal_t *config)
{
if (nullptr == config) {
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Mixing C and C++ null pointer constants. In C code (line 52), 'nullptr' is used which is a C++ keyword. In C, use 'NULL' instead. This will cause a compilation error in C code.

Suggested change
if (nullptr == config) {
if (NULL == config) {

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +184
void loadDeviceCapabilities(unsigned int capabilityType)
{
void* pDLHandle = nullptr;
bool isSymbolsLoaded = false;

INT_INFO("Entering capabilityType = 0x%08X", capabilityType);
dlerror(); // clear old error
pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY);
INT_INFO("DL Instance '%s'", (nullptr == pDLHandle ? "NULL" : "Valid"));

// Audio Port Config
if (DEVICE_CAPABILITY_AUDIO_PORT & capabilityType) {
audioConfigs_t dynamicAudioConfigs = {0 };
dlSymbolLookup audioConfigSymbols[] = {
{"kAudioConfigs", (void**)&dynamicAudioConfigs.pKConfigs},
{"kAudioPorts", (void**)&dynamicAudioConfigs.pKPorts},
{"kAudioConfigs_size", (void**)&dynamicAudioConfigs.pKConfigSize},
{"kAudioPorts_size", (void**)&dynamicAudioConfigs.pKPortSize}
};

isSymbolsLoaded = false;
if (nullptr != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, audioConfigSymbols, sizeof(audioConfigSymbols)/sizeof(dlSymbolLookup));
}
AudioOutputPortConfig::getInstance().load(isSymbolsLoaded ? &dynamicAudioConfigs : nullptr);
}

// Video Port Config
if (DEVICE_CAPABILITY_VIDEO_PORT & capabilityType) {
videoPortConfigs_t dynamicVideoPortConfigs = {0};
dlSymbolLookup videoPortConfigSymbols[] = {
{"kVideoPortConfigs", (void**)&dynamicVideoPortConfigs.pKConfigs},
{"kVideoPortConfigs_size", (void**)&dynamicVideoPortConfigs.pKVideoPortConfigs_size},
{"kVideoPortPorts", (void**)&dynamicVideoPortConfigs.pKPorts},
{"kVideoPortPorts_size", (void**)&dynamicVideoPortConfigs.pKVideoPortPorts_size},
{"kResolutionsSettings", (void**)&dynamicVideoPortConfigs.pKResolutionsSettings},
{"kResolutionsSettings_size", (void**)&dynamicVideoPortConfigs.pKResolutionsSettings_size}
};

isSymbolsLoaded = false;
if (nullptr != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoPortConfigSymbols, sizeof(videoPortConfigSymbols)/sizeof(dlSymbolLookup));
}
VideoOutputPortConfig::getInstance().load(isSymbolsLoaded ? &dynamicVideoPortConfigs : nullptr);
}

// Video Device Config
if (DEVICE_CAPABILITY_VIDEO_DEVICE & capabilityType) {
videoDeviceConfig_t dynamicVideoDeviceConfigs = {0};
dlSymbolLookup videoDeviceConfigSymbols[] = {
{"kVideoDeviceConfigs", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs},
{"kVideoDeviceConfigs_size", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs_size}
};
isSymbolsLoaded = false;
if (nullptr != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoDeviceConfigSymbols, sizeof(videoDeviceConfigSymbols)/sizeof(dlSymbolLookup));
}
VideoDeviceConfig::getInstance().load(isSymbolsLoaded ? &dynamicVideoDeviceConfigs : nullptr);
}

// Front Panel Config
if (DEVICE_CAPABILITY_FRONT_PANEL & capabilityType) {
fpdConfigs_t dynamicFPDConfigs = {0};
dlSymbolLookup fpdConfigSymbols[] = {
{"kFPDIndicatorColors", (void**)&dynamicFPDConfigs.pKFPDIndicatorColors},
{"kFPDIndicatorColors_size", (void**)&dynamicFPDConfigs.pKFPDIndicatorColors_size},
{"kIndicators", (void**)&dynamicFPDConfigs.pKIndicators},
{"kIndicators_size", (void**)&dynamicFPDConfigs.pKIndicators_size},
{"kFPDTextDisplays", (void**)&dynamicFPDConfigs.pKTextDisplays},
{"kFPDTextDisplays_size", (void**)&dynamicFPDConfigs.pKTextDisplays_size}
};
isSymbolsLoaded = false;
if (nullptr != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, fpdConfigSymbols, sizeof(fpdConfigSymbols)/sizeof(dlSymbolLookup));
}
FrontPanelConfig::getInstance().load(isSymbolsLoaded ? &dynamicFPDConfigs : nullptr);
}

if (nullptr != pDLHandle) {
dlclose(pDLHandle);
pDLHandle = nullptr;
}
INT_INFO("Exiting ...");
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Duplicate function implementation. loadDeviceCapabilities is implemented in both manager.cpp (lines 101-184) and dsConfigs.c (lines 84-172). These implementations are nearly identical and load the same device configurations. This code duplication violates DRY principle and creates maintenance burden. Consider consolidating into a single shared implementation or clearly documenting why both are needed.

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +134
INT_INFO("Allocated and copied %d audio configs (%s)", numElements, configType);
return numElements;
}

static int allocateAndCopyAudioPorts(const dsAudioPortConfig_t* source, int numElements, bool isDynamic)
{
const char* configType = isDynamic ? "dynamic" : "static";

if (numElements <= 0) {
INT_ERROR("Invalid %s port numElements: %d\n", configType, numElements);
return -1;
}

audioConfiguration.pKAudioPorts = (dsAudioPortConfig_t*)malloc(numElements * sizeof(dsAudioPortConfig_t));
if (audioConfiguration.pKAudioPorts == NULL) {
INT_ERROR("Failed to allocate memory for %s audio ports\n", configType);
return -1;
}

memcpy(audioConfiguration.pKAudioPorts, source, numElements * sizeof(dsAudioPortConfig_t));
INT_INFO("Allocated and copied %d audio ports (%s)", numElements, configType);
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The logging function signature changed to include a 'func' parameter, but the INT_INFO macro at line 114 and 134 doesn't include the '\n' character which was present in the previous logging. This inconsistency could affect log formatting, though it appears the new logging function adds its own newline at line 73 of dslogger.cpp.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +72
vsnprintf(formatted, kFormatMessageSize, format, argptr);
va_end(argptr);

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);
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Potential buffer overflow risk. The log formatting uses kFormatMessageSize (896 bytes) for the user message, but then formats an additional header that could be up to ~128 bytes. If the user message is exactly 896 bytes, the total formatted output at line 66-72 could exceed MAX_LOG_BUFF (1024 bytes), causing buffer overflow. Consider reducing kFormatMessageSize further or using dynamic allocation.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +82
static int LoadDLSymbols(void* pDLHandle, const dlSymbolLookup_t* symbols, int numberOfSymbols)
{
int currentSymbols = 0;
int isAllSymbolsLoaded = 0;

if ((NULL == pDLHandle) || (NULL == symbols)) {
INT_ERROR("Invalid DL Handle or symbolsPtr\n");
return 0;
}

INT_INFO("numberOfSymbols = %d\n", numberOfSymbols);
for (int i = 0; i < numberOfSymbols; i++) {
if ((NULL == symbols[i].dataptr) || (NULL == symbols[i].name)) {
INT_ERROR("Invalid symbol entry at index [%d]\n", i);
continue;
}
*(symbols[i].dataptr) = dlsym(pDLHandle, symbols[i].name);
if (NULL == *(symbols[i].dataptr)) {
INT_ERROR("[%s] is not defined\n", symbols[i].name);
}
else {
currentSymbols++;
INT_INFO("[%s] is defined and loaded, data[%p]\n", symbols[i].name, *(symbols[i].dataptr));
}
}
isAllSymbolsLoaded = (numberOfSymbols) ? (currentSymbols == numberOfSymbols) : 0;
return isAllSymbolsLoaded;
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The function return type is declared as 'int' but the function always returns 0 or -1. However, the caller in dsConfigs.c (line 111) checks the result but doesn't actually use the return value properly - it checks 'isSymbolsLoaded' which is the result of this function, then passes it as a boolean to determine whether to use dynamic or static config. The function should return a boolean type (or the caller should be updated to handle -1 as false).

Copilot uses AI. Check for mistakes.
return numElements;
}

int dsLoadVideoOutputPortConfig(const videoPortConfigs_t* dynamicVideoPortConfigs)
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The function signature declares return type as 'int', but at line 53 in the header file it's declared as 'void'. This is a function signature mismatch between declaration and definition that will cause compilation errors.

Copilot uses AI. Check for mistakes.
Comment on lines +252 to +256
INT_INFO("Store sizes configSize =%d, portSize =%d, resolutionSize = %d\n", configSize, portSize, resolutionSize);
videoPortConfiguration.kDefaultResIndex = defaultResIndex;
INT_INFO("Store sizes videoPortConfiguration.kDefaultResIndex = %d\n", videoPortConfiguration.kDefaultResIndex);

INT_INFO("Store sizes configSize =%d, portSize =%d, resolutionSize = %d\n", configSize, portSize, resolutionSize);
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Duplicate log message at lines 252 and 256. The same information is being logged twice consecutively, which is redundant and clutters the logs.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 24, 2026 12:46
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 41 out of 41 changed files in this pull request and generated 9 comments.


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

Comment on lines 70 to +73
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);

Copy link

Copilot AI Feb 24, 2026

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 but later defined without static, which is a linkage mismatch and typically fails to compile. Also this file uses std::function but doesn't include <functional>. Make the declaration/definition consistent (either both static or both non-static) and add the missing header include.

Copilot uses AI. Check for mistakes.
Comment on lines +1712 to +1721
// Print kVideoPortPorts array
INT_INFO("[DsMgr] ========== Dumping kVideoPortPorts Array in _GetVideoPortType ==========\r\n");
INT_INFO("[DsMgr] Total ports retrieved: %d\r\n", numPorts);
for (int k = 0; k < numPorts; k++) {
const dsVideoPortPortConfig_t *port = &kVideoPortPorts[k];
INT_INFO("[DsMgr] [%d] type=%d, index=%d, connectedAOP_type=%d, connectedAOP_index=%d, defaultResolution=%s\r\n",
k, port->id.type, port->id.index,
port->connectedAOP.type, port->connectedAOP.index,
port->defaultResolution ? port->defaultResolution : "NULL");
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The port/resolution array dumps added here run unconditionally at INT_INFO level and iterate over every entry. These functions can be called frequently, so this can create significant log spam and runtime overhead in production. Please gate these dumps behind an existing runtime flag (e.g., /opt/dsMgrDumpDeviceConfigs) or only enable them under INT_DEBUG/higher log level.

Copilot uses AI. Check for mistakes.
Comment on lines 66 to 68
public:
std::vector<VideoResolution> _supportedResolutions;
static VideoOutputPortConfig & getInstance();
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

_supportedResolutions was moved into the public API surface of VideoOutputPortConfig. This exposes internal mutable state and allows callers to bypass locking (gSupportedResolutionsMutex) which can lead to data races or inconsistent cache state. Prefer keeping this member private and providing a const accessor (or a method that fills a caller-provided list) that preserves the class’ synchronization guarantees.

Copilot uses AI. Check for mistakes.
Comment on lines +388 to +433
intptr_t Host::getAudioPortHandle()
{
try
{
if (isHDMIOutPortPresent())
{
//STB profile with single audio output port
AudioOutputPort aPort = getAudioOutputPort("HDMI0");
return aPort.getOutputPortHandle();
}
else
{
//TV profile with multiple audio output ports
// First check the ports which are dynamically conected and finally fallback to SPEAKER0 which is always connected.
const std::string audio_ports[] = {"HDMI_ARC0", "HEADPHONE0", "SPDIF0", "SPEAKER0"};

// Try each port in priority order
for (const auto& portName : audio_ports)
{
try
{
AudioOutputPort aPort = getAudioOutputPort(portName);
cout << "Checking audio port: " << portName << " isEnabled: " << aPort.isEnabled() << " isConnected: " << aPort.isConnected() << "\n";
// Check if port is enabled and connected
if (aPort.isEnabled() && aPort.isConnected())
{
cout << "Using audio port: " << portName << "\n";
return aPort.getOutputPortHandle();
}
}
catch(const std::exception& e)
{
// Port not found or error accessing it, log and continue to next port
cout << "Exception while accessing audio port " << portName << ": " << e.what() << "\n";
continue;
}
}
}
}
catch(const std::exception& e)
{
cout << " Exception Thrown in getAudioPortHandle().. returning NULL...: " << e.what() << "\n";
}

return NULL;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

Host::getAudioPortHandle() returns NULL even though the return type is intptr_t. This can be misleading and makes it harder to distinguish “no handle” from a valid numeric handle; it also gets passed into dsGetAudioFormat() immediately after. Return a well-defined invalid handle value (e.g., 0 or -1, matching HAL expectations) and consider logging via INT_* macros instead of cout for consistency with the rest of the module.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +67
if ( -1 == access("/opt/dsMgrDumpDeviceConfigs", F_OK) ) {
INT_INFO("Dumping of Device configs is disabled\n");
return;
}
INT_INFO("\n=============== Starting to Dump VideoPort Configs ===============\n");

int configSize = -1, portSize = -1, resolutionSize = -1;
if (( NULL != config->pKVideoPortConfigs ) && ( NULL != config->pKVideoPortPorts ) && ( nullptr != config->pKVideoPortResolutionsSettings ))
{
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

This file is compiled as C (.c) but uses C++ nullptr (line 66) and calls access()/F_OK without including the proper header. This will fail to compile on C toolchains (and C99+ treats implicit declarations as errors). Replace nullptr with NULL and add the required includes (e.g., <unistd.h> for access/F_OK; also ensure bool is available via <stdbool.h> or a project header).

Copilot uses AI. Check for mistakes.
Comment on lines 38 to 39
#define DEBUG 1 // Using for dumpconfig

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

#define DEBUG 1 is introduced but never used in this translation unit. Consider removing it to avoid dead code/macros and accidental interactions with other headers/macros during compilation.

Suggested change
#define DEBUG 1 // Using for dumpconfig

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +55
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;
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

access()/F_OK is used here but this C file doesn't include the header that declares it (typically <unistd.h>). On C99+ compilers this can be a hard error due to implicit function declaration. Please include the correct header (and ensure bool is defined via <stdbool.h> or a project header since this file uses bool later).

Copilot uses AI. Check for mistakes.
Comment on lines +1959 to +1960
dsVideoPortResolution_t *Resn = &kVidoeResolutionsSettings[0];

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

getPixelResolution() unconditionally sets Resn = &kVidoeResolutionsSettings[0] even when dsGetVideoPortResolutions() returns iCount == 0 or kVidoeResolutionsSettings == NULL, which will dereference invalid memory. Add a guard for iCount > 0 && kVidoeResolutionsSettings != NULL and return a safe default (or an error) when the resolutions list isn't available.

Copilot uses AI. Check for mistakes.
Comment on lines +674 to +678
const dsVideoPortPortConfig_t *port = &kVideoPortPorts[k];
INT_INFO("[DsMgr] [%d] type=%d, index=%d, connectedAOP_type=%d, connectedAOP_index=%d, defaultResolution=%s\r\n",
k, port->id.type, port->id.index,
port->connectedAOP.type, port->connectedAOP.index,
port->defaultResolution);
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

In _GetDisplayPortType(), the log prints port->defaultResolution with %s without a NULL check. If defaultResolution is NULL for any port, this can crash during logging. Use a ternary fallback (e.g., "NULL") like other call sites.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 26, 2026 15:43
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 41 out of 41 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

rpc/srv/dsDisplay.c:586

  • After malloc(sizeof(dsDisplayEDID_t)), the code checks if (edid == NULL) but the comment says it's handling malloc failure. This should check edidData == NULL (and also handle the case where edidData is NULL before memset/memcpy_s). As written, an allocation failure will lead to a NULL dereference.

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

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");
}
Copy link

Copilot AI Feb 26, 2026

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 allocateAndCopyVideoPortConfigs() and allocateAndCopyVideoPortPorts() deep-copy strings (name, defaultResolution). Those heap allocations will leak unless freed per-entry before freeing the arrays.

Copilot uses AI. Check for mistakes.
Comment on lines +50 to 55
#define INT_ERROR(FORMAT, ...) LOG_ERROR(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define INT_WARNING(FORMAT, ...) LOG_WARNING(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define INT_INFO(FORMAT, ...) LOG_INFO(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define INT_DEBUG(FORMAT, ...) LOG_DEBUG(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define INT_TRACE(FORMAT, ...) LOG_TRACE(PREFIX(FORMAT), fileName(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)

Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

INT_TRACE expands to LOG_TRACE(...), but LOG_TRACE is not defined anywhere in this header (only DEBUG/ERROR/INFO/WARNING exist). This leaves a broken macro that will fail to compile if INT_TRACE is ever used. Define LOG_TRACE (mapping to an appropriate RDK_LOG level) or remove INT_TRACE.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +56
{
if (nullptr == config) {
INT_ERROR("Audio config is NULL\n");
return;
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

audioDumpconfig() uses nullptr, but this file is C (.c) and will not compile. Use NULL (and consider adding a NULL check for edidData-style allocations consistently).

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +116
static int allocateAndCopyAudioConfigs(const dsAudioTypeConfig_t* source, int numElements, bool isDynamic)
{
const char* configType = isDynamic ? "dynamic" : "static";

if (numElements <= 0) {
INT_ERROR("Invalid %s config numElements: %d\n", configType, numElements);
return -1;
}

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;
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

allocateAndCopyAudioConfigs() does a shallow memcpy of dsAudioTypeConfig_t. That struct contains pointer fields (e.g., name, encodings, compressions, stereoModes), so after dsConfigs.c dlclose()s the HAL, these pointers can dangle and cause use-after-free when audio config is accessed. Deep-copy the pointed-to data (and free it in dsAudioConfigFree()), or keep the HAL library loaded for the lifetime of the cached config.

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +179
static dsError_t loadDeviceCapabilities(unsigned int capabilityType)
{
void* pDLHandle = NULL;
int isSymbolsLoaded = 0;
dsError_t ret = dsERR_GENERAL, audioRet = dsERR_GENERAL, videoRet = dsERR_GENERAL, videoPortRet = dsERR_GENERAL;

INT_INFO("Entering capabilityType = 0x%08X\n", capabilityType);
dlerror(); /* clear old error */
pDLHandle = dlopen(RDK_DSHAL_NAME, RTLD_LAZY);
INT_INFO("DL Instance '%s'\n", (NULL == pDLHandle ? "NULL" : "Valid"));

/* Audio Port Config */
if (DEVICE_CAPABILITY_AUDIO_PORT & capabilityType) {
audioConfigs_t dynamicAudioConfigs;
memset(&dynamicAudioConfigs, 0, sizeof(audioConfigs_t));

dlSymbolLookup_t audioConfigSymbols[] = {
{"kAudioConfigs", (void**)&dynamicAudioConfigs.pKAudioConfigs},
{"kAudioPorts", (void**)&dynamicAudioConfigs.pKAudioPorts},
{"kAudioConfigs_size", (void**)&dynamicAudioConfigs.pKConfigSize},
{"kAudioPorts_size", (void**)&dynamicAudioConfigs.pKPortSize}
};

isSymbolsLoaded = 0;
if (NULL != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, audioConfigSymbols,
sizeof(audioConfigSymbols)/sizeof(dlSymbolLookup_t));
}
audioRet = dsLoadAudioOutputPortConfig(isSymbolsLoaded ? &dynamicAudioConfigs : NULL);
if(audioRet == dsERR_GENERAL)
{
INT_ERROR("dsLoadAudioOutputPortConfig() failed");
}
}

/* Video Port Config */
if (DEVICE_CAPABILITY_VIDEO_PORT & capabilityType) {
videoPortConfigs_t dynamicVideoPortConfigs;
memset(&dynamicVideoPortConfigs, 0, sizeof(videoPortConfigs_t));

dlSymbolLookup_t videoPortConfigSymbols[] = {
{"kVideoPortConfigs", (void**)&dynamicVideoPortConfigs.pKVideoPortConfigs},
{"kVideoPortConfigs_size", (void**)&dynamicVideoPortConfigs.pKVideoPortConfigs_size},
{"kVideoPortPorts", (void**)&dynamicVideoPortConfigs.pKVideoPortPorts},
{"kVideoPortPorts_size", (void**)&dynamicVideoPortConfigs.pKVideoPortPorts_size},
{"kResolutionsSettings", (void**)&dynamicVideoPortConfigs.pKVideoPortResolutionsSettings},
{"kResolutionsSettings_size", (void**)&dynamicVideoPortConfigs.pKResolutionsSettings_size},
{"kDefaultResIndex", (void**)&dynamicVideoPortConfigs.pKDefaultResIndex}
};

isSymbolsLoaded = 0;
if (NULL != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoPortConfigSymbols,
sizeof(videoPortConfigSymbols)/sizeof(dlSymbolLookup_t));
}
videoPortRet = dsLoadVideoOutputPortConfig(isSymbolsLoaded ? &dynamicVideoPortConfigs : NULL);
if(videoPortRet == dsERR_GENERAL)
{
INT_ERROR("dsLoadVideoOutputPortConfig() failed");
}
}

/* Video Device Config */
if (DEVICE_CAPABILITY_VIDEO_DEVICE & capabilityType) {
videoDeviceConfig_t dynamicVideoDeviceConfigs;
memset(&dynamicVideoDeviceConfigs, 0, sizeof(videoDeviceConfig_t));

dlSymbolLookup_t videoDeviceConfigSymbols[] = {
{"kVideoDeviceConfigs", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs},
{"kVideoDeviceConfigs_size", (void**)&dynamicVideoDeviceConfigs.pKVideoDeviceConfigs_size}
};

isSymbolsLoaded = 0;
if (NULL != pDLHandle) {
isSymbolsLoaded = LoadDLSymbols(pDLHandle, videoDeviceConfigSymbols,
sizeof(videoDeviceConfigSymbols)/sizeof(dlSymbolLookup_t));
}
videoRet = dsLoadVideoDeviceConfig(isSymbolsLoaded ? &dynamicVideoDeviceConfigs : NULL);
if(videoRet == dsERR_GENERAL)
{
INT_ERROR("dsLoadVideoDeviceConfig() failed");
}
}

if (NULL != pDLHandle) {
dlclose(pDLHandle);
pDLHandle = NULL;
}

if(audioRet == dsERR_GENERAL || videoRet == dsERR_GENERAL || videoPortRet == dsERR_GENERAL)
{
INT_ERROR("Failed to load device capabilities: audioRet=%d, videoRet=%d, videoPortRet=%d\n", audioRet, videoRet, videoPortRet);
return dsERR_GENERAL;
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

In loadDeviceCapabilities(), audioRet/videoRet/videoPortRet are initialized to dsERR_GENERAL and later the function returns failure if any remain dsERR_GENERAL, even when that capability wasn't requested in capabilityType. This makes the capabilityType parameter misleading and will break partial loads. Initialize the "*_Ret" variables to dsERR_NONE and only validate the ones corresponding to requested capability bits (or gate the final check by capabilityType).

Copilot uses AI. Check for mistakes.

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

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

When logCb is registered, ds_log() now forwards only the raw formatted message (without level/file/line/function context). Since the callback signature is just (priority, const char*), this is a behavior change that drops important context compared to the stderr path. Consider prefixing the message with the same metadata before invoking logCb (or keep the previous behavior).

Suggested change
logCb(priority, formatted);
char fullMsg[MAX_LOG_BUFF] = {'\0'};
snprintf(fullMsg,
sizeof(fullMsg),
"[DS][%d] %s [%s:%d] %s: %s \n",
(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 +2442 to +2445
if (_dsGetVideoPortPortConfigs(&numPorts, &pVideoPortPorts) != dsERR_NONE) {
INT_ERROR("Failed to get video port port configurations\n");
return NULL;
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

This function returns NULL on error, but its return type is intptr_t and this module already defines NULL_HANDLE as 0. Returning NULL_HANDLE (or a documented sentinel) would be clearer and avoids pointer-typed semantics in integer APIs.

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

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

In the error cleanup path, this code frees videoPortResolutionsSettings[i].name, but dsVideoPortResolution_t::name is a fixed-size array (copied via memcpy), not a heap pointer. Freeing it is invalid and can crash. Remove these per-entry frees and only free the resolutions array itself.

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

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Same issue as above: the cleanup path frees videoPortResolutionsSettings[i].name, which is not heap-allocated. This is an invalid free.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 2, 2026 17:26
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 41 out of 41 changed files in this pull request and generated 7 comments.


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

Comment on lines +27 to +35
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dsserverlogger.h"
#include "dsTypes.h"
#include "dsError.h"
#include "dsAudioConfig.h"
#include "dsAudioSettings.h"

Copy link

Copilot AI Mar 2, 2026

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 lead to implicit-declaration warnings/errors depending on compiler flags. Add the proper include so the declaration and F_OK are available.

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +35
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dsserverlogger.h"
#include "dsTypes.h"
#include "dsError.h"
#include "dsVideoDeviceConfig.h"
#include "dsVideoDeviceSettings.h"

Copy link

Copilot AI Mar 2, 2026

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 lead to implicit-declaration warnings/errors depending on compiler flags. Add the proper include so the declaration and F_OK are available.

Copilot uses AI. Check for mistakes.
Comment on lines 66 to 69
public:
std::vector<VideoResolution> _supportedResolutions;
std::vector<VideoResolution> _originalSupportedResolutions;
static VideoOutputPortConfig & getInstance();
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

Making _supportedResolutions and _originalSupportedResolutions public exposes mutable internal state to the rest of the codebase, which makes it easy to accidentally corrupt the cache and creates tight coupling. Prefer keeping these members private and providing a const accessor (e.g., returning a const std::vector<VideoResolution>& or a read-only List).

Copilot uses AI. Check for mistakes.

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);
Copy link

Copilot AI Mar 2, 2026

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 but defined without static later in the file. This changes linkage and typically results in a compile error. Make the declaration/definition consistent (either both static or both non-static).

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 on lines +27 to +35
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dsserverlogger.h"
#include "dsTypes.h"
#include "dsError.h"
#include "dsVideoPortSettings.h"
#include "dsVideoResolutionSettings.h"
#include "dsVideoPortConfig.h"
Copy link

Copilot AI Mar 2, 2026

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 lead to implicit-declaration warnings/errors depending on compiler flags. Add the proper include so the declaration and F_OK are available.

Copilot uses AI. Check for mistakes.
Comment on lines 36 to 60
@@ -52,13 +49,13 @@ static inline const char* fileName(const char* path) {
#define DS_LOG_LEVEL ERROR_LEVEL
#endif

#define INT_INFO(FORMAT, ...) ds_log(INFO_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ )
#define INT_WARN(FORMAT, ...) ds_log(WARN_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ )
#define INT_ERROR(FORMAT, ...) ds_log(ERROR_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ )
#define INT_INFO(FORMAT, ...) ds_log(INFO_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ )
#define INT_WARN(FORMAT, ...) ds_log(WARN_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ )
#define INT_ERROR(FORMAT, ...) ds_log(ERROR_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ )

// conditionally enable debug logs, based on DS_LOG_LEVEL
#if DS_LOG_LEVEL >= DEBUG_LEVEL
#define INT_DEBUG(FORMAT, ...) ds_log(DEBUG_LEVEL, fileName(__FILE__), __LINE__, FORMAT, ##__VA_ARGS__ )
#define INT_DEBUG(FORMAT, ...) ds_log(DEBUG_LEVEL, fileName(__FILE__), __LINE__, __FUNCTION__, FORMAT, ##__VA_ARGS__ )
#else
#define INT_DEBUG(FORMAT, ...) ((void)0)
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

DS_LOG_LEVEL is defined to the enum identifier ERROR_LEVEL, but #if DS_LOG_LEVEL >= DEBUG_LEVEL is evaluated by the preprocessor. Since enum identifiers aren't macros, they evaluate as 0, which will make this condition behave incorrectly (typically enabling debug logs unconditionally). Define log levels as preprocessor constants (or make DS_LOG_LEVEL a numeric literal) so the #if works as intended.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +136
static int allocateAndCopyAudioPorts(const dsAudioPortConfig_t* source, int numElements, bool isDynamic)
{
const char* configType = isDynamic ? "dynamic" : "static";

if (numElements <= 0) {
INT_ERROR("Invalid %s port numElements: %d\n", configType, numElements);
return -1;
}

audioConfiguration.pKAudioPorts = (dsAudioPortConfig_t*)malloc(numElements * sizeof(dsAudioPortConfig_t));
if (audioConfiguration.pKAudioPorts == NULL) {
INT_ERROR("Failed to allocate memory for %s audio ports\n", configType);
return -1;
}

memcpy(audioConfiguration.pKAudioPorts, source, numElements * sizeof(dsAudioPortConfig_t));
INT_INFO("Allocated and copied %d audio ports (%s)", numElements, configType);
return numElements;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

allocateAndCopyAudioPorts() does a shallow memcpy of dsAudioPortConfig_t. The port config struct includes pointer members (e.g., connected VOPs in the stub configs), so after dlclose() those pointers can become dangling. Deep-copy any pointer members here as well, and ensure dsAudioConfigFree() frees them.

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

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

Copilot reviewed 41 out of 41 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

rpc/srv/dsDisplay.c:586

  • edidData is allocated with malloc(), but the subsequent NULL check is against edid rather than edidData. If the allocation fails, memset(edidData, ...) will dereference NULL and crash. Please check edidData == NULL (and separately validate edid) before using it.

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

Comment on lines +2442 to +2445
if (_dsGetVideoPortPortConfigs(&numPorts, &pVideoPortPorts) != dsERR_NONE) {
INT_ERROR("Failed to get video port port configurations\n");
return NULL;
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

dsGetDefaultPortHandle() returns NULL on failure, but the return type is intptr_t (integer). In C this is typically a pointer constant and can trigger -Wint-conversion warnings; also callers likely expect 0/NULL_HANDLE for an invalid handle. Return 0 (or the project’s invalid-handle constant) instead.

Copilot uses AI. Check for mistakes.
Comment on lines +2297 to +2302
//This function does not have any caller.
bool isComponentPortPresent()
{
bool componentPortPresent = false;
int numPorts,i;

numPorts = dsUTL_DIM(kSupportedPortTypes);
for(i=0; i< numPorts; i++)
{
if (kSupportedPortTypes[i] == dsVIDEOPORT_TYPE_COMPONENT)
int numTypeConfigs = 0;
const dsVideoPortTypeConfig_t* typeConfigs = NULL;
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

isComponentPortPresent() is not referenced anywhere in the codebase (as noted by the comment) and is currently a non-static symbol in a C translation unit. If it’s meant to be an internal helper, make it static (or remove it) to avoid exporting an unused symbol from the server binary/library.

Copilot uses AI. Check for mistakes.
Comment on lines +246 to +263
// Deep copy connectedVOPs array if present
// Note: We need to know the size of connectedVOPs array
// For now, assuming it's NULL or a single element (common case)
// A proper implementation would need size information
if (src->connectedVOPs != NULL) {
dest->connectedVOPs = (dsVideoPortPortId_t*)malloc(sizeof(dsVideoPortPortId_t));
if (dest->connectedVOPs == NULL) {
INT_ERROR("Failed to allocate connectedVOPs for audio port %d\n", i);
// Cleanup previously allocated items
for (int j = 0; j < i; j++) {
free((void*)audioConfiguration.pKAudioPorts[j].connectedVOPs);
}
free(audioConfiguration.pKAudioPorts);
audioConfiguration.pKAudioPorts = NULL;
return -1;
}
memcpy((void*)dest->connectedVOPs, src->connectedVOPs, sizeof(dsVideoPortPortId_t));
} else {
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

connectedVOPs is deep-copied as if it contains a single dsVideoPortPortId_t, but in the existing stub config it is an array indexed by dsVIDEOPORT_TYPE_MAX (i.e., multiple entries). Copying/allocating only one element will truncate the data and can lead to out-of-bounds reads if callers iterate over the expected array length. Allocate/copy the full expected array size (or add an explicit size field to dsAudioPortConfig_t and copy that many elements).

Copilot uses AI. Check for mistakes.
Comment on lines +592 to +597
int iCount = 0;
//Get details from libds
if (_dsGetVideoPortResolutions(&iCount, &pVideoResolutionsSettings) != dsERR_NONE) {
INT_ERROR("Failed to get video port resolutions\n");
}

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

If _dsGetVideoPortResolutions() fails, iCount remains 0 and pVideoResolutionsSettings stays NULL, so the loop never runs and edid->numOfSupportedResolution is left at 0 even if the EDID contains supported modes. Consider returning early without clearing the EDID list, or falling back to the static resolution table so behavior matches the previous implementation.

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

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

Copilot reviewed 42 out of 42 changed files in this pull request and generated 5 comments.


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

Comment on lines +32 to +33
libdshalsrv_la_SOURCES = dsHost.cpp hostPersistence.cpp dsAudio.c dsDisplay.c dsFPD.c dsMgr.c dsVideoDevice.c dsVideoPort.c dsserverlogger.c \
dsConfigs.c dsAudioConfig.c dsVideoPortConfig.c dsVideoDeviceConfig.c dsCompositeIn.c dsHdmiIn.c
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

dsConfigs.c uses dlopen/dlsym/dlclose, but libdshalsrv_la doesn't appear to link against libdl. On many toolchains this will fail at link time with unresolved dlopen symbols. Consider adding -ldl via libdshalsrv_la_LIBADD (or an appropriate *_LDFLAGS) so the new config loader links reliably.

Copilot uses AI. Check for mistakes.
Comment on lines +209 to +225
/**
* @brief Retry initialization function with configurable retry logic.
*
* This helper function attempts to initialize a device settings component by calling
* the provided initialization function. It retries the operation with a delay between
* attempts until either the operation succeeds, the maximum retry count is reached,
* or (optionally) a specific error state is encountered.
*
* @param[in] functionName Name of the initialization function being called. Used for logging
* purposes to identify which component is being initialized.
* @param[in] initFunc Lambda or function object that performs the actual initialization.
* Should return dsError_t indicating success (dsERR_NONE) or an error code.
*
* @return dsERR_NONE on successful initialization, or the last error code encountered after
* all retry attempts are exhausted. When checkInvalidState is true, also returns
* immediately with the error code if a non-dsERR_INVALID_STATE error occurs.
*/
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

initializeFunctionWithRetry’s docstring mentions returning early based on dsERR_INVALID_STATE / a checkInvalidState option, but the implementation retries unconditionally for any non-dsERR_NONE result and has no checkInvalidState parameter. Please align the comment with the actual behavior (or implement the described behavior if that was the intent).

Copilot uses AI. Check for mistakes.
Comment on lines 268 to +272
void Manager::Initialize()
{
{std::lock_guard<std::mutex> lock(gManagerInitMutex);
printf("Entering %s count %d with thread id %lu\n",__FUNCTION__,IsInitialized,pthread_self());
bool needInit = false;

{std::lock_guard<std::mutex> lock(gManagerInitMutex);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The Manager::Initialize() API comment immediately above this function still references AudioOutputPortConfig::getInstance().load() / VideoOutputPortConfig::getInstance().load() / VideoDeviceConfig::getInstance().load() with no parameters, but these load methods now take dynamic config pointers and are invoked via loadDeviceCapabilities(...). Updating that comment would prevent callers from following an outdated initialization sequence.

Copilot uses AI. Check for mistakes.
$(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -ldshalcli -shared -o $(LIBNAMEFULL)
$(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -ldshalcli -shared -o $(LIBNAMECLI)
$(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMEFULL)
$(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI)
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This library now calls dlopen/dlsym (see ds/manager.cpp), but the link command here only adds -lIARMBus -ldshalcli. On many systems you must also link -ldl to resolve these symbols. Consider adding -ldl (or ensuring $(DSHAL_LDFLAGS) already includes it) to avoid link failures.

Suggested change
$(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI)
$(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI)

Copilot uses AI. Check for mistakes.
Comment on lines +124 to +126
catch (...) {
printf("Unknown exception during DeInitialize\n");
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Minor: the new printf uses \n while surrounding output in this file uses \r\n. For consistent console output formatting, consider using \r\n here too.

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.

7 participants