LLVM KaleidoscopeJIT: How to view errors? - c++

I've been following the LLVM tutorial and I'm now trying to tweak & try extending things but I keep running into an error where code won't JIT & the compiler (the one I've made with LLVM) will abort with:
piler: /usr/lib/llvm-9/include/llvm/Support/Error.h:626: llvm::Expected<T>::storage_type* llvm::Expected<T>::getStorage() [with T = long unsigned int; llvm::Expected<T>::storage_type = long unsigned int]: Assertion `!HasError && "Cannot get value when an error exists!"' failed.
The assert is raised just after trying to get the address of the JIT-ted function:
reinterpret_cast<double (*)()>(expr_symbol.getAddress().get());
I really need to see what the error is to attempt to fix it but I can't figure out how to get or view it.

Solved this.
.getAddress() returns an llvm::Expected which wraps around the address, it can contain an error or the address if found.
To handle/log the error you must 'take' the error and log it with llvm::logAllUnhandledErrors
auto address = expr_symbol.getAddress();
if (auto err = address.takeError()) {
llvm::logAllUnhandledErrors(std::move(err), llvm::errs(), "[JIT Error] ");
return -1;
}

Related

How LoadString() works in VC++?

I am working on an MFC application where when I write Something like this:CString sName; sName.LoadString(IDS_NAME_STRING) it works fine but when I try to write while initializing in one line like CString sName = sName.LoadString(IDS_NAME_STRING), I am getting error
Error C2440 'initializing': cannot convert from 'BOOL' to 'ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<_CharType>>>'
I am not getting what's wrong with the latter statement. Can anyone help me to understand this error?
CString::LoadString returns a value of type BOOL. That's what the error message is telling you. It turned out to be a bit longer as it includes the full template instantiations. It's ultimately saying
cannot convert from 'BOOL' to 'CString'
The solution is what you already have:
CString sName;
sName.LoadString(IDS_NAME_STRING);
If you'd rather have that as a single statement, you'll have to implement a function for it, e.g.
CString load_string(uint32_t id) {
CString s;
s.LoadString(id);
return s;
}
With that you can write
auto s = load_string(IDS_NAME_STRING);
Note that the function load_string mirrors the behavior of the initial code: If a string resource with any given ID cannot be found, it returns an empty string. If you'd rather have failure communicated to clients you could throw an exception.

How to determine if std::filesystem::remove_all failed?

I am trying to use the non-throwing version of std::filesystem::remove_all, I have something like:
bool foo()
{
std::error_code ec;
std::filesystem::remove_all(myfolder, ec);
if (ec.value())
{
// failed to remove, return
return false;
}
}
Is this the correct way to use error_code?
My reasoning:
I read this:
The overload taking a std::error_code& parameter sets it to the OS API
error code if an OS API call fails, and executes ec.clear()
Now here:
clear - sets the error_code to value 0 in system_category
Now I used this to imply error_code == 0 => No error. error_code != 0 => error.
I really can't any much examples of uses of error_code. I just want to determine if all the files have been removed or not.
There is a difference between ec.value() and ec != std::error_code{}; in the case where the error code in ec is a different error category than system error and has a value of 0, the first will return false, while the second will return true.
Error codes are a tuple of categories and value. Looking only at the value is a tiny bit of "code smell".
In this case, I don't think it is possible for the error code to have anything except the system category. And it would be bad form for a non-system error category to use the value 0 for an actual error.
If there was no error (value 0) with a non-system error code, treating it like an error is probably a bad idea. So maybe you shouldn't be checking the category.
Finally, if (ec.value()) is a verbose way of saying if (ec). I'd use the explicit operator bool() const instead of calling .value().
Another option is:
if (-1 == std::filesystem::remove_all(myfolder, ec)) {
// failed to remove, return
return false;
}

Why is RakNet's SetNetworkID causing an assert to fail?

So I have a factory for creating objects based on RakNet's NetworkIDObjects. If it's the authority then it will just create a new object, otherwise it will create the object then set the Net ID:
std::shared_ptr<CNetObject> CNetObjectFactory::Create(int netObjectType, bool IsAuthority, RakNet::NetworkID networkID) const
{
auto entry = m_RegisteredObjects.find(netObjectType);
auto clone = std::shared_ptr<CNetObject>(entry->second->Clone());
clone->SetNetworkIDManager(m_NetworkIDManager.get());
if (IsAuthority)
{
clone->SetAuthority();
}
else if (networkID != 0)
{
clone->SetNetworkID(networkID);
}
return clone;
}
This works fine for the first couple of NetObjects spawned on the client, but the third one always crashes inside SetNetworkID:
Assertion Failed! nio->GetNetworkID()!=rawId
With the following callstack:
MyApp.exe!RakNet::NetworkIDManager::TrackNetworkIDObject(class RakNet::NetworkIDObject *) Unknown
MyApp.exe!RakNet::NetworkIDObject::SetNetworkID(unsigned __int64) Unknown
MyApp.exe!CNetObjectFactory::Create(int netObjectType, bool IsAuthority, unsigned __int64 networkID) Line 42 C++
I can't find any information about this error anywhere else, nor can I figure out what is different about this particular object. The NetworkIDs seem no different to the previous objects (except it's increased by one). As far as I can tell there's nothing obvious that can be causing this crash.
So I figured out the problem - the error is thrown because I am trying to add an object with the same NetworkID as one that has already been added.
It stemmed from further up the call stack:
auto netObject = m_NetworkIDManager->GET_OBJECT_FROM_ID<CNetObject *>(networkId);
if (netObject == nullptr)
{
netObject = m_NetObjectFactory->Create(netObjectType, false, networkId).get();
}
I check to see if the object exists, then if it doesn't I go ahead and create it. The problem was that the NetworkIDManager referenced in this piece of code was a completely different instance, meaning the check would always fail and it would try to create a new object every time.

Segmentation fault when testing migrated library from qt4 to qt5

I am testing this library but I am getting a segmentation fault whenever it reachs a certain line (the commented one below). This issue comes from this question - tldr the same problem on a much bigger project, so I decided to test the libraries separatedly and apparently this is what fails. This code works on a co-worker's 32bits machine using Qt4 (he handed me the code). I migrated it to Qt5 and compiled with a 32bit compiler and I am getting the segmentation fault. If I comment the offending line and the two below it the program runs (although its just an empty window).
What could be happening?
#include "qenctest.h"
#include <QLibrary>
#include <QtWidgets/QMessageBox>
typedef void (*encRefresh)(QPainter*);
encRefresh enc_refresh = NULL;
typedef void (*encResize)(QSize);
encResize enc_resize = NULL;
typedef QENCSignaler* (*encInit)(QString);
typedef void (*encOpenFile)(QString);
QENCTest::QENCTest(QWidget *parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
QLibrary _qenc("qenc");
encInit enc_init;
encOpenFile enc_openFile;
enc_init = (encInit) _qenc.resolve("init"); // I checked and it does load the library and the symbol succesfully
enc_openFile = (encOpenFile) _qenc.resolve("openFile");
enc_resize = (encResize) _qenc.resolve("resize");
enc_refresh = (encRefresh) _qenc.resolve("refresh");
QString path = "encfg";
QENCSignaler* qencSignaler = enc_init(path); // Throws segfault here
connect(qencSignaler, SIGNAL(newChart(Chart*)), this, SLOT(qencNewChart(Chart*)));
connect(qencSignaler, SIGNAL(startReadChart(char*)), this, SLOT(qencStartReadChart(char*)));
enc_openFile("PL2BAPOL.000");
int _s = 0;
}
Debug info:
PS: What does it mean that some locals & expressions are in red?
EDIT
Alright, the only major changes I had to make in the library code were these:
AttributeSet::iterator vItPOI = attributes.at(i).find("POI");
if (vItPOI == attributes.at(i).end()) continue;
AttributeSet::iterator vItPOI0 = attributes.at(i).find("POI0");
if (vItPOI0 == attributes.at(i).end()) continue;
if (vItPOI -> getStringValue() == "Bankowoæ" &&
selectedPOI & POI_BANKING) {
if (vItPOI0 -> getStringValue() == "Placówka banku") {
drawSymbol(painter, x, y, POI_BANKING);
}
}
To this (there are more ifs but this illustrates it properly)
ShapeAttribute vItPOI = attributes.at(i).find("POI").value();
if (attributes.at(i).find("POI") == attributes.at(i).end()) continue;
ShapeAttribute vItPOI0 = attributes.at(i).find("POI0").value();
if (attributes.at(i).find("POI0") == attributes.at(i).end()) continue;
if (vItPOI . getStringValue() == "Bankowo��" &&
selectedPOI & POI_BANKING) {
if (vItPOI0 . getStringValue() == "Plac�wka banku") {
drawSymbol(painter, x, y, POI_BANKING);
}
}
In theory it should be the same shouldnt it? Although I do find strange that in the first snippet it uses -> instead of . when its not a pointer. I had to change it to that because I was getting these errors:
^
..\qenc\ShapeLandPOI.cpp: In member function 'virtual void ShapeLandPOI::draw(QPainter*)':
..\qenc\ShapeLandPOI.cpp:74:62: error: conversion from 'QMap<QString, ShapeAttribute>::const_iterator' to non-scalar type 'QMap<QString, ShapeAttribute>::iterator' requested
AttributeSet::iterator vItPOI = attributes.at(i).find("POI");
^
..\qenc\ShapeLandPOI.cpp:76:64: error: conversion from 'QMap<QString, ShapeAttribute>::const_iterator' to non-scalar type 'QMap<QString, ShapeAttribute>::iterator' requested
AttributeSet::iterator vItPOI0 = attributes.at(i).find("POI0");
^
In your changed code you have the line
ShapeAttribute vItPOI0 = attributes.at(i).find("POI0").value();
But if "POI0" is not found the find function would return end which is an iterator pointing to beyond the collection, and so it's value function would be causing undefined behavior.
As for the errors it seems that the QMap object is constant, and so you can't get non-const iterators. Just change to use AttributeSet::const_iterator instead and you can use the original function otherwise unmodified. This will probably fix your crashes, as then you don't have the risk of undefined behavior as described above.

Python exception text on syntax errors (boost library)

I've got this code snnipet (the whole program compiles and links correctly):
...
try
{
boost::python::exec_file(
"myscript.py", // this file contains a syntax error
my_main_namespace,
my_local_namespace
);
return true;
}
catch(const boost::python::error_already_set &)
{
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
// the next line crashes on syntax error
std::string error = boost::python::extract<std::string>(pvalue);
...
}
The file that the program tries to execute has a syntax error, so an exception is thrown. When the program tries to get the error message crashes...
The code works well with run-time errors but somehow crashes with syntax errors.
How can i get the error string with this kind of errors?
Thanks in advance
From the documentation of PyErr_Fetch: "The value and traceback object may be NULL even when the type object is not". You should check whether pvalue is NULL or not before trying to extract the value.
std::string error;
if(pvalue != NULL) {
error = boost::python::extract<std::string>(pvalue);
}
If you want to check whether the exception is a SyntaxError you can compare ptype against the exception types listed here.
To answer anymore specifically I would need a backtrace from the point where it crashed.
Edit
pvalue is an exception object, not a str instance so you should use PyObject_Str to get the string representation of the exception.
You may need to call PyErr_NormalizeException first to turn pvalue into the correct exception type.