V8 Cannot set ObjectTemplate with name "console" - c++

I try to set a global object named console, but that specific name causes a crash and to me it seems like it's telling me that the object already exists. I can though set it to anything else. Why can I not set the object to name "console"?
V8 Version is 6.5.254.6
Error
# Fatal error in ../../src/objects.cc, line 6007
# Debug check failed: !it.IsFound().
Code Snippet
isolate->Enter();
v8::HandleScope handle_scope(isolate);
// Create globals
auto globalObj = v8::ObjectTemplate::New(isolate);
// Create console object
auto consoleObj = v8::ObjectTemplate::New(isolate);
// Log
auto logcb = [](V8CallbackArgs args) {
auto& log = Log::Instance();
for (size_t i = 1; i < args.Length(); i++)
log << *v8::String::Utf8Value(args[i]);
log << std::endl;
};
consoleObj->Set(v8::String::NewFromUtf8(isolate, "log"), v8::FunctionTemplate::New(isolate, logcb));
// Set global object
globalObj->Set(v8::String::NewFromUtf8(isolate, "console"), consoleObj); // nonono cannot have it console, con is ok though
// Create script context
context = v8::Persistent<v8::Context, v8::CopyablePersistentTraits<v8::Context>>(isolate, v8::Context::New(isolate, nullptr, globalObj));
{
v8::Context::Scope context_scope(context.Get(isolate));
v8::TryCatch tc(isolate);
auto source = v8::String::NewFromUtf8(src.c_str());
auto script = v8::Script::Compile(source);
if (script->Run().IsEmpty() && CV8ScriptRuntime::isDebug) {
v8loge "Error loading script \"" << filepath << "\n" << std::endl
<< "Exception: " << *v8::String::Utf8Value(tc.Exception()) << std::endl
<< "Stack trace: " << *v8::String::Utf8Value(tc.StackTrace()) << std::endl << Log::White;
}
}

Your observation is correct. When V8 initializes a Context, it installs a global console object into it, and assumes (guarded by a check) that a property with that name does not exist yet. When you provide your own "console", that check fails.
If you want to overwrite V8's built-in console, you'll have to create the Context first (via v8::Context::New), then delete (or overwrite) the console property on its global object.
If all you wanted was to have a console object in your embedder just like the one you know from browsers, then I'm happy to inform you that this work has already been done and you can simply use it :-)

Related

How do I unload/destroy a lua script?

I'm trying to make a very simple lua wrapper that can be used to load & run multiple Lua scripts. I'm concerned because I don't see any documentation on how to properly destroy/delete loaded scripts without completely destroying the lua_State itself.
Is it possible to delete/unload loaded lua scripts? Is this unnecessary or will continuously calling luaL_dofile lead to a memory leak?
Simplified question.... If I call luaL_dofile on the same lua_State object, will this lead to a memory leak or issues or does lua handle this in the back end as it loads a new script?
Here's a demo...
lua_State* m_lua_state = luaL_newstate();
lua_gc(m_lua_state, LUA_GCSTOP, 0);
luaL_openlibs(m_lua_state);
lua_gc(m_lua_state, LUA_GCRESTART, 0);
for(int i = 0; i < 99999999; i++)
{
// Since I don't unload the previous file, does this cause a memory leak until lua_close is called?
if (luaL_dofile(m_lua_state, file_path.c_str()) != LUA_OK)
{
std::string error_msg = lua_tostring(m_lua_state, -1);
std::cout << "Error: " << error_msg << std::endl;
return false;
}
else
{
lua_getglobal(m_lua_state, function_name.c_str());
if (lua_isfunction(m_lua_state, -1))
{
int stack_size = lua_gettop(m_lua_state);
int number_of_args = 0;
if (lua_pcall(m_lua_state, number_of_args, 0, 0) != LUA_OK)
{
std::cout << "Error Calling Function In Script: " << file_path << "::" << function_name << " - " << lua_tostring(m_lua_state, -1) << std::endl;
}
int total_return_values = lua_gettop(m_lua_state) - stack_size;
}
else
{
std::cout << "Error Invalid Function In Script: " << file_path << "::" << function_name << std::endl;
}
}
}
lua_close(m_lua_state);
If by unload you mean undo the effects of running some Lua code, then it cannot be done unless you save the state of what is precious before running the code. This can be done by sandboxing the code.
If you just want to remove a Lua table, set to nil all references to it and let the table be garbage collected automatically or manually.
When you load a lua file you are really executing it's code. It's not like a dll or something in other languages:
int luaL_dofile (lua_State *L, const char *filename);
Loads and runs the given file. It is defined as the following macro:
If your file is something like this:
function sayHello()
print('Hello, world!')
end
Then loading the file will create a function 'sayHello' on the global object. If you load the file again it will replace the existing function with the new one and there should be no memory leak. Anyone calling 'sayHello' will call the new function on the global object, unless they saved a reference to the original function. Code commonly does this because it is slightly faster to call a local variable instead of a global function. If another file has local sayhi = sayHello at the top for instance then any calls to 'sayhi' will call the original function.
If you are creating classes and expect the data to remain, any objects (lua tables) created before the reload will still reference the metatables for the old classes. The code for your new classes will not automatically apply to classes created before the reload.
Take an example in the LUA docs:
Account = {}
function Account:deposit (v)
self.balance = self.balance + v
end
function Account:new (o)
o = o or {} -- create object if user does not provide one
setmetatable(o, self)
self.__index = self
return o
end
a = Account:new{balance = 0}
a:deposit(100.00)
a is now a table with a 'balance' property of 100.00 and a metatable pointing to the Account table which has a deposit function. If you make a change to the deposit function to print the balance and reload the file, it will replace the global 'Account' table and functions, but the table 'a' will still have the original Account table as it's metatable. So calling 'a.deposit' will still not print the value.

findAndGetString() in DCMTK returns null for the tag

I am developing a quick DICOM viewer using DCMTK library and I am following the example provided in this link.
The buffer from the API always returns null for any tag ID, eg: DCM_PatientName.
But the findAndGetOFString() API works fine but returns only the first character of the tag in ASCII, is this how this API should work?
Can someone let me know why the buffer is empty the former API?
Also the DicomImage API also the same issue.
Snippet 1:
DcmFileFormat fileformat;
OFCondition status = fileformat.loadFile(test_data_file_path.toStdString().c_str());
if (status.good())
{
OFString patientName;
char* name;
if (fileformat.getDataset()->findAndGetOFString(DCM_PatientName, patientName).good())
{
name = new char[patientName.length()];
strcpy(name, patientName.c_str());
}
else
{
qDebug() << "Error: cannot access Patient's Name!";
}
}
else
{
qDebug() << "Error: cannot read DICOM file (" << status.text() << ")";
}
In the above snippet name has the ASCII value "50" and the actual name is "PATIENT".
Snippet 2:
DcmFileFormat file_format;
OFCondition status = file_format.loadFile(test_data_file_path.toStdString().c_str());
std::shared_ptr<DcmDataset> dataset(file_format.getDataset());
qDebug() << "\nInformation extracted from DICOM file: \n";
const char* buffer = nullptr;
DcmTagKey key = DCM_PatientName;
dataset->findAndGetString(key,buffer);
std::string tag_value = buffer;
qDebug() << "Patient name: " << tag_value.c_str();
In the above snippet, the buffer is null. It doesn't read the name.
NOTE:
This is only a sample. I am just playing around the APIs for learning
purpose.
The following sample method reads the patient name from a DcmDataset object:
std::string getPatientName(DcmDataset& dataset)
{
// Get the tag's value in ofstring
OFString ofstring;
OFCondition condition = dataset.findAndGetOFString(DCM_PatientName, ofstring);
if(condition.good())
{
// Tag found. Put it in a std::string and return it
return std::string(ofstring.c_str());
}
// Tag not found
return ""; // or throw if you need the tag
}
I have tried your code with your datasets. I just replaced the output to QT console classes to std::cout. It works for me - i.e. it prints the correct patient name (e.g. "PATIENT2" for scan2.dcm). Everything seems correct, except for the fact that you apparently want to transfer the ownership for the dataset to a smart pointer.
To obtain the ownership for the DcmDataset from the DcmFileFormat, you must call getAndRemoveDataset() instead of getDataset(). However, I do not think that your issue is related that. You may want to try my modified snippet:
DcmFileFormat file_format;
OFCondition status = file_format.loadFile("d:\\temp\\StackOverflow\\scan2.dcm");
std::shared_ptr<DcmDataset> dataset(file_format.getAndRemoveDataset());
std::cout << "\nInformation extracted from DICOM file: \n";
const char* buffer = nullptr;
DcmTagKey key = DCM_PatientName;
dataset->findAndGetString(key, buffer);
std::string tag_value = buffer;
std::cout << "Patient name: " << tag_value.c_str();
It probably helps you to know that your code and the dcmtk methods you use are correct, but that does not solve your problem. Another thing I would recommend is to verify the result returned by file_format.loadFile(). Maybe there is a surprise in there.
Not sure if I can help you more, but my next step would be to verify your build environment, e.g. the options that you use for building dcmtk. Are you using CMake to build dcmtk?

Why Isn't find_one working in MongoDB C++?

I have a MongoDB 3.0.7 database, created with the mongo shell. The following works fine:
% mongo test
> vs = db.myCollection.findOne({"somefield.subfield": "somevalue"})
but when I do this in C++:
mongocxx::instance inst{};
mongocxx::client conn{};
auto db = conn["test"];
bsoncxx::stdx::optional< bsoncxx::document::value> docObj;
try {
docObj =
db["myCollection"]
.find_one(document{} <<
"somefield.subfield" << "someValue" <<
bsoncxx::builder::stream::finalize);
} catch (mongocxx::exception::operation e) {
std::cerr << "Retrieval failed (and exception thrown)";
}
if (docObj == bsoncxx::stdx::nullopt)
std::cerr << "Failed to find object";
I get "Failed to find object". What am I missing here?
Update: 11/23/2015, 10:00
I've installed the latest cxx driver (0.3.0), and made the following changes:
mongocxx::instance inst{};
mongocxx::client *connPtr;
bsoncxx::stdx::string_view connectionString("mongodb://localhost");
connPtr = new mongocxx::client(mongocxx::uri(connectionString));
auto db = connPtr->database("test");;
bsoncxx::stdx::optional< bsoncxx::document::value> docObj;
try {
docObj =
db["myCollection"]
.find_one(document{} <<
"somefield.subfield" << "someValue" <<
bsoncxx::builder::stream::finalize);
} catch (mongocxx::exception::operation e) {
std::cerr << "Retrieval failed (and exception thrown)";
}
if (docObj == bsoncxx::stdx::nullopt)
std::cerr << "Failed to find object";
I'm back to exactly the same thing. Calling db.list_collections(document{}) retrieves no results.
The bsoncxx library has two document types, views and values. A document::value contains the actual document data, and a document::view is just a reference to some underlying value. Values must outlive the views that use them.
There's a bug in the new c++11 driver with how document::values are passed around. This code produces a document::value :
document{} << "someField" << "someValue" << finalize;
The collection.find_one() method takes a document::view, and document::values convert implicitly to document::views. Unfortunately, this means if you dynamically build a document in your call to find_one(), as above, you can shoot yourself in the foot:
collection.find_one(document{} << "someField" << "someValue" << finalize);
finalize makes a temporary document::value, then find_one converts that to a document::view. The temporary value is dropped on the floor, leaving your view value-less, like a dangling pointer.
A workaround is to make your value in a separate call, and keep it around:
document::value doc = document{} << "someField" << "someValue" << finalize;
collection.find_one(doc.view());
I suspect this is what's causing your queries to fail; if not, it's something to make your code resilient to nonetheless!
You can track this ticket for the real fix for this problem.

Boost log select destination file

Is it possible with one instance of Boost log, to log into severeal files.
I mean is it possible to specify in which file the log will be written:
BOOST_LOG_..(...) << "aaa" <- go to **A.log**
BOOST_LOG_..(...) << "bbb" <- go to **B.log**
Yes, it's possible - using filters.
How you do it exactly depends on your preferences, but here's an example with scoped logger tags:
void SomeFunction()
{
{
// everything in this scope gets logged to A.log
BOOST_LOG_SCOPED_LOGGER_TAG(lg, "Log", std::string, "LogA")
BOOST_LOG(lg) << "aaa";
BOOST_LOG(lg) << "aaa2";
}
{
// everything in this scope gets logged to B.log
BOOST_LOG_SCOPED_LOGGER_TAG(lg, "Log", std::string, "LogB")
BOOST_LOG(lg) << "bbb";
BOOST_LOG(lg) << "bbb2";
}
}
// This is your log initialization routine
void InitLogs()
{
// Initialize sinkA to use a file backend that writes to A.log and sinkB to B.log.
// ...
// ...
// Make sink A only accept records with the Log attribute "LogA"
// while sink B will only accept records where it is "LogB".
sinkA.set_filter(flt::attr<std::string>("Log") == "LogA");
sinkB.set_filter(flt::attr<std::string>("Log") == "LogB");
}

NetworkManager and Qt Problem

I am still new to using Qt4/Dbus, and i am trying to get a list of acccess points with Qt API to send/receive Dbus messeges.
I got the following error:
org.freedesktop.DBus.Error.UnknownMethod
Method "GetAccessPoint" with signature "" on interface "org.freedesktop.NetworkManager.Device.Wireless" doesn't exist
The code is:
QStringList *netList = new QStringList();
QDBusConnection sysbus = QDBusConnection::systemBus();
QDBusInterface callNM("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager","org.freedesktop.NetworkManager.Device.Wireless",sysbus);
if(callNM.isValid())
{
QDBusMessage query= callNM.call("GetAccessPoints");
if(query.type() == QDBusMessage::ReplyMessage)
{
QDBusArgument arg = query.arguments().at(0).value<QDBusArgument>();
arg.beginArray();
while(!arg.atEnd())
{
QString element = qdbus_cast<QString>(arg);
netList->append(element);
}
arg.endArray();
}else{
std::cout<< query.errorName().toStdString() << std::endl;
std::cout<< query.errorMessage().toStdString() << std::endl;
}
int x= netList->size();
for(int y=0; y< x ;y++)
{
widget.avail_nets->addItem(netList->at(y)); // just print it to my gui from the stringlist array
}
}else{
std::cout<<"fail" << std::endl;
}
Whats wrong?My naming was correct and I am following the exact specs from here
The method name is GetAccessPoints.
While your error is:
org.freedesktop.DBus.Error.UnknownMethod
Method "GetAccessPoint" with signature
"" on interface
"org.freedesktop.NetworkManager.Device.Wireless"
doesn't exist
Highlight on "GetAccessPoint". Thus you might have misspelled the method name in the code, although the code you pasted here uses the correct method name, maybe you fixed it and forgot to rebuild or clean the project?
I had the same issue, but then I noticed that it only happened when I called the GetAccessPoints method on a wired device. Make sure the device is a wireless device (i.e. DeviceType equals NM_DEVICE_TYPE_WIFI), and everything should work fine.
i modify this and works for me
QDBusInterface callNM("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager/Devices/0","org.freedesktop.NetworkManager.Device.Wireless",sysbus);
and the result is
"/org/freedesktop/NetworkManager/AccessPoint/2"
"/org/freedesktop/NetworkManager/AccessPoint/1"
i think /org/freedesktop/NetworkManager is not correct path for specific device (wireless devices).
QDBusInterface dbus_iface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Devices/0", "org.freedesktop.NetworkManager.Device.Wireless", bus);
QDBusMessage query = dbus_iface.call("GetAccessPoints");
if(query.type() == QDBusMessage::ReplyMessage) {
QDBusArgument arg = query.arguments().at(0).value<QDBusArgument>();
arg.beginArray();
while(!arg.atEnd()) {
QString element = qdbus_cast<QString>(arg);
netList->append(element);
showAccessPointProperties(element);
}
arg.endArray();
} else {
qDebug() << "got dbus error: " << query.errorName();
qDebug() << "check the parameters like service, path, interface and method name !!!";
}
Hope this will help.