Compare boost::system::error_category - c++

The following comparison fails for an error whom outputs "asio.misc" for errorCode.category().name() and "end of file" for errorCode.message()
If it claims to be in category asio.misc, then why does the if condition of (errorCode.category() == boost::asio::error::misc_category ) evaluate to false?
Googling (including answers here) says that a boost::system::error_code can have the same value in more than one category, so I assume that in order to get the proper message and meaning we must compare boost::system::error_category as well as boost::system::error_code::value.
How do we properly compare the category if this fails to work?
Code in question:
//--------------------------------------------------------------------------------------------------
std::string ClientSocketASIO::ErrorCodeToString(const boost::system::error_code & errorCode)
{
std::ostringstream debugMsg;
debugMsg << " Error Category: " << errorCode.category().name() << ". "
<< " Error Message: " << errorCode.message() << ". ";
if( errorCode.category() == boost::asio::error::misc_category )
{
switch (errorCode.value())
{
case boost::asio::error::eof:
debugMsg << ". Server has disconnected.";
break;
case boost::asio::error::connection_refused:
debugMsg << ". Connection Refused";
break;
default:
debugMsg << ". Unknown Error.";
break;
}
}
else
{
debugMsg << ". Unknown Error category.";
}
return debugMsg.str();
}
EDIT:
According to https://theboostcpplibraries.com/boost.system and Boost::file_system: Checking error codes
People commonly and mistakenly write code only comparing the error value and not the category. The error value alone is not unique and may occur in more than one category. Users are also free to create their own error codes and categories. Therefore, both must be compared. This, I assume, doesn't effect a large number of applications, because they are only using one feature or library of boost their project anyway and/or the majority of error codes are mapped to windows error codes which made a best effort to not collide.
I had to get on another computer to hit up the boost mailing list, since my work blocks almost everything.
http://boost.2283326.n4.nabble.com/Compare-boost-system-error-category-td4692861.html#a4692869
According to a fella over there, the reason the comparison is failing is because the boost library is statically linked, and boost::system::error_category::operator == compares addresses, so the LHS is the address in one lib and the RHS is the address in another. They are not going to be equal when they are expected to be.
Using the address for operator == seems like a very silly move to me. I will continue to rant about it on the boost mailing list and edit here for others if any new knowledge is discovered.
For now, I am dynamically link and use form
//--------------------------------------------------------------------------------------------------
std::string ClientSocketASIO::ErrorCodeToString(const boost::system::error_code & errorCode)
{
std::ostringstream debugMsg;
debugMsg << " Error Category: " << errorCode.category().name() << ". "
<< " Error Message: " << errorCode.message() << ". ";
// IMPORTANT - These comparisons only work if you dynamically link boost libraries
// Because boost chose to implement boost::system::error_category::operator == by comparing addresses
// The addresses are different in one library and the other when statically linking.
//
// We use make_error_code macro to make the correct category as well as error code value.
// Error code value is not unique and can be duplicated in more than one category.
if (errorCode == make_error_code(boost::asio::error::connection_refused))
{
debugMsg << ". Connection Refused";
}
else if (errorCode == make_error_code(boost::asio::error::eof))
{
debugMsg << ". Server has disconnected.";
}
else
{
debugMsg << ". boost::system::error_code has not been mapped to a meaningful message.";
}
return debugMsg.str();
}
however, this does not work when I link statically to boost either. If anyone has any more suggestions on how we are to properly compare boost::system::error_code and get expected results, please let's get to the bottom of this.

The C++ 11 standard implies that each error category instance shall have
a globally unique address and comparisons of equality shall use that
address to compare. Unfortunately, this is not reliable in portable
code, only the Dinkumware STL implements true address uniqueness
anywhere in the process and it adds a full memory barrier to achieve
that i.e. it's expensive.
Boost's quality of implementation is the same as libstdc++ or libc++,
you can get multiple instantiations in certain circumstances and those
can have differing addresses.
In my own code, I do the comparison operator first, and if that fails I
do a strcmp() of the category's name(). To date, this has not bitten me.
I would personally consider this aspect of error categories to be a
defect in the standard, as specified it forces non-header-only
implementation if you want it to be conforming, and even that doesn't
cover RTLD_LOCAL which means you need to fall back onto named shared
memory or some hack.

Related

Function abi::__cxa_current_exception_type() returns non-ASCII characters

I'm running into an issue where running on a remote machine (but not locally) results in an unexpected exception of unknown type. I attempted to get more diagnostic information by wrapping things with a try {} catch {} with a range of possible exception types (including std::exception const &) but the exception still falls through to the catch(...) clause.
For lack of a better option, I attempted to get the type of the exception with (the GCC/Clang specific function) abi::__cxa_current_exception_type()->name() (within the catch(...) block), but this results in an output with non-ASCII characters. (Specifically, I'm getting 0��m- printed.) Attempting to pass it through abi::__cxa_demangle() before printing doesn't seem to help:
try {
// code which throws the exception
} catch (std::exception const & e) {
std::cout << "std::exception: " << e.what() << '\n';
} catch (...) {
int status = 0;
std::cout << "__cxa_current_exception_type() reports error type as: " << abi::__cxa_demangle( abi::__cxa_current_exception_type()->name(),0,0,&status) << '\n';
}
I'm a little surprised that the mangled name contains non-ASCII characters. (And to be explicit, we don't use non-ASCII identifiers in our code, and I'm not aware of any of our dependencies doing so.) I've also attempted to read through some name mangling resources to figure out what might be going on with the 0��m-, but I didn't find any likely reasons for the leading 0, or why there might be non-ASCII characters in the mangled name.
Do people have any ideas as to what might be going on here, and what sort of exception type is being thrown here? Or alternatively, are there approaches I may have missed to figure out the type?

how can i handle an invalid exception handler routine?

I'm building a program, that creates and deletes directories. I use the MSVC compiler (Visual Studio 2017), which is the reason i can't use "getcwd()" or "dirent.h" respectively.
I have tried several different ways to get the current working directory, but there was always a problem. I managed to print the cwd with "_wgetcwd()". However I couldn't find how I could convert it's output to use it in "_rmdir()" or "_wrmdir()" in my research.
My main goal is to be able to remove a directory without having to install some new compiler. If this condition is met, any help is appreciated, because I already tried to install a different Compiler, but I didn't got it to work. I also tried different ways to get the cwd and convert it into the desired datatype, but nothing worked with the scope of my IDE and my very basic knowledge.
I'm pretty much a beginner in programming and I'm learning with this book, that unfortunately uses "dirent.h". The following is a snippet of my current code, where I have eradicated all errors. However I still get this last annoying exception:
#include <iostream>
#include <stdlib.h>
#include<string>
#include <direct.h>
int main() {
int t = 0;
std::string str;
char xy = ' ';
char* _DstBuf = &xy;
const char* uniquename;
uniquename = _getdcwd(0, _DstBuf, _MAX_PATH);
std::cout << "Current path is ";
while (*uniquename != '\0') // this pointer points to the beginning of my path
{
std::cout << char(*uniquename); // prints one char of the path name for each iteration
char var = char(*uniquename);
str.push_back(var); //here the exception below is thrown.
// jump to the next block of memory
uniquename++;
}
std::cout << str <<'\n';
const char* lastchance = str.c_str();
if (_wchdir('..')) {
std::cout << "changing directory failed.\n";
}
if (_rmdir(lastchance) == -1 && errno == ENOTEMPTY) {
std::cout << "Given path is not a directory, the directory is not empty, or the directory is either the current working directory or the root directory.\n";
}
else if (_rmdir(lastchance) == -1 && errno == ENOENT)
{
std::cout << "Path is invalid.\n";
}
else if (_rmdir(lastchance) == -1 && errno == EACCES)
{
std::cout << "A program has an open handle to the directory.\n";
}
else if (_rmdir(lastchance)) {
std::cout << "removing directory still not possible\n";
}
}
This is the exception I get:
Unhandled exception at 0x6E656D69 in Experimentfile.exe: 0xC00001A5: An invalid exception handler routine has been detected (parameters: 0x00000003).
So if you are going to program in a C style (even though you have a C++ compiler) you're going to have to learn how arrays and pointers work. It's far too big a topic to learn from the internet you need a good book.
However I'll point out some of the errors
char xy = ' ';
char* _DstBuf = &xy;
const char* uniquename;
uniquename = _getdcwd(0, _DstBuf, _MAX_PATH);
This is just hopelessly wrong. It compiles but that doesn't mean it's going to work. This is what's required
char DstBuf[_MAX_PATH];
_getdcwd(0, DstBuf, _MAX_PATH);
_getdcwd requires an array which is passed as a pointer (see, you need to learn about arrays and pointers).
Then you attempt to print out the result and assign the result to a string. Again the code is way more complex than it needs to be. Here's the simpler version
std::string str = DstBuf;
std::cout << str <<'\n';
Then you attempt to change directories. I don't know why you are using the wide version _wchdir when you have narrow strings, use _chdir instead. And again the parameter is incorrect, '..' is a multi character literal, but _chdir requires a C-string. Here's the correct verison using _chdir.
if (_chdir("..")) {
std::cout << "changing directory failed.\n";
}
Then you try to remove a directory four times, obviously you can't remove a directory more than once.
And so on, and so on.
There are several problems with your code. I think your exception is caused by this line:
uniquename = _getdcwd(0, _DstBuf, _MAX_PATH);
Which is calling _getdcwd and passing it a pointer to a single character, while also specifying that the pointer can hold up to _MAX_PATH. This is completely undefined behaviour.
To fix this issue I think you should completely change what you are doing. Your code reads like C code, apart from the scattered C++ parts like std::string. Since C++17 the standard library has support for filesystem manipulation built in. Therefore you can rewrite your code using std::filesystem in a much more concise and safe way.
... // get path to delete and store it in del_path (del_path should be an std::filesystem::path object)
std::filesystem::remove_directories(del_path); // Recursive delete the directory specified by del_path
...
Note: std::filesystem::remove_directories will throw an std::filesystem::filesystem_error if it fails.
You can obtain the current directory using std::filesystem through std::filesystem::current_path.
I also recommend picking up a better book on C++ since this one does not seem to be teaching you good practices

Questions about DefineClass and my attempted usage of it

I'm trying to create a class/inject a class inside a java process through injecting a DLL into the process and using JNI to interface with java.
I came across a function called DefineClass but i can't quite get it work how i expected it to, so i have a few questions about the parameters the functions take:
In my case, what do i pass as class loader?
It accepts a byte array and its length as the "content" of the class, what would be the correct way of getting these bytes?
Which parts of the class is to be included in the array of bytes? Do i include everything or strip away parts?
Everything i have tried so far has resulted in the function returning null, so I'm not sure where to begin looking. If anyone would include some example usage or important notes about the usage that would be amazing!
jobject defined = jni->DefineClass("ChatFormatting", NULL, reach_buf, 4132);
if (defined == nullptr) {
std::cout << "Defined is NULL." << std::endl;
} else {
std::cout << "Success!" << std::endl;
}
You can get only class name and its' member entries addresses are incorrect.
Before inject, you must change addresses of entries by injectee module address.

How to not have any error when try to get a not existing node

Could somebody knows what kind of exception return the following code inside the "try" ?
I try to use the 3 kind of "catch (exception)" and no one seems to work.
try
{
std::cout << "try to get not existing path" << std::endl;
std::string path = this->m_Tree.get<std::string>(PATH);
}
catch (const boost::property_tree::ptree_bad_path& e)
{
std::cout << "ptree_bad_path" << std::endl;
}
Thank you for your help.
Look at the docs:
Three Ways of Getting Data
There are three versions of get: get, get (default-value version), and get_optional, which differ by failure handling strategy. All versions take path specifier, which determines in which key to search for a value. It can be a single key, or a path to key, where path elements are separated with a special character (a '.' if not specified differently). For example debug.logging.errorlevel might be a valid path with dot as a separator.
So, just use get_optional<std::string> I'd say
ptree pt;
/* ... */
boost::optional<float> v = pt.get_optional<float>("a.path.to.float.value");

streamed variables as a function parameter in C++

When you stream variables to an output stream such as cout, type conversion is automatic. What I'm trying to figure out is how to do this via a function call, for example:
inline void DEBUG(ostream& s) // Don't know if this prototype is appropriate
{
cout << s;
}
main()
{
int i = 5;
DEBUG("The value is: " << i << endl); // This doesn't compile
DEBUG("The value is: " + i + endl); // Neither does this
}
I found similar questions on here, but they all involve passing the stream object as a parameter, whereas I'm trying to pass the "streamed data" to a function that already has the stream object, so it's the other way round. Is this even possible? I don't want to resort to explicit type conversions. I also found this question, but I really don't want to write a whole logger class if I can avoid it.
At the moment I'm implementing it as a macro, which works, but I'd rather use an inline function if possible.
#define DEBUG(s) (cout << s)
Of course it does not compile. There are many reasons for that.
First, Operator << is not defined for standard streams, and you are trying to do exactly that: stream stream into stream in your DEBUG(). (Pun intended).
Second, operator << is not defined for string literals, and you are trying to invoke it here:
"The value is: " << i
+ is not defined for literals either, by the way.
To achieve the semantic you want to see, you will have to start with the stream. String literal need to be converted to stream first, and than you can apply << to it. This is ONLY way to achieve what you want.
Edit:
Now since I understand the rationale, I can give a better answer. There are many ways how people are trying to segregate different levels of debugging uniformely, and there are several libraries aiming for that (log4cpp, boost.log to name just few). Before you start implementing your own logging, I would definitely suggest looking into those. There is much more to the good logging than just debug levels.
If, for any reason, you want to use your own homebrew, here are the couple of recepies you might explore:
Use your own logger class (one of the very rare examples, close to
the single one! where Singleton is appropriate). You can than set the
logging level in the beggining of your application, and than just
call Logger::debug() << ...
Enrich above solution with macros. The problem with functions is that, unlike macros, they loose context. So if you want to log file and line number of the logging invocation (and you usually do!), you might want to do LOG_DEBUG << ...; here LOG_DEBUG would expand into something like Logger::debug() << __FILE__ << ":" << __LINE__ << ....
Once you've done this, you will see that sometimes you call other functions inside the << chain. At this point you might realize that those functions would be called regardless of your debug level, and might think you do not want to call them when debugging is not enabled (something along the lines LOG_DEBUG << " Object now is " << object.serialize(); So you will want to enrich the LOG_DEBUG macro to not execute anything when debug level does not match.
And the saga continues... Ready to use the library?
Well, what (at least some) logging libraries would do is create a temporary proxy object that would act as a stream:
#include <iostream>
struct LoggerProxy {
LoggerProxy(const char* file, int line)
{
std::cout << "File " << file << ", line " << line << ": ";
}
template<typename T>
LoggerProxy& operator<<(T&& t)
{
std::cout << t;
return *this;
}
};
#define LOG_DEBUG LoggerProxy{__FILE__, __LINE__}
int main()
{
LOG_DEBUG << "Value is: " << 4;
}
You can do a lot of fancy stuff with this, such as debug level checks, output to different streams or multiple backends (such as simultaneous output to std::cout/cerr and log file) and many more.