I'm using the target attribute to generate different function implementations depending on the CPU architecture. If one of the functions throws an exception it doesn't get caught if I compile with gcc, but with clang it works as expected.
If there is only a single implementation of the function it does work for gcc as well.
Is this a bug in gcc?
Example (godbolt):
#include <stdexcept>
#include <iostream>
using namespace std;
__attribute__((target("default")))
void f() {
throw 1;
}
__attribute__((target("sse4.2,bmi")))
void f() {
throw 2;
}
int main()
{
try {
f();
}
catch(... )
{
std::cout << "Caught exception" << std::endl;
}
}
Output of gcc:
terminate called after throwing an instance of 'int'
Output of clang:
Caught exception
I reported this and a GCC developer confirmed it as a bug: link
For now a workaround seems to wrap the function and use the gnu::noipa attribute to disable interprocedural optimizations:
__attribute__((target("default")))
void f() {
throw 1;
}
__attribute__((target("sse4.2")))
void f() {
throw 2;
}
[[gnu::noipa]]
void f1()
{
f();
}
int main()
{
try {
f1();
}
catch(... )
{
return 0;
}
return 1;
}
The bug is now fixed in gcc's master branch and should be released with gcc version 13.
I'm trying to write a custom allocator to get better code coverage for branches that are executed only when OOM occurs. I managed to write the allocator, but when a bad_alloc is thrown on debug inside a class from std, an internal call to abort is made. This behavior is only on debug, on release I can run the tests.
Is there any way to disable this behavior on debug configuration?
Update #1
This is a code snippet where the problem described above occurs. I also forgot to mention that I use MSVC.
#include <iostream>
#include <string>
bool throw_bad_alloc = false;
void* operator new(size_t size)
{
if (throw_bad_alloc)
throw std::bad_alloc();
return ::malloc(size);
}
void operator delete(void* ptr)
{
::free(ptr);
}
int main()
{
try {
throw_bad_alloc = true;
std::string name;
name = "test_string";
}
catch (...)
{
std::cout << "thrown";
return 0;
}
std::cout << "not thrown";
return 0;
}
How can catch an exception being thrown from the constructor of a statically allocated object? Or at least how I can handle such an exception (like set_terminate or smth.) to perform some teardown logic before termination:
#include <iostream>
struct A
{
A(){throw std::exception();}
};
static A a;
int main(){}
The general work around for having global variables is a function with a static member.
#include <iostream>
struct A
{
A(){throw std::exception();}
};
A& getA()
{
static A a;
return a;
}
int main()
{
try {
getA();
}
catch(...) {
// error
}
}
Now You still effectively have a global variable. BUT the variable is initialized on first use. If you do this for all globals then the globals will not be initialized before main starts and you can out the try catch in main().
Here is the problem I encountered when trying recently to fiddle with private invocation outsie from the context of class members:
#include <iostream>
#include <exception>
class TestClass {
private: int var;
};
int main() {
TestClass test;
try {
test.var;
}
catch( std::exception& e) {
std::cout << "why does this not occur ?";
}
return 0;
}
The error is reasonable error: ‘int TestClass::var’ is private within this context test.var; therefor I tried to wrap the call within a template class to avoid the error being intellisensed.
#include <iostream>
#include <exception>
class TestClass {
private:
int var;
};
template <class t>
void foo() {
t cl;
try {
cl.var;
}
catch (std::exception& e) {
std::cout << "why does this not occur ?";
}
return;
}
int main() {
foo<TestClass>();
return 0;
}
This lame access attempt to this poor private variable area always leads to some compile-time violation error, SFINAE getarround doesn't seem to get anything resolved, I tried to just remote-sniff the accessibility to Class::var type always using templating:
#include <iostream>
#include <exception>
#include <type_traits>
#include <cstdint>
class TestClass
{
private:
int var;
};
template <class C>
int hasmember() {
int ret=0;
try {
ret= std::is_same<decltype(C::var), int>::value;
}
catch (std::exception& e)
{
std::cout << "why does this not occur ?";
}
return ret;
}
int main() {
TestClass cl;
printf("%s", hasmember<TestClass>()?"yes":"no");
}
The error-console is pale, and the program outputs "yes" not making sign of anything caugth within the context of an exception.
While its uninterceptability within try/exception clause is not well explainable for me, Why the compiler doesn't allow the code to execute and is there any flag to raise for g++ force it to run ?
Few shots and trials using SFINAE, extern didn't lead a way to any sign of light, but a moment I thought what if i use some oldschool C hacks to try forcing a seg-fault around the perimeter of this private region ?
Here what I have tried:
class Class_
{
private:
int b = 10;
public:
int a ;
};
int main()
{
Class_ Class_;
try {
printf("%d\n", *((&Class_.a) - 1));
}
catch (void* exc) {
printf("yet, will this ever be caught? \n");
};
}
Surprise!
No, the raw 'so-said' private value is accessed without restriction, I just tried to hindtrack the address one byte bacwards to get its predecessor, It's not so hard to achieve with variables of differnt types once you check their membership class::var and cast their typeinfo, the question here can this be anyhow a security defficiency in C++ class structurisation? Is C considered unsafe when used with C++ and how to safen this private area forcing a segmentation fault that conducts the eip to an exception handler ?
Note: More than probably that valgrind reports a crash in such a situation, I didn't try out but I would like some one to confirm.
Mocking types:
With class type mocking i could have access to a private member of another class of slight difference in its core, nothing makes evidence of an exception thrown, the experience follows:
#include <stdio.h>
class foo {
public:
int var=0;
int val=1;
};
class bar {
int var=2;
public:
int val=3;
};
int main()
{
bar* cl;
cl = new bar();
printf("%d\n",cl->val);
try {
printf("%d\n", ((foo*)(cl))->var);
}
catch (void* e) {
printf("Will this ever be caught ?");
}
return 0;
}
Output:
3
2
Conclusion: c++ compiler forbids compiling a conventional unauthorized access to a private member, while it doesn't throw an exception if this member is accessed from outside its container during run-time.
To summarize what you are likely misunderstanding:
private and protected are essentially limiting the access to the names of variables, functions, etc. which follow. That means, (outside C or any friend of C) you will not have access to (the name) C::var. If decltype(C::var) works, that is likely a bug in your compiler (both gcc and clang do not allow this).
Generally, there is no such thing as a built-in memory protection in C++ (I'm sure it is possible using some functionality of the underlying operating system). You will always have the possibility to cast a pointer to an object to char* and access individual bytes of the object. That means, if (you think) you know what you are doing you can access individual members of a class (calling private member functions is challenging, I guess). In other words, if you want to shoot yourself in the foot, C++ will not keep you from doing that.
class test
{
private:
class privateStruct
{
public:
int m;
privateStruct(int p){m=p;}
};
};
void ff()
{
test::privateStruct ps(4);
throw ps; //Does not work..
}
void main()
{
try
{
ff();
}
catch(...)
{
}
}
But the Following Code Works Why
class test
{
private:
class privateStruct
{
public:
int m;
privateStruct(int p){m=p;}
};
};
void ff()
{
throw test::privateStruct(4); //Work why
}
void main()
{
try
{
ff();
}
catch(...)
{
}
}
NOTE : I am using VC++ 6.
I need answer why the above code works.
Thanks in Advance :)
This is an old/known bug with Visual Studio 6.0. It ignores access specifiers when constructing temporaries. No fix is available.
Raising the warning level to 3 or higher (/W3) will cause the offending code to give a warning.
The code in your second example works because Visual C++ 6 is notorious for its horrible standards compliance.
It works by accident.
Even the second code snippet won't compile. privateStruct cannot be accessed in the function ff().