Let's consider the following three files.
tclass.h:
#include <iostream>
#include <vector>
template<typename rt>
class tclass
{
public:
void wrapper()
{
//Storage is empty
for(auto it:storage)
{
}
try
{
thrower();
}
catch(...)
{
std::cout << "Catch in wrapper\n";
}
}
private:
void thrower(){}
std::vector<int> storage;
};
spec.cpp:
#include "tclass.h"
//The exact type does not matter here, we just need to call the specialized method.
template<>
void tclass<long double>::thrower()
{
//Again, the exception may have any type.
throw (double)2;
}
main.cpp:
#include "tclass.h"
#include <iostream>
int main()
{
tclass<long double> foo;
try
{
foo.wrapper();
}
catch(...)
{
std::cerr << "Catch in main\n";
return 4;
}
return 0;
}
I use Linux x64, gcc 4.7.2, the files are compiled with this command:
g++ --std=c++11 *.cpp
First test: if we run the program above, it says:
terminate called after throwing an instance of 'double'
Aborted
Second test: if we comment for(auto it:storage) in the tclass.h file, the program will catch the exception in main function. WATWhy? Is it a stack corruption caused by an attempt to iterate over the empty vector?
Third test: lets uncomment back the for(auto it:storage) line and move the method specialization from spec.cpp to main.cpp. Then the exception is caught in wrapper. How is it possible and why does possible memory corruption not affect this case?
I also tried to compile it with different optimization levels and with -g, but results were the same.
Then I tried it on Windows 7 x64, VS2012 express, compiling with x64 version of cl.exe with no extra command line arguments. At the first test this program produced no output, so I think it just crashed silently, so the result is similar with Linux version. For the second test it produced no output again, so result is different from Linux. For the third test the result was similar with Linux result.
Are there any errors in this code so they can lead to such behavior? May the results of the first test be caused by possible bug in compilers?
With your code, I have with gcc 4.7.1:
spec.cpp:6: multiple definition of 'tclass<long double>::thrower()'
You may correct your code by declaring the specialization in your .h as:
template<> void tclass<long double>::thrower();
Related
Attempting to compile the following code with vcvarsall.bat in command line throws a warning saying that the exception handler is needed in the code but not called before using /EHsc.
Code:
#include <iostream>
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}
The batch file:
#echo off
cl C:\Development\..\basicmath.cpp
The warning:
C:\...\ostream(746): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:...\basicmath.cpp(10): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)' being compiled
Line 743 - 754 of ostream line 746 (from error) is _TRY:
if (!_Ok) {
_State |= ios_base::badbit;
} else { // state okay, insert
_TRY_IO_BEGIN
if ((_Ostr.flags() & ios_base::adjustfield) != ios_base::left) {
for (; 0 < _Pad; --_Pad) { // pad on left
if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) {
_State |= ios_base::badbit; // insertion failed, quit
break;
}
}
}
Adding /EHsc to my batch file will allow it to run but I would like to know why this is. Why does this block of code from the file for output require EHsc to be called?
MSDOCS says EHsc is for cleanup to prevent memory leaks, what is causing the leak and why do they need an external program to fix the leak instead of fixing it in the same file (this may sound rude but its just ignorant)?
Edit: thank you for pointing out its a warning and not an error.
Short answer:
Add /EHs or /EHsc to your compilation options as the documentation suggests. It's the most portable option regarding exceptions handling, if you will ever need to execute the same code on Unix machine.
Long answer:
There are two parts to this question. First is why the warning occurs in iostream and the second is what does the warning mean.
Why are there exceptions in iostream?
The default behaviour of streams in C++ is exceptionless - any failure is represented by setting an internal fail bit, accessible with eof(), fail() and bad() functions. However, you can change this behaviour to throwing exceptions on failure by using exceptions() method on stream. You can choose which fail bits trigger exceptions, but the main point is that the code must be there by standard. The warning seems to analyze only that - it notices a possible path where throw occurs and reports a warning.
What does the warning mean?
From the Microsoft documentation (emphasis mine):
By default (that is, if no /EHsc, /EHs, or /EHa option is specified), the compiler supports SEH handlers in the native C++ catch(...) clause. However, it also generates code that only partially supports C++ exceptions . The default exception unwinding code doesn't destroy automatic C++ objects outside of try blocks that go out of scope because of an exception.
The issue is that (for some reason) MSVC compiler by default generates assembly which is wrong according to the standard. Stack unwinding will not be perfomerd when exception is thrown, which may cause memory leaks and other unexpected behaviours.
An example correct C++ code, which has a memory leak under the default setting:
void foo()
{
std::string str = "This is a very long string. It definitely doesn't use Small String Optimization and it must be allocated on the heap."
std::cout << str;
throw std::runtime_error{"Oh no, something went wrong"};
}
int main()
{
try
{
foo();
}
catch (std::exception&)
{
// str in foo() was possibly not released, because it wasn't deleted when exception was thrown!
}
}
So the final answer would be:
If you plan to use Structured Exceptions (like divide-by-zero or invalid memory access errors) or use a library that uses them, use /EHa
If you don't need to catch SEs, choose /EHs for compatibility with C++ standard and portability
Never leave the defaults, always set /EH to one alternative or another, otherwise you will have to deal with strange behaviours when using exceptions.
That's a warning so your current program compiles fine. But problems come up in programs as such:
#include <exception>
#include <iostream>
struct A{
A(int x):x(x) {
std::cout<<"Contructed A::"<<x<<'\n';
}
~A() {
std::cout<<"Destructed A::"<<x<<'\n';
}
private:
int x;
};
void foo() {
A a{2};
throw std::bad_exception{};
}
int main()
{
A a {1};
try {
foo();
} catch(const std::bad_exception& ex) {
std::cout<<ex.what()<<'\n';
}
return 0;
}
Using cl test.cpp yields the output:
Contructed A::1
Contructed A::2
bad exception
Destructed A::1
While using cl test.cpp /EHsc yields:
Contructed A::1
Contructed A::2
Destructed A::2
bad exception
Destructed A::1
This behavior is explained by the documentation for the warning C4530:
When the /EHsc option isn't enabled, automatic storage objects in the
stack frames between the throwing function and the function where the
exception is caught don't get destroyed. Only the automatic storage
objects created in a try or catch block get destroyed, which can lead
to significant resource leaks and other unexpected behavior.
That explains a {2} not being destructed when the program wasn't compiled with /EHsc.
And of course,
If no exceptions can possibly be thrown in your executable, you may
safely ignore this warning.
So, for a program like
#include <cstdio>
int main()
{
std::printf("hello world\n");
return 0;
}
cl.exe quietly compiles.
I was experimenting with Clang 6.0's Memory Sanitizer(MSan).
Code is compiled with
clang++ memsans.cpp -std=c++14 -o memsans -g -fsanitize=memory -fno-omit-frame-pointer -Weverything
on Ubuntu 18.04. As per the MSan documentation
It will tolerate copying of uninitialized memory, and also simple
logic and arithmetic operations with it. In general, MemorySanitizer
silently tracks the spread of uninitialized data in memory, and
reports a warning when a code branch is taken (or not taken) depending
on an uninitialized value.
So the following code does not generate any error
#include <iostream>
class Test {
public:
int x;
};
int main() {
Test t;
std::cout << t.x;
std::cout << std::endl;
return 0;
}
But this will
#include <iostream>
class Test {
public:
int x;
};
int main() {
Test t;
if(t.x) {
std::cout << t.x;
}
std::cout << std::endl;
return 0;
}
Ideally one would like both of these code samples to generate some sort of error since both are "using" an uninitialised variable in the sense that the first one is printing it. This code is a small test code and hence the error in the first code is obvious, however if it were a large codebase with a similar error, MSan would totally miss this. Is there any hack to force MSan to report this type of error as well ?
It sounds like your C++ library wasn't built with MSan. Unlike ASan and UBSan, MSan requires that the whole program was built with msan enabled. Think of it like having a different ABI, you shouldn't link two programs built with different msan settings. The one exception is libc for which msan adds "interceptors" to make it work.
If you write your own code which you want to integrate with msan by reporting an error where msan normally wouldn't (say, in a function which makes a copy but you know the data needs to be initialized) then you can use __msan_check_mem_is_initialized from the msan_interface.h file: https://github.com/llvm-mirror/compiler-rt/blob/master/include/sanitizer/msan_interface.h
I am new c++ so forgive me to be asking this question. I created a project and run it the first time, it is successful. But when i start another project and i added 4 classes to it (you can see from the tabs) and the main.cpp is unable to run. I am confused as the codes are exactly the same in both projects.
Run Successful:
Success
Build Successful but run failed:
Run Failed
What are the solutions to solve this problem?
Do i have to post codes of all my classes? (there are 8 files)
student.h:
#ifndef CLSSTUDENT_H
#define CLSSTUDENT_H
#include <string>
#include <iostream>
using namespace std;
class clsStudent {
protected:
string name;
string student_no;
string program;
public:
clsStudent(string n, string sn,string prog );
virtual void displayStudentDetails();
};
student.cpp
#include "TutorialClass.h"
void TutorialClass::addStudent(clsStudent std)
{
_students.push_back(std);
}
int TutorialClass::getStudentCount()
{
return _students.size();
}
void TutorialClass::display()
{
}
#endif /* CLSSTUDENT_H */
I open up a new project and added only this class. It is unable to run as well. What is the problem in the codes?
It seems that your program only fails to run when it's compiled with other files. My bet is that in these files you've got buggy code that is running before main() gets to run.
This can happen in cases like this:
int f() {
throw; // bam! Uncaught exception;
}
int x = f(); // this runs before main()
Or this:
class C {
C() {
cout << "This runs before main() too!" << endl;
}
};
C my_c; // calls constructor
In both cases: code was executed before main(). You want this because you want your global variables to be initialized before running main(). If this initialization code manages to crash the program via a segfault or an exit() call or throwing some exception which isn't caught? You've got a crashed program before it ever even gets the chance to run.
how to prove that when that compile the templates in C++, the compiler generates an instantiation in each compilation unit that uses it, then the linker throws away all but one of them[the commond model];
so there are 2 thing we should prove
1. create multiple copies 2.remove the copies when link
we can prove the second one use the code like
////head.h
#ifndef _TEMP_H
#define _TEMP_H
#include <typeinfo>
#include <iostream>
template<typename T>
class Test
{
public:
Test(T i = 0) : val(i) {}
void getId() const
{
std::cout << typeid(*this).name() << std::endl;
}
void getVal() const
{
std::cout << "Val: " << val << std::endl;
}
private:
T val;
};
#endif
//a.cpp
#include "head.h"
Test<int> a(1);
//b.cpp
#include "head.h"
extern Test<int> a;
int main()
{
Test<int> b;
a.getId();
b.getId();
a.getVal();
b.getVal();
return 0;
}
compiler: g++ 4.4.1
get the result :
4TestIiE
4TestIiE
Val: 1
Val: 0
So the second one has been proved;
But I can not prove the first one
I google it and have some sugestions as followed
1. use the dump yes we can dump the objfile and get the result
but can we write some code to output something to prove it??
Number 1 is easy. Just create a bunch of different source files and include the template header in each one, and use the template class to produce some output. Then compile each source file separately. Now link them each one by one with a main program that calls it. If you don't get any linker errors but the program generates the output, that proves each compiled object file contained the template code.
P.S. The extra copies might not get eliminated, they may still exist as dead code in the executable.
Some compilers definitely don't do that. The IBM C++ compiler generates required templates at link time and compiles them then, in a repeat-until-closure process.
I'm having some troubles with Boost.Interprocess allocators when compiling with optimization. I managed to get this down to a 40 lines testcase, most of which is boilerplate. Just have a look at create() and main() functions in the code below.
#include <iostream>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
namespace interp = boost::interprocess;
struct interp_memory_chunk
{
interp::managed_shared_memory chunk;
interp_memory_chunk ()
{
interp::shared_memory_object::remove ("GCC_interprocess_test");
chunk = interp::managed_shared_memory (interp::create_only, "GCC_interprocess_test", 0x10000);
}
~interp_memory_chunk ()
{
interp::shared_memory_object::remove ("GCC_interprocess_test");
}
};
typedef interp::allocator <int, interp::managed_shared_memory::segment_manager> allocator_type;
inline void
create (allocator_type& allocator, allocator_type::value_type& at, int value)
{
allocator.construct (allocator.address (at), value);
}
int
main ()
{
interp_memory_chunk memory;
allocator_type allocator (memory.chunk.get_segment_manager ());
allocator_type::pointer data = allocator.allocate (1);
create (allocator, *data, 0xdeadbeef);
std::cout << std::hex << *data << "\n";
}
When compiling this without optimization:
g++ interprocess.cpp -lboost_thread -o interprocess
and running, the output is deadbeef, as expected.
However, when compiling with optimization:
g++ -O1 interprocess.cpp -lboost_thread -o interprocess
running gives 0, not what is expected.
So, I'm not sure where the problem is. Is this a bug in my program, i.e. do I invoke some UB? Is it a bug in Boost.Interprocess? Or maybe in GCC?
For the record, I observe this behavior with GCC 4.6 and 4.5, but not with GCC 4.4 or Clang. Boost version is 1.46.1 here.
EDIT: Note that having create() as a separate function is essential, which might indicate that problem arises when GCC inlines it.
As others have suggested, one solution is try to find the minimial set of optimisation flags you need to trigger your problem, using -O1 -fno....
Other options:
Use Valgrind and see what it comes up with
Try compiling with "-fdump-tree-all", this generates a bunch of intermediate compiled files. You can then see if the compiled code has any differences. These intermediate files are still in C++, so you don't need to know assembler. They are pretty much human readable, and certainly diffable.