How to get the exit code of a Boost process? - c++

I wondering, how to get the exit code of my child process. The function exit_code() always return 0, doesn't matter terminated (send SIGKILL) or correctly finished.
I am using boost ver 1.65 and C++0x. I cant change these settings.
As I read in the documentation:
int exit_code() const;
Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated.
So this function is not helping me, but I may could use the error code.
std::error_code ec;
bp::system("g++ main.cpp", ec);
But std::error_code is only supported since c++11. I tried boost::system::error_code, but thats not correct.
Here the link to Boost::process:
https://www.boost.org/doc/libs/1_65_0/doc/html/boost_process/tutorial.html
Any idea, how to get that exit code?

You should be able to get the exit code simply by checking the return value:
int ec = bp::system("g++ main.cpp");
The overload taking an std::error_code is only for handling the edge case of g++ not existing in the first place (so it can never start the executable, and therefore there is no exit code). If you do not use that function, it will throw an exception on failure instead.1
try {
int ec = bp::system("g++ main.cpp");
// Do something with ec
} catch (bp::process_error& exception) {
// g++ doesn't exist at all
}
A cleaner way to do this would be to resolve g++ yourself first by searching the $PATH environment variable (just like your shell would):
auto binary_path = bp::search_path(`g++`);
if (binary_path.empty()) {
// g++ doesn't exist
} else {
int ec = bp::system(binary_path, "main.cpp");
}
1 Note, however, that C++0x is C++11, just before it was formally standardized, and that it is very likely your standard library will support std::error_code even if you tell it to use C++0x.

Related

can we clear errono after function call

I have some function call like below, and want to print success after success call, but got failure, even the function actually behave correctly.
int myfunction() {
// does some linux sys call for example
int error = run_cmd ("ifconfig usb10 up");
int syserrorno = errno;
strerror(syserrorno);
return error;
}
int main(){
int error =1;
int retry = 0;
do {
error = myfunction();
retry++;
}
while ( error !=-1 && retry <3);
return 0;
}
Basically I tried to:
Run a syscal via myFunction, return error = 1 if fail or 0 if success.
The return error in myFunction is the same as in syscal.
The syscal is a posix spawn command that I reuse from library.
If there is error, print error, redo 3 times.
So I have 1st run of syscall unsuccessfully; it returns error and print out "unavailabe resources". It is expected.
The second time is successful as I check the usb10 and it is up. But it still prints out the same error instead of success.
Is there a way to print it correctly ?
When using errno, always set errno=0; before calling the function(s) whose status you want to check. C library and POSIX functions will set errno to a non-zero value if they encounter an error, but they do not reset it to zero if they succeed.
(The reason they work this way: When a function reporting via errno is actually implemented in terms of other functions, you don't want a later success to make errno forget about an earlier failure. This also makes it possible for user code to set errno=0;, call a number of closely-related library functions, and just check for overall success or failure after all of those calls.)

error_code: how to set and check errno

I'm trying to understand what category I should use, when calling a C function that sets errno on Linux.
I'm not sure all the possible error codes are defined by POSIX, so I'm tempted to use the system_category.
But I like to handle generic condition in my code later on, so I would like to do things like that:
std::error_code ec;
some_func(some_path, ec);
if (ec) {
if (ec == std::errc::file_exists) {
// special handling
}
return ec;
}
To set the error code in some_func(), I expected to proceed like this:
ec.assign(EEXIST, std::system_category());
Mostly based on this discussion:
<system_error> categories and standard/system error codes
And the code sample provided by #niall-douglas:
std::error_code ec;
if(-1 == open(...))
ec = std::error_code(errno, std::system_category());
// To test using portable code
if(ec == std::errc::no_such_file_or_directory)
...
// To convert into nearest portable error condition (lossy, may fail)
std::error_condition ec2(ec.default_error_condition())
-- https://stackoverflow.com/a/40063005/951426
However, on Linux, with GCC 6.1.1, I have:
std::error_code(EEXIST, std::system_category()) == std::errc::file_exists returns false
std::error_code(EEXIST, std::generic_category()) == std::errc::file_exists returns true
I was expecting the errno + system_category to be comparable with std::errc conditions.
This means my initial code that checks if (ec == std::errc::file_exists) does not work if I don't use the generic category.
Is this the expected behavior?
This is a bug recently fixed in latest GCC 6, 7 and 8 point releases. It'll work as you expect if you're on the latest point release. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60555.

How to delegate an action to function return?

The problem
I have the following simple situation popping up all over the place. A large number of requests come to the device with a function signature like this:
Err execute( const ICommandContext &context,
const RoutineArguments &arguments,
RoutineResults &results)
There is essentially a request handling server that will call this execute the function for a variety of request types that have these signatures. We have 2 return paths in the case of an error.
The Err output type (consider it to be equivalent to an int) which is used to inform the server or system that something has gone wrong that is to do with the system, not the request. This is always sorted at the top of the function before the user request is dealt with.
RoutineResults provides a setStatus function that can be used to return failure information of the request to the client.
For this reason we have a lot of this type of code popping up:
// Failure due to request
Err error = someFunctionCall(clientInput);
if (!error.success()) {
results.setStatus(error); // Inform the client of the error
return SUCCESS; // Inform the system that we are all good
}
We have a particular request type that has around 15 parameters that come in and are sent off around the system. We would conceptually need 15 of this if error do set which seems wasteful. It is also prone to errors if we need to go through and change anything about how we return. How can we effectively delegate the setStatus and return to a short amount of code that only needs to happen once in the function?
A Macro Solution
A c system might solve this with a macro, something like:
#define M_InitTry Err error
#define M_Try(statement) if (!(error = statement).success()) { goto catch_lab; }
#define M_Catch catch_lab: if (!error.successs())
#define M_Return return error
Which would be used like this:
Err execute( const ICommandContext &context, ...) {
M_InitTry;
...
M_Try(someFunctionCall(clientInput));
M_Try(someFunctionCall(otherClientInput));
...
M_Catch {
// Other specific actions for dealing with the return.
results.setStatus(error);
error = SUCCESS;
}
M_Return;
}
This cleans the code nicely, but is not particularly nice with the goto. It will cause problems if defining variables that might be skipped by a goto.
A delegating solution
I was trying to think of a more C++ so I thought an RAII type delegate might help. Something like:
class DelegateToFunctionEnd {
typedef std::function<void(void)> EndFunction;
public:
DelegateToFunctionEnd(EndFunction endFunction) : callAtEnd(endFunction) { }
~DelegateToFunctionEnd() {
callAtEnd();
}
private:
EndFunction callAtEnd;
};
Pretty simple, it does a delegate of the action until the function return by implementing the action in the destructor. You might use it like this:
Err execute( const ICommandContext &context, ...) {
Err error;
DelegateToFunctionEnd del(std::bind(&RoutineResults::setStatus, &results, std::cref(error)));
error = someFunctionCall(clientInput));
if (error) return SUCCESS;
...
}
Live example.
This solution seems ok, but has several problems:
It is not as clear what is happening.
It is easier to make a mistake about setting error correctly.
You still need a large number of if statements to deal with the returns.
The ability to configure the terminating action is not great.
Dangerous if the user doesn't carefully consider the destruction order of items at function return.
A better solution?
This must be a problem that comes up often. Is there a general solution that provides a clean delegation of this set and returns type action?
I have some unfortunate restrictions below. Don't let these stop you from answering because it might be helpful for future people.
I am working on a c++03 limited system. We have boost, but no c++11.
Embedded system and we have silly rules about exceptions and memory allocation.
If error status codes are proving troublesome, you should consider using exceptions instead. That is, change the API of your functions
so they are guaranteed to have success as a post-condition
throw a suitable std::exception in the event of failure
It is impossible to "forget" to examine a status code if you do this. If you choose not to handle an error condition, the exception thrown by low-level code automatically percolates upwards. You only need to catch a low-level exception if
You need to do some manual roll-back or deallocation in the event of an error,
and RAII is impractical. In this case you would rethrow the expcetion.
You want to translate a low-level exception message or exception type into a high-level message, using a thrown) nested exception.
Maybe, you can write your statement as array, something like:
Err execute( const ICommandContext &context, ...)
{
const boost::function<Err()> functions[] = {
boost::bind(&someFunctionCall, std::ref(clientInput)),
boost::bind(&someFunctionCall, std::ref(otherClientInput)),
// ...
};
for (std::size_t i = 0; i != sizeof(functions) / sizeof(functions[0]); ++i) {
Err err = functions[i]();
if (!err.successs()) {
results.setStatus(err);
return SUCCESS;
}
}
return SUCCESS;
}
and if you do that several time with only different statements,
you might create
Err execute_functions(const ICommandContext &context, std::function<Err()> functions);
Maybe also provide other entry points as OnError depending of your needs.
Split the function.
The inner function returns an error code based on user input; the outer translates that to a client error, and only returns server side errors.
Inner function contains:
if(Err error = someFunctionCall(clientInput))
return error;
repeatedly. Outer has the relay to client error code, but only once.
Err just needs an operator bool. If it cannot have it, create a type that converts to/from Err and has an operator bool.
Can you add a method to error that does the check etc and return a bool.
if(!someFunctionCall(clientInput).handleSuccess(results))
{
return SUCCESS;
}

Properly terminating program. Using exceptions

Question:
Is using exceptions the proper way to terminate my program if all I want is to display an error message and close (accounting that I may be deep in the program)? Or can I just explicitly call something like exit(EXIT_FAILURE) instead?
What I'm Currently Doing:
I'm working on a game project and am trying to figure out the best way to terminate the program in the case of an error that calls for such an action. For example, in the case the textures can't be loaded I display an error message and terminate the program.
I'm currently doing this with exceptions like so:
int main()
{
Game game;
try
{
game.run();
}
catch (BadResolutionException & e)
{
Notification::showErrorMessage(e.what(), "ERROR: Resolution");
return 1;
}
catch (BadAssetException & e)
{
Notification::showErrorMessage(e.what(), "ERROR: Assets");
return 1;
}
catch (std::bad_alloc & e)
{
Notification::showErrorMessage(e.what(), "ERROR: Memory");
return 1;
}
return 0;
}
All but bad_alloc are my own defined exceptions derived from runtime_error.
I don't need any manual resource cleanup and I'm using std::unique_ptr for any dynamic allocation. I just need to display the error message and close the program.
Research/Alternatives to Exceptions:
I've looked up a lot of posts on SO and other places and have seen others say anything from don't use exceptions, to use exceptions but your using them wrong. I've also looked up explicitly calling something like exit().
Using exit() sounds nice but I read it won't go back through the call stack up to main cleaning everything up (if I can find this again I'll post the link). Additionally, according to http://www.cplusplus.com/reference/cstdlib/exit/ this should not be used if multiple threads are active. I do expect to be creating a second thread for a short time at least once, and an error could occur in that thread.
Not using exceptions was mentioned in some replies here in relation to games https://gamedev.stackexchange.com/questions/103285/how-industy-games-handle-their-code-errors-and-exceptions
Use exceptions was discussed here: http://www.quora.com/Why-do-some-people-recommend-not-using-exception-handling-in-C++
There are a number of other sources I've read but those were the most recent I looked at.
Personal Conclusion:
Due to my limited experience of working with error handling and using exceptions, I'm not sure if I'm on the right track. I've chosen the route of using exceptions based on the code I posted above. If you agree that I should tackle those cases with exceptions, am I using it correctly?
It's generally considered good practice to let all exceptions propagate through to main. This is primarily because you can be sure the stack is properly unwound and all destructors are called (see this answer). I also think it's more organised to do things this way; you always known where your program will terminate (unless the program crashes). It's also facilitates more consistent error reporting (a point often neglected in exception handling; if you can't handle the exception, you should make sure your user knows exactly why). If you always start with this basic layout
int main(int argc, const char **argv)
{
try {
// do stuff
return EXIT_SUCCESS;
} catch (...) {
std::cerr << "Error: unknown exception" << std::endl;
return EXIT_FAILURE;
}
}
then you won't go far wrong. You can (and should) add specific catch statements for better error reporting.
Exceptions when multithreading
There are two basic ways of executing code asynchronously in C++11 using standard library features: std::async and std::thread.
First the simple one. std::async will return a std::future which will capture and store any uncaught exceptions thrown in the given function. Calling std::future::get on the future will cause any exceptions to propagate into the calling thread.
auto fut = std::async(std::launch::async, [] () { throw std::runtime_error {"oh dear"}; });
fut.get(); // fine, throws exception
On the other hand, if an exception in a std::thread object is uncaught then std::terminate will be called:
try {
std::thread t {[] () { throw std::runtime_error {"oh dear"};}};
t.join();
} catch(...) {
// only get here if std::thread constructor throws
}
One solution to this could be to pass a std::exception_ptr into the std::thread object which it can pass the exception to:
void foo(std::exception_ptr& eptr)
{
try {
throw std::runtime_error {"oh dear"};
} catch (...) {
eptr = std::current_exception();
}
}
void bar()
{
std::exception_ptr eptr {};
std::thread t {foo, std::ref(eptr)};
try {
// do stuff
} catch(...) {
t.join(); // t may also have thrown
throw;
}
t.join();
if (eptr) {
std::rethrow_exception(eptr);
}
}
Although a better way is to use std::package_task:
void foo()
{
throw std::runtime_error {"oh dear"};
}
void bar()
{
std::packaged_task<void()> task {foo};
auto fut = task.get_future();
std::thread t {std::move(task)};
t.join();
auto result = fut.get(); // throws here
}
But unless you have good reason to use std::thread, prefer std::async.
There's nothing wrong with catching unrecoverable errors and shutting down your program this way. In fact, it's how exceptions should be used. However, be careful not to cross the line of using exceptions to control the flow of your program in ordinary circumstances. They should always represent an error which cannot be gracefully handled at the level the error occurred.
Calling exit() would not unwind the stack from wherever you called it. If you want to exit cleanly, what you're already doing is ideal.
You have already accepted an answer, but I wanted to add something about this:
Can I just explicitly call something like exit() instead?
You can call exit, but (probably) shouldn't.
std::exit should be reserved for situations where you want to express "exit right now!", not simply "application has nothing left to do".
As an example, if you were to write a controller for a laser used in cancer treatments, your first priority in case something went wrong would be to shut down the laser and call std::exit - or possibly std::terminate (to ensure any side effects of a hanging, slow or crashing application do not kill a patient).
Similar to how exceptions should not be used for controlling application flow, exit should not be used to stop the application in normal conditions.
Is using exceptions the proper way to terminate my program if all I want is to display an error message and close (accounting that I may be deep in the program)?
Yes. This is the reason for using exceptions. An error occurred deep down in the code and something at a higher level will handle it. In your case, at the highest level.
There are arguments for/against exceptions vs. error codes, and this is a good read:
Exceptions or error codes
Can I just explicitly call something like exit() instead?
You can, but you may end up duplicating your logging code. Also, if in the future you decide that you want to handle an exception differently you will have to change all your exit calls. Imagine you wanted a different message, or to fall back on an alternative process.
Another similar question:
Correct usage of exit() in c++?
You also have a flaw in your approach as you don't handle all (C++) exceptions. You want something like this:
int main()
{
Game game;
try
{
game.run();
}
catch (BadResolutionException & e)
{
Notification::showErrorMessage(e.what(), "ERROR: Resolution");
return 1;
}
catch (BadAssetException & e)
{
Notification::showErrorMessage(e.what(), "ERROR: Assets");
return 1;
}
catch (std::bad_alloc & e)
{
Notification::showErrorMessage(e.what(), "ERROR: Memory");
return 1;
}
catch (...)
{
// overload?
Notification::showErrorMessage("ERROR: Unhandled");
return 1;
}
return 0;
}
If you don't handle all* exceptions you could have the game terminate without telling you anything useful.
You can't handle ALL exceptions. See this link:
C++ catching all exceptions
From the documentation:
[[noreturn]] void exit (int status);
Terminate calling process
Terminates the process normally, performing the regular cleanup for terminating programs.
Normal program termination performs the following (in the same order):
Objects associated with the current thread with thread storage duration are destroyed (C++11 only).
Objects with static storage duration are destroyed (C++) and functions registered with atexit are called.
All C streams (open with functions in ) are closed (and flushed, if buffered), and all files created with tmpfile are removed.
Control is returned to the host environment.
Note that objects with automatic storage are not destroyed by calling exit (C++).
If status is zero or EXIT_SUCCESS, a successful termination status is returned to the host environment.
If status is EXIT_FAILURE, an unsuccessful termination status is returned to the host environment.
Otherwise, the status returned depends on the system and library implementation.
For a similar function that does not perform the cleanup described above, see quick_exit.

Is it evil to redefine assert?

Is it evil to redefine the assert macro?
Some folks recommend using your own macro ASSERT(cond) rather than redefining the existing, standard, assert(cond) macro. But this does not help if you have a lot of legacy code using assert(), that you don't want to make source code changes to, that you want to intercept, regularize, the assertion reporting of.
I have done
#undef assert
#define assert(cond) ... my own assert code ...
in situations such as the above - code already using assert, that I wanted to extend the assert-failing behavior of - when I wanted to do stuff like
1) printing extra error information to make the assertions more useful
2) automatically invoking a debugger or stack track on an assert
... this, 2), can be done without redefining assert, by implementing a SIGABRT signal handler.
3) converting assertion failures into throws.
... this, 3), cannot be done by a signal handler - since you can't throw a C++ exception from a signal handler. (At least not reliably.)
Why might I want to make assert throw? Stacked error handling.
I do this latter usually not because I want the program to continue running after the assertion (although see below), but because I like using exceptions to provide better context on errors. I often do:
int main() {
try { some_code(); }
catch(...) {
std::string err = "exception caught in command foo";
std::cerr << err;
exit(1);;
}
}
void some_code() {
try { some_other_code(); }
catch(...) {
std::string err = "exception caught when trying to set up directories";
std::cerr << err;
throw "unhandled exception, throwing to add more context";
}
}
void some_other_code() {
try { some_other2_code(); }
catch(...) {
std::string err = "exception caught when trying to open log file " + logfilename;
std::cerr << err;
throw "unhandled exception, throwing to add more context";
}
}
etc.
I.e. the exception handlers add a bit more error context, and then rethrow.
Sometimes I have the exception handlers print, e.g. to stderr.
Sometimes I have the exception handlers push onto a stack of error messages.
(Obviously that won't work when the problem is running out of memory.)
** These assert exceptions still exit ... **
Somebody who commented on this post, #IanGoldby, said "The idea of an assert that doesn't exit doesn't make any sense to me."
Lest I was not clear: I usually have such exceptions exit. But eventually, perhaps not immediately.
E.g. instead of
#include <iostream>
#include <assert.h>
#define OS_CYGWIN 1
void baz(int n)
{
#if OS_CYGWIN
assert( n == 1 && "I don't know how to do baz(1) on Cygwin). Should not call baz(1) on Cygwin." );
#else
std::cout << "I know how to do baz(n) most places, and baz(n), n!=1 on Cygwin, but not baz(1) on Cygwin.\n";
#endif
}
void bar(int n)
{
baz(n);
}
void foo(int n)
{
bar(n);
}
int main(int argc, char** argv)
{
foo( argv[0] == std::string("1") );
}
producing only
% ./assert-exceptions
assertion "n == 1 && "I don't know how to do baz(1) on Cygwin). Should not call baz(1) on Cygwin."" failed: file "assert-exceptions.cpp", line 9, function: void baz(int)
/bin/sh: line 1: 22180 Aborted (core dumped) ./assert-exceptions/
%
you might do
#include <iostream>
//#include <assert.h>
#define assert_error_report_helper(cond) "assertion failed: " #cond
#define assert(cond) {if(!(cond)) { std::cerr << assert_error_report_helper(cond) "\n"; throw assert_error_report_helper(cond); } }
//^ TBD: yes, I know assert needs more stuff to match the definition: void, etc.
#define OS_CYGWIN 1
void baz(int n)
{
#if OS_CYGWIN
assert( n == 1 && "I don't know how to do baz(1) on Cygwin). Should not call baz(1) on Cygwin." );
#else
std::cout << "I know how to do baz(n) most places, and baz(n), n!=1 on Cygwin, but not baz(1) on Cygwin.\n";
#endif
}
void bar(int n)
{
try {
baz(n);
}
catch(...) {
std::cerr << "trying to accomplish bar by baz\n";
throw "bar";
}
}
void foo(int n)
{
bar(n);
}
int secondary_main(int argc, char** argv)
{
foo( argv[0] == std::string("1") );
}
int main(int argc, char** argv)
{
try {
return secondary_main(argc,argv);
}
catch(...) {
std::cerr << "main exiting because of unknown exception ...\n";
}
}
and get the slightly more meaningful error messages
assertion failed: n == 1 && "I don't know how to do baz(1) on Cygwin). Should not call baz(1) on Cygwin."
trying to accomplish bar by baz
main exiting because of unknown exception ...
I should not have to explain why these context sensitive error messages can be more meaningful.
E.g. the user may not have the slightest idea why baz(1) is being called.
It may well ne a pogram error - on cygwin, you may have to call cygwin_alternative_to_baz(1).
But the user may understand what "bar" is.
Yes: this is not guaranteed to work. But, for that matter, asserts are not guaranteed to work, if they do anything more complicated than calling in the abort handler.
write(2,"error baz(1) has occurred",64);
and even that is not guaranteed to work (there's a secure bug in this invocation.)
E.g. if malloc or sbrk has failed.
Why might I want to make assert throw? Testing
The other big reason that I have occasionally redefined assert has been to write unit tests for legacy code, code that uses assert to signal errors, which I am not allowed to rewrite.
If this code is library code, then it is convenient to wrap calls via try/catch. See if the error is detected, and go on.
Oh, heck, I might as well admit it: sometimes I wrote this legacy code. And I deliberately used assert() to signal errors. Because I could not rely on the user doing try/catch/throw - in fact, oftentimes the same code must be used in a C/C++ environment. I did not want to use my own ASSERT macro - because, believe it or not, ASSERT often conflicts. I find code that is littered with FOOBAR_ASSERT() and A_SPECIAL_ASSERT() ugly. No... simply using assert() by itself is elegant, works basically. And can be extended.... if it is okay to override assert().
Anyway, whether the code that uses assert() is mine or from someone else: sometimes you want code to fail, by calling SIGABRT or exit(1) - and sometimes you want it to throw.
I know how to test code that fails by exit(a) or SIGABRT - something like
for all tests do
fork
... run test in child
wait
check exit status
but this code is slow. Not always portable. And often runs several thousand times slower
for all tests do
try {
... run test in child
} catch (... ) {
...
}
This is a riskier than just stacking error message context since you may continue operating. But you can always choose types of exceptions to cactch.
Meta-Observation
I am with Andrei Alexandresciu in thinking that exceptions are the best known method to report errors in code that wants to be secure. (Because the programmer cannot forget to check an error return code.)
If this is right ... if there is a phase change in error reporting, from exit(1)/signals/ to exceptions ... one still has the question of how to live with the legacy code.
And, overall - there are several error reporting schemes. If different libraries use different schemes, how make them live together.
Redefining a Standard macro is an ugly idea, and you can be sure the behaviour's technically undefined, but in the end macros are just source code substitutions and it's hard to see how it could cause problems, as long as the assertion causes your program to exit.
That said, your intended substitution may not be reliably used if any code in the translation unit after your definition itself redefines assert, which suggests a need for a specific order of includes etc. - damned fragile.
If your assert substitutes code that doesn't exit, you open up new problems. There are pathological edge cases where your ideas about throwing instead could fail, such as:
int f(int n)
{
try
{
assert(n != 0);
call_some_library_that_might_throw(n);
}
catch (...)
{
// ignore errors...
}
return 12 / n;
}
Above, a value of 0 for n starts crashing the application instead of stopping it with a sane error message: any explanation in the thrown message won't be seen.
I am with Andrei Alexandresciu in thinking that exceptions are the best known method to report errors in code that wants to be secure. (Because the programmer cannot forget to check an error return code.)
I don't recall Andrei saying quite that - do you have a quote? He's certainly thought very carefully about how to create objects that encourage reliable exception handling, but I've never heard/seen him suggest that a stop-the-program assert is inappropriate in certain cases. Assertions are a normal way of enforcing invariants - there's definitely a line to be drawn concerning which potential assertions can be continued from and which can't, but on one side of that line assertions continue to be useful.
The choice between returning an error value and using exceptions is the traditional ground for the kind of argument/preference you mention, as they're more legitimately alternatives.
If this is right ... if there is a phase change in error reporting, from exit(1)/signals/ to exceptions ... one still has the question of how to live with the legacy code.
As above, you shouldn't try to migrate all existing exit() / assert etc. to exceptions. In many cases, there will be no way to meaningfully continue processing, and throwing an exception just creates doubt about whether the issue will be recorded properly and lead to the intended termination.
And, overall - there are several error reporting schemes. If different libraries use different schemes, how make them live together.
Where that becomes a real issue, you'd generally select one approach and wrap the non-conforming libraries with a layer that provides the error handling you like.
I wrote an application that runs on an embedded system. In the early days I sprinkled asserts through the code liberally, ostensibly to document conditions in the code that should be impossible (but in a few places as lazy error-checking).
It turned out that the asserts were occasionally being hit, but no one ever got to see the message output to the console containing the file and line number, because the console serial port generally was not connected to anything. I later redefined the assert macro so that instead of outputting a message to the console it would send a message over the network to the error logger.
Whether or not you think redefining assert is 'evil', this works well for us.
If you include any headers/libraries that utilize assert, then you would experience unexpected behavior, otherwise the compiler allows you to do it so you can do it.
My suggestion, which is based on personal opinion is that in any case you can define your own assert without the need to redefine the existing one. You are never gaining extra benefit from redefining the existing one over defining a new one with a new name.