Exception handling?

void GLAPIENTRY scene::debugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
std::string info = glDebugMessageCallbackInfo(source, type, id, severity, length, message, userParam);
sprintf((char*)userParam, “%s”, info.c_str());
throw std::exception(info.c_str());
}

void scene::Draw()
{
GLchar lastErrorMessageBuffer[MAX_ERROR_MESSAGE_BUFFER];
glDebugMessageCallback(this->debugMessageCallback, &lastErrorMessageBuffer[0]);
int iNumObjects = objects.size();
for (int i = 0; i < iNumObjects; i++)
{
try
{
objects[i]->Draw();
}
catch (…)
{
ReportError(lastErrorMessageBuffer);
}
}
}

So enthrall me, i would like to know which part of the above code is not “portable”, is it the glDebugMessageCallback? is it the try catch block? (which is about as portable as it gets!), or is it the throw std::exception?

no chocolate analogies, just answer why it is not portable then?

Thanks.

I am not throwing “through a C function”?? i am throwing from a C++ method. and the method is declared static inside the class that is using the try catch result. i do not see any violation in this? the compiler works with it. where is the OpenGL specification that states i cannot do this? I think you will find your wrong.

I don’t know how your code has defined GLAPIENTRY. What is known is that glDebugMessageCallback requires that the function it is given has C linkage.

If it does, then throwing an exception from it is undefined behavior, since you’re throwing an exception across what is effectively a C function’s interface, which is not defined in the C++ specification. And if it does not, then as previously stated, your code has UB, since OpenGL requires a function with C linkage.

So either way, this is UB.

And that’s separate from the fact that, even if none of that was the case, you have to make debug callbacks synchronous (with the GL_DEBUG_OUTPUT_SYNCHRONOUS enable) or else these messages could come from other threads.

GLAPIENTRY is defined itself by glfw3.h, however I removed it and now i just needed instead
glDebugMessageCallback((GLDEBUGPROC)this->debugMessageCallback, lastErrorMessageBuffer[0]);

and GLDEBUGPROC is defined by Glad.

It still works and receives the std::exception.

I am setting on init the GL_DEBUG_OUTPUT_SYNCHRONOUS and also am starting up a DEBUG_CONTEXT but why do i need to be considering other threads? I just have one application thread?

“Throwing through a C function is not something C++ has any concept of. And passing OpenGL a pointer to a function with C++ linkage is not part of the OpenGL specification of any version.”

I will repeat yet again, I am not thowing in a C function. it is within a statically declared C++ method.

I have just looked on other discussion threads and forums that state it is okay to use C++ static methods as callbacks so I am sorry i do not concur with anything you are saying.

You’re not quite understanding the idea that whether it works on your machine, with your compiler, and your OpenGL implementation is not a valid standard of proof for this discussion. We’re talking about what is guaranteed to work, not what you can get away with.

If GLAPIENTRY is properly declared, then the function will have C linkage. But then you’re throwing exceptions through a function with C linkage.

Because OpenGL implementations may, and often do, create other threads to do some work in. But since you’re setting the debug output to be synchronous, that’s fine.

That doesn’t meet the requirements of the specification, which says:

Inevitably, that type has C linkage; the entire header containing its definition is bracketed with

#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif

Now, on platforms where the “system” C and C++ compilers are basically the same compiler (and come from the same source as the linker), you’ll probably get away with differences in linkage (so long as you’re not trying to export the function from one compilation unit and import it into another, because functions with C++ linkage have their names mangled to support overloading).

But in any case, it doesn’t matter that you’re throwing from a C++ function, but that you’re throwing through a C function. Somewhere on the call stack between the callback and the try/catch will be at least one C function (the OpenGL API function that invoked the callback). When an exception is thrown, the exception-handling code generated by the compiler has to unwind the call stack until it finds a handler. And a C++ compiler isn’t required to know how to do this for C functions, and a C compiler certainly isn’t required to know how to deal with exceptions. Because C functions can only (legally) call functions with C linkage (whether directly or through function pointers), and C++ functions with C linkage aren’t allowed to throw exceptions (because code generated by a C compiler doesn’t know how to deal with them).

It probably works if the C compiler, C++ compiler and linker are all part of “Microsoft Developer Studio”, and they’re the same versions which were used to compile both opengl32.dll and the ICD. It probably works if the C and C++ compilers are both gcc, the linker is GNU ld, and they’re the same versions used to build all of the myriad fragments that Linux’ OpenGL implementation has been split into of late.

But in general, anyone following your suggestion of throwing exceptions from the debug callback is opening the door to the kind of problems that aren’t exactly simple to diagnose even by someone familiar with the low-level details of compilation and linking, and all but impossible for those who aren’t.

If it works, it works. If it doesn’t, you get a crash, quite possibly with a backtrace that’s complete gibberish for good measure.

We were targeting the Windows platform using Glad, Glfw and Microsoft Windows. Glad and other C linkage library docs state that we can use C++ Static methods as a callback in such places.

Its actually down to whether or not the CPU assembly supports stack unwinding and its irrelevant and not whether you are in C or C++. I would check your compiler switches to look for an ability to support stack unwinding.

We do not have any requirements to support another platform at this moment in time, although we may expand to test onto other such platforms in the future. As said before, the original thread was to provide information about how to receive OpenGL error information, and i think we have covered enough for that user’s question in this discussion thread so thank you for your time, we won’t be participating anymore in this or other discussions, have already removed the glad “C” linkage dependencies and will be using something else more modern instead to handle any bindings.