Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/IJavaScriptContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
class IJavaScriptContext
{
public:
virtual ~IJavaScriptContext() = default; //change added

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

The comment "//change added" is unclear and unnecessary. Comments should explain why code exists, not document when it was added (that's what version control is for).

Suggested change
virtual ~IJavaScriptContext() = default; //change added
virtual ~IJavaScriptContext() = default;

Copilot uses AI. Check for mistakes.
virtual bool runScript(const char *script, bool isModule=true, std::string name="", const char *args = nullptr, bool isApplication=false) = 0;
virtual bool runFile(const char *file, const char* args, bool isApplication=false) = 0;
virtual std::string getUrl() = 0;
Expand Down
62 changes: 36 additions & 26 deletions src/JSRuntimeClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ bool JSRuntimeClient::run()
t.detach();

std::unique_lock<std::mutex> lock(mStateMutex);
mStateCondition.wait_for(lock, std::chrono::seconds(5));
mStateCondition.wait_for(lock, std::chrono::seconds(5), [this]() {
return mState != "none";
});
return mState == "open";
}

Expand Down Expand Up @@ -152,37 +154,45 @@ void JSRuntimeClient::onClose(websocketpp::connection_hdl hdl)
#ifndef UNIT_TEST_BUILD
int main(int argc, char **argv)
{
std::string command;
std::string response;
try {
std::string command;
std::string response;

if (argc > 1)
{
NativeJSLogger::log(INFO, "Send input commands at ws://localhost:%s\n", std::to_string(WS_SERVER_PORT).c_str());
return -1;
}

JSRuntimeClient *client = JSRuntimeClient::getInstance();
client->initialize(WS_SERVER_PORT);
if (!client->run())
{
NativeJSLogger::log(ERROR, "Unable to connect to server\n");
return -1;
}
if (argc > 1)
{
NativeJSLogger::log(INFO, "Send input commands at ws://localhost:%s\n", std::to_string(WS_SERVER_PORT).c_str());
return -1;
}

while (client->getState() == "open" && std::getline(std::cin, command))
{
client->sendCommand(command, response);
if (!response.empty())
JSRuntimeClient *client = JSRuntimeClient::getInstance();
client->initialize(WS_SERVER_PORT);
if (!client->run())
{
NativeJSLogger::log(INFO, "Response: %s\n", response.c_str());
NativeJSLogger::log(ERROR, "Unable to connect to server\n");
return -1;
}
else

while (client->getState() == "open" && std::getline(std::cin, command))
{
NativeJSLogger::log(WARN, "Missing response\n");
break;
client->sendCommand(command, response);
if (!response.empty())
{
NativeJSLogger::log(INFO, "Response: %s\n", response.c_str());
}
else
{
NativeJSLogger::log(WARN, "Missing response\n");
break;
}
}
}

return 0;
return 0;
} catch (const std::exception& e) {
NativeJSLogger::log(ERROR, "Uncaught exception in main: %s\n", e.what());
return -1;
} catch (...) {
NativeJSLogger::log(ERROR, "Unknown exception caught in main\n");
return -1;
}
}
#endif
46 changes: 28 additions & 18 deletions src/JSRuntimeClientContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,36 @@
#include "NativeJSLogger.h"
int main()
{
std::string containerId = "com.sky.as.apps_TestApp";
const std::string basePath = "/opt/twocontext"; // constant base path
const std::vector<std::string> apps = {"app1", "app2"};

std::string ipAddress = JSRuntimeContainer::getContainerIpAddress(containerId);
if (ipAddress.empty()) {
NativeJSLogger::log(ERROR, "Failed to retrieve IP address for container");
return 1;
}
try {
std::string containerId = "com.sky.as.apps_TestApp";
const std::string basePath = "/opt/twocontext"; // constant base path
const std::vector<std::string> apps = {"app1", "app2"};

std::string ipAddress = JSRuntimeContainer::getContainerIpAddress(containerId);
if (ipAddress.empty()) {
NativeJSLogger::log(ERROR, "Failed to retrieve IP address for container");

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

Missing newline character in the log message format string. The message should end with \n for proper logging output formatting.

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

for (const auto &app : apps) {
std::string url = basePath + std::string("/") + app + std::string("/index.html");
if (access(url.c_str(), F_OK) == 0) {
std::string pathAppConfig = basePath + std::string("/") + app + std::string("/app.config");
std::string options = JSRuntimeContainer::parseAppConfig(pathAppConfig);
std::string message = JSRuntimeContainer::buildLaunchMessage(url, options);
JSRuntimeContainer::connectAndSend(ipAddress, message);
for (const auto &app : apps) {
std::string url = basePath + std::string("/") + app + std::string("/index.html");
if (access(url.c_str(), F_OK) == 0) {
std::string pathAppConfig = basePath + std::string("/") + app + std::string("/app.config");
std::string options = JSRuntimeContainer::parseAppConfig(pathAppConfig);
std::string message = JSRuntimeContainer::buildLaunchMessage(url, options);
JSRuntimeContainer::connectAndSend(ipAddress, message);
}
}
}

return 0;
return 0;
}
catch (const std::exception& e) {
NativeJSLogger::log(ERROR, "Exception in main: %s", e.what());

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

Missing newline character in the log message format string. The message should end with \n for proper logging output formatting.

Copilot uses AI. Check for mistakes.
return 1;
}
catch (...) {
NativeJSLogger::log(ERROR, "Unknown exception in main");

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

Missing newline character in the log message format string. The message should end with \n for proper logging output formatting.

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

1 change: 1 addition & 0 deletions src/JSRuntimeServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class JsonWrap
if (!itm || !cJSON_IsNumber(itm))
{
std::cerr << "Error: " << name << "is not a Uint32_t" << std::endl;
res=0;
err = true;
}
else
Expand Down
78 changes: 63 additions & 15 deletions src/NativeJSRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ void NativeJSRenderer::createApplicationInternal(ApplicationRequest& appRequest)
context->setCreateApplicationEndTime(endTime, id);

mContextMap[id].context=context;
mUserMutex.unlock();
}

void NativeJSRenderer::runApplicationInternal(ApplicationRequest& appRequest)
Expand Down Expand Up @@ -445,7 +444,7 @@ void NativeJSRenderer::terminateApplicationInternal(ApplicationRequest& AppReque

else
{
NativeJSLogger::log(ERROR, "Unable to find application with id: %d and url: %s\n", id, mContextMap[id].url);
NativeJSLogger::log(ERROR, "Unable to find application with id: %d and url: %s\n", id, mContextMap[id].url.c_str());

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

This code attempts to access mContextMap[id] in the else branch when the id was not found in the map (mapEntry == mContextMap.end()). This will either create a new invalid entry in the map or access uninitialized memory, potentially causing a crash or undefined behavior.

Suggested change
NativeJSLogger::log(ERROR, "Unable to find application with id: %d and url: %s\n", id, mContextMap[id].url.c_str());
NativeJSLogger::log(ERROR, "Unable to find application with id: %d\n", id);

Copilot uses AI. Check for mistakes.
return ;
}

Expand All @@ -468,7 +467,6 @@ void NativeJSRenderer::run()
{
while(mRunning)
{
uint32_t id;
mUserMutex.lock();
if (mConsoleMode) {
processDevConsoleRequests();
Expand Down Expand Up @@ -506,6 +504,7 @@ void NativeJSRenderer::run()
if(!mTestFileName.empty())
{
ModuleSettings settings;
uint32_t id;

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

The variable 'id' is declared but not initialized before being passed to ApplicationRequest constructor. This will result in undefined behavior as the uninitialized value is used to construct the ApplicationRequest object and subsequently used in createApplicationInternal and runApplicationInternal calls.

Suggested change
uint32_t id;
uint32_t id = 0;

Copilot uses AI. Check for mistakes.
settings.enableJSDOM = mEnableTestFileDOMSupport;
ApplicationRequest appRequest(id, RUN, mTestFileName, settings.enableHttp, settings.enableXHR, settings.enableWebSocket, settings.enableWebSocketEnhanced, settings.enableFetch, settings.enableJSDOM, settings.enableWindow, settings.enablePlayer);
NativeJSRenderer::createApplicationInternal(appRequest);
Expand Down Expand Up @@ -620,18 +619,67 @@ bool NativeJSRenderer::downloadFile(std::string& url, MemoryStruct& chunk)
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_PROXY, "");
res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_URL: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_FOLLOWLOCATION: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_HEADERFUNCTION: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)&chunk);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_HEADERDATA: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_WRITEFUNCTION: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_WRITEDATA: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_TIMEOUT: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_NOSIGNAL: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_SSL_VERIFYHOST: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_SSL_VERIFYPEER: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_USERAGENT: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);

}
res = curl_easy_setopt(curl, CURLOPT_PROXY, "");
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_PROXY: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
Comment on lines +661 to +681

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

After curl_easy_cleanup is called on error, the function continues executing with the same curl handle which is now invalid. After each error case with curl_easy_cleanup, the function should return immediately to avoid using the freed handle.

Suggested change
}
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_SSL_VERIFYHOST: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_SSL_VERIFYPEER: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_USERAGENT: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
res = curl_easy_setopt(curl, CURLOPT_PROXY, "");
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_PROXY: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return ret;
}
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_SSL_VERIFYHOST: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return ret;
}
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_SSL_VERIFYPEER: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return ret;
}
res = curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_USERAGENT: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return ret;
}
res = curl_easy_setopt(curl, CURLOPT_PROXY, "");
if (res != CURLE_OK) {
NativeJSLogger::log(ERROR, "Failed to set CURLOPT_PROXY: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return ret;

Copilot uses AI. Check for mistakes.
}


//curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
Expand Down
10 changes: 9 additions & 1 deletion src/jsc/JavaScriptContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ if (mModuleSettings.enablePlayer)
gTopLevelContext = nullptr;
}
mPriv->releaseAllProtected();

//changed added

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

The comment "//changed added" is unclear and unnecessary. Comments should explain why code exists, not document when it was added (that's what version control is for).

Suggested change
//changed added

Copilot uses AI. Check for mistakes.
if (mNetworkMetricsData)
{
delete mNetworkMetricsData;
mNetworkMetricsData = nullptr;
}

JSGlobalContextRelease(mContext);
JSContextGroupRelease(mContextGroup);
rtLogInfo("%s end", __FUNCTION__);
Expand Down Expand Up @@ -394,7 +402,7 @@ if (mModuleSettings.enablePlayer)
gAAMPJSBindings = new AAMPJSBindings();
loadAAMPJSBindingsLib();
}
if (gAAMPJSBindings->fnLoadJS)
if (gAAMPJSBindings && gAAMPJSBindings->fnLoadJS)
{
gAAMPJSBindings->fnLoadJS(mContext);
}
Expand Down
2 changes: 1 addition & 1 deletion src/jsc/JavaScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ bool JavaScriptEngine::initialize()
if (garbageCollectInterval)
{
garbageCollectIntervalValue = atof(garbageCollectInterval);
NativeJSLogger::log(INFO, "garbage collection interval value: %d\n", garbageCollectIntervalValue);
NativeJSLogger::log(INFO, "garbage collection interval value: %f\n", garbageCollectIntervalValue);
}
mGarbageCollectionTag = installTimeout(garbageCollectIntervalValue, true,
[engine] () mutable {
Expand Down
24 changes: 21 additions & 3 deletions src/jsc/JavaScriptUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void dispatchPending()
{
std::unique_lock<std::mutex> lock(gDispatchMutex);
std::list<std::function<void ()>> pending = std::move(gPendingFun);
gDispatchMutex.unlock();
lock.unlock();
for(auto& fun : pending)
fun();
}
Expand Down Expand Up @@ -321,17 +321,32 @@ rtError rtReadBinaryBinding(int numArgs, const rtValue* args, rtValue* result, v
const char *fd = "hello.wasm";
struct stat buf;

stat(fd, &buf);
if (stat(fd, &buf) != 0)
{
rtLogError("Failed to stat file: %s", fd);
fclose(ptr);
return RT_ERROR;
}

int size = buf.st_size;

buffer = (char*)malloc(size);
fread(buffer,size,1,ptr); // read 10 bytes to our buffer
size_t bytesRead = fread(buffer, size, 1, ptr);
Comment on lines 333 to +334

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

If malloc fails on line 333, buffer will be NULL, but the code doesn't check this before calling fread on line 334. This will cause a segmentation fault if memory allocation fails.

Copilot uses AI. Check for mistakes.
fclose(ptr);

if (bytesRead != 1)
{
rtLogError("Failed to read file: expected 1 item, read %zu items", bytesRead);
free(buffer);
return RT_ERROR;
}

if (result)
{
result->setString(buffer);
}

free(buffer);
return RT_OK;
}

Expand Down Expand Up @@ -693,13 +708,15 @@ rtError rtJSRuntimeDownloadMetrics(int numArgs, const rtValue* args, rtValue* re
rtValue keys;
if (map->Get("allKeys", &keys) != RT_OK) {
rtLogWarn("Could not retrieve url for network metrics data.");
delete netMetricsArray; //newly added

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

The comment "//newly added" is unnecessary and should be removed. Comments should explain why code exists, not document when it was added (that's what version control is for).

Copilot uses AI. Check for mistakes.
return RT_FAIL;
}
rtObjectRef objRef = keys.toObject();
rtArrayObject* keysArray = static_cast<rtArrayObject*>(objRef.getPtr());

if (!keysArray) {
rtLogWarn("No url found in the network metrics data.");
delete netMetricsArray; //newly added

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

The comment "//newly added" is unnecessary and should be removed. Comments should explain why code exists, not document when it was added (that's what version control is for).

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

Expand All @@ -715,6 +732,7 @@ rtError rtJSRuntimeDownloadMetrics(int numArgs, const rtValue* args, rtValue* re
NetworkMetrics* metrics = (NetworkMetrics*)storedValue.toVoidPtr();
if (!metrics) {
rtLogError("Failed to cast stored value to NetworkMetrics structure for url: %s.", key.cString());
delete netMetricsArray; //newly added

Copilot AI Jan 16, 2026

Copy link

Choose a reason for hiding this comment

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

The comment "//newly added" is unnecessary and should be removed. Comments should explain why code exists, not document when it was added (that's what version control is for).

Suggested change
delete netMetricsArray; //newly added
delete netMetricsArray;

Copilot uses AI. Check for mistakes.
return RT_FAIL;
}
rtMapObject* metricsMap = new rtMapObject();
Expand Down
Loading
Loading