I have recently moved from Linux to Windows 10 for my OpenGL C++ projects, and the first time I do something with arrays on Windows, they suddenly don't seem to work anymore. Every time I try to create an array from a non-const variable that represents a size, the execution of the program does nothing (meaning no output to the console, but also no error message). It compiles fine. To understand what I mean, look at this code snippet:
#include <iostream>
int main()
{
int s = 10;
float* array = new float[s];
std::cout << *array;
delete[] array;
return 0;
}
It is perfectly legit, but when compiling it with MinGW on Windows and then running it, nothing happens. Yet, using the GCC compiler on Linux writes a 0 to the console, which is perfectly fine and logical, indicating that it is not the code that is flawed. Do you know what could cause this problem? It is really on Windows that I have encountered this behaviour for the first time. Both compilation commands are straight-forward:
g++ array-test.cpp -o array-test
Note that making s a const int fixes the issue, but I do want my arrays to be dynamically allocated, from user input.
I am using a relatively unspectacular text editor (Notepad++) and compile in the Windows PowerShell with MinGW. The supplied code replicates the behaviour on my machine, but I cannot guarantee that it will do so on others as well. Even example code from the internet creating an array with a non-const variable as size will not run.
Related
I asked a question about this earlier but I hadn't done hours of research yet. My C++ compiler appears to be fine, but my computer cannot run .exe which were compiled from C++ code using the vector class if the vector has any contents. Here is some extremely basic code that cannot run (no errors thrown, nothing is printed) as a result of this:
#include <vector>
#include <iostream>
using namespace std;
int main()
{
printf("Hello!\n");
std::vector<int> myints;
// myints.push_back(1);
// vector<int> myvector = {10,20,30,40,50};
return 0;
}
With both of those two lines commented out, the code prints Hello! as expected. If either line is uncommented, my computer cannot run the .exe that is built. I thought this was likely a compiler issue so I uninstalled and reinstalled g++ on Windows. Same results.
Then I had a friend compile my code, both with the lines commented and uncommented. He sent me the resulting .exes. The one with both lines commented produced the Hello! output, the one with them uncommented did not. I compiled the code (lines uncommented) and sent him the .exe and it ran.
This is not an issue unique to my compiler, this is coming from my machine somehow. I can do other C++ stuff just fine, like allocating space for an array with malloc() but I want to append stuff onto a list so I need vector to work.
I have a C++ client to a C++/CLI DLL, which initializes a series of C# dlls.
This used to work. The code that is failing has not changed. The code that has changed is not called before the exception is thrown. My compile environment has changed, but recompiling on a machine with an environment similar to my old one still failed. (EDIT: as we see in the answer this is not entirely true, I was only recompiling the library in the old environment, not the library and client together. The client projects had been upgraded and couldn't easily go back.)
Someone besides me recompiled the library, and we started getting memory management issues. The pointer passed in as a String must not be in the bottom 64K of the process's address space. I recompiled it, and all worked well with no code changes. (Alarm #1) Recently it was recompiled, and memory management issues with strings re-appeared, and this time they're not going away. The new error is Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I'm pretty sure the problem is not located where I see the exception, the code didn't change between the successful and failing builds, but we should review that to be complete. Ignore the names of things, I don't have much control over the design of what it's doing with these strings. And sorry for the confusion, but note that _bridge and bridge are different things. Lots of lines of code missing because this question is already too long.
Defined in library:
struct Config
{
std::string aye;
std::string bee;
std::string sea;
};
extern "C" __declspec(dllexport) BridgeBase_I* __stdcall Bridge_GetConfiguredDefaultsImplementationPointer(
const std::vector<Config> & newConfigs, /**< new configurations to apply **/
std::string configFolderPath, /**< folder to write config files in **/
std::string defaultConfigFolderPath, /**< folder to find default config files in **/
std::string & status /**< output status of config parse **/
);
In client function:
GatewayWrapper::Config bridge;
std::string configPath("./config");
std::string defaultPath("./config/default");
GatewayWrapper::Config gwtransport;
bridge.aye = "bridged.dll";
bridge.bee = "1.0";
bridge.sea = "";
configs.push_back(bridge);
_bridge = GatewayWrapper::Bridge_GetConfiguredDefaultsImplementationPointer(configs, configPath, defaultPath, status);
Note that call to library that is crashing is in the same scope as the vector declaration, struct declaration, string assignment and vector push-back
There are no threading calls in this section of code, but there are other threads running doing other things. There is no pointer math here, there are no heap allocations in the area except perhaps inside the standard library.
I can run the code up to the Bridge_GetConfiguredDefaultsImplementationPointer call in the debugger, and the contents of the configs vector look correct in the debugger.
Back in the library, in the first sub function, where the debugger don't shine, I've broken down the failing statement into several console prints.
System::String^ temp
List<CConfig^>^ configs = gcnew List<CConfig ^>((INT32)newConfigs.size());
for( int i = 0; i< newConfigs.size(); i++)
{
std::cout << newConfigs[i].aye<< std::flush; // prints
std::cout << newConfigs[i].aye.c_str() << std::flush; // prints
temp = gcnew System::String(newConfigs[i].aye.c_str());
System::Console::WriteLine(temp); // prints
std::cout << "Testing string creation" << std::endl; // prints
std::cout << newConfigs[i].bee << std::flush; // crashes here
}
I get the same exception on access of bee if I move the newConfigs[i].bee out above the assignment of temp or comment out the list declaration/assignment.
Just for reference that the std::string in a struct in a vector should have arrived at it's destination ok
Is std::vector copying the objects with a push_back?
std::string in struct - Copy/assignment issues?
http://www.cplusplus.com/reference/vector/vector/operator=/
Assign one struct to another in C
Why this exception is not caught by my try/catch
https://stackoverflow.com/a/918891/2091951
Generic AccessViolationException related questions
How to handle AccessViolationException
Programs randomly getting System.AccessViolationException
https://connect.microsoft.com/VisualStudio/feedback/details/819552/visual-studio-debugger-throws-accessviolationexception
finding the cause of System.AccessViolationException
https://msdn.microsoft.com/en-us/library/ms164911.aspx
Catching access violation exceptions?
AccessViolationException when using C++ DLL from C#
Suggestions in above questions
Change to .net 3.5, change target platform - these solutions could have serious issues with a large mult-project solution.
HandleProcessCorruptedStateExceptions - does not work in C++, this decoration is for C#, catching this error could be a very bad idea anyway
Change legacyCorruptedStateExceptionsPolicy - this is about catching the error, not preventing it
Install .NET 4.5.2 - can't, already have 4.6.1. Installing 4.6.2 did not help. Recompiling on a different machine that didn't have 4.5 or 4.6 installed did not help. (Despite this used to compile and run on my machine before installing Visual Studio 2013, which strongly suggests the .NET library is an issue?)
VSDebug_DisableManagedReturnValue - I only see this mentioned in relation to a specific crash in the debugger, and the help from Microsoft says that other AccessViolationException issues are likely unrelated. (http://connect.microsoft.com/VisualStudio/feedbackdetail/view/819552/visual-studio-debugger-throws-accessviolationexception)
Change Comodo Firewall settings - I don't use this software
Change all the code to managed memory - Not an option. The overall design of calling C# from C++ through C++/CLI is resistant to change. I was specifically asked to design it this way to leverage existing C# code from existing C++ code.
Make sure memory is allocated - memory should be allocated on the stack in the C++ client. I've attempted to make the vector be not a reference parameter, to force a vector copy into explicitly library controlled memory space, did not help.
"Access violations in unmanaged code that bubble up to managed code are always wrapped in an AccessViolationException." - Fact, not a solution.
but it was the mismatch, not the specific version that was the problem
Yes, that's black letter law in VS. You unfortunately just missed the counter-measures that were built into VS2012 to turn this mistake into a diagnosable linker error. Previously (and in VS2010), the CRT would allocate its own heap with HeapAlloc(). Now (in VS2013), it uses the default process heap, the one returned by the GetProcessHeap().
Which is in itself enough to trigger an AVE when you run your app on Vista or higher, allocating memory from one heap and releasing it from another triggers an AVE at runtime, a debugger break when you debug with the Debug Heap enabled.
This is not where it ends, another significant issue is that the std::string object layout is not the same between the versions. Something you can discover with a little test program:
#include <string>
#include <iostream>
int main()
{
std::cout << sizeof(std::string) << std::endl;
return 0;
}
VS2010 Debug : 32
VS2010 Release : 28
VS2013 Debug : 28
VS2013 Release : 24
I have a vague memory of Stephen Lavavej mentioning the std::string object size reduction, very much presented as a feature, but I can't find it back. The extra 4 bytes in the Debug build is caused by the iterator debugging feature, it can be disabled with _HAS_ITERATOR_DEBUGGING=0 in the Preprocessor Definitions. Not a feature you'd quickly want to throw away but it makes mixing Debug and Release builds of the EXE and its DLLs quite lethal.
Needless to say, the different object sizes seriously bytes when the Config object is created in a DLL built with one version of the standard C++ library and used in another. Many mishaps, the most basic one is that the code will simply read the Config::bee member from the wrong offset. An AVE is (almost) guaranteed. Lots more misery when code allocates the small flavor of the Config object but writes the large flavor of std::string, that randomly corrupts the heap or the stack frame.
Don't mix.
I believe 2013 introduced a lot of changes in the internal data formats of STL containers, as part of a push to reduce memory usage and improve perf. I know vector became smaller, and string is basically a glorified vector<char>.
Microsoft acknowledges the incompatibility:
"To enable new optimizations and debugging checks, the Visual Studio
implementation of the C++ Standard Library intentionally breaks binary
compatibility from one version to the next. Therefore, when the C++
Standard Library is used, object files and static libraries that are
compiled by using different versions can't be mixed in one binary (EXE
or DLL), and C++ Standard Library objects can't be passed between
binaries that are compiled by using different versions."
If you're going to pass std::* objects between executables and/or DLLs, you absolutely must ensure that they are using the same version of the compiler. It would be well-advised to have your client and its DLLs negotiate in some way at startup, comparing any available versions (e.g. compiler version + flags, boost version, directx version, etc.) so that you catch errors like this quickly. Think of it as a cross-module assert.
If you want to confirm that this is the issue, you could pick a few of the data structures you're passing back and forth and check their sizes in the client vs. the DLLs. I suspect your Config class above would register differently in one of the fail cases.
I'd also like to mention that it is probably a bad idea in the first place to use smart containers in DLL calls. Unless you can guarantee that the app and DLL won't try to free or reallocate the internal buffers of the other's containers, you could easily run into heap corruption issues, since the app and DLL each have their own internal C++ heap. I think that behavior is considered undefined at best. Even passing const& arguments could still result in reallocation in rare cases, since const doesn't prevent a compiler from diddling with mutable internals.
You seem to have memory corruption. Microsoft Application Verifier is invaluable in finding corruption. Use it to find your bug:
Install it to your dev machine.
Add your exe to it.
Only select Basics\Heaps.
Press Save. It doesn't matter if you keep application verifier open.
Run your program a few times.
If it crashes, debug it and this time, the crash will point to your problem, not just some random location in your program.
PS: It's a great idea to have Application Verifier enabled at all times for your development project.
I'm seeing something weird happening with Visual Studio 2015 Community. Code that worked perfectly in VS2012 crashes at startup when ported to VS2015, before main is invoked: the classic symptoms of some static initialization mess. I have a few static variables, but used properly, with the standard "Construct On First Use" pattern, e.g.:
const int& i()
{
static int *v = new int(1);
return *v;
}
The code above causes an assert from the runtime while initializing the program (see image http://i.stack.imgur.com/nsQGS.png). Pressing retry simply quits the program: no call stack, no information whatsoever.
The code below however works flawlessly:
const int& i()
{
static int *v = nullptr;
if (v == nullptr)
v = new int(1);
return *v;
}
It seems to me that VS2015 is doing what looks like some (illegal) optimization (even in a debug build), by executing the static variable initialization code during program initialization, and not the first time that the function is called, as the C++ standard requires.
I tried several variations of the code above: class methods, free functions, different objects (std::vector, cv::Mat), always with the same result: the static pointer has to be initialized to null or the program doesn't start.
So... am I missing something or is VS2015 actually messing up badly?
UPDATE:
I spent some time trying to find the minimal setup that shows the problem, and this is what I got:
create a project using the "CLR empty project" template.
add a cpp file, containing just the offending function and main(). Main can be empty, it doesn't matter: the bug occurs BEFORE it is even reached.
add 'main' as entry point (or you get a link error).
The x86 version works, but the x64 doesn't.
For comparison, a project with the identical code but created as "Win32 console application" doesn't have the problem, even after adding the /CLR option. I can see differences in the vcxproj files, but none justifies the error, although one or more of them clearly IS the cause.
Is there a way to upload a zip with the project?
Well, #bogdan got it right. My project had a mix of settings that was neither /SUBSYSTEM:CONSOLE nor /SUBSYSTEM:WINDOWS. Once I fixed that, everything started to work as expected. My test projects had the same problem, I blame Microsoft for not having a clear "CLR windows app" C++ template any more in VS2015 (they want to push you to use C# for that, which makes sense most of the times, but not always).
I found this page particularly useful in explaining all the different settings that have to be consistent (it's not just /SUBSYSTEM...).
I wish I could mark #bogdan's comment as answer, but I can't see anything to do that.
Thanks Bogdan!
I'm trying to copy a wide c-string from one place into another. I'm using Visual Studio 2012 express on windows8 64-bit platform. It works perfectly fine unless i try to run the application on my main computer with Windows7 x64. It crashes instantly. No exception error though it's a messy crash with no trackable error code whatsoever. If you need more specific information about the crash itself i will try to provide it. When i comment out the copying the program works perfectly fine. So it's pretty obvious the problem is with the function itself. Here is the line that does all the copying:
virtual void CClass::ChangeText();
void CClass::ChangeText(float _f)
{
std::wstringstream wss;
wss << _f;
wcscpy(const_cast<wchar_t *>(this->m_lpszWideText),wss.str().c_str());
}
^ crashes on win7 / works on win8
My wild guess is that the new compiler uses a newer version of wmemcpy that just doesn't work on windows 7? Shouldn't the program crash only when it reaches the function call line though?
A Crash with String-Copy algorithms have usually two origins:
Your Source is not NULL-Terminated
In Your Example this is not the case, because you extract it from wstringstream::c_str()
Your Destination is not big enough to handle the source data, and so is written out of Bounds.
This may be the cause of your Crash, means, your this->m_lpszWideText is too small (please give the Declaration of it and, if it is dynamically allocated show us, how.)
I have an issue with my code that has some very strange symptoms.
The code is compiled on my computer with the following versions:
a. GCC Version: 4.4.2
b. CMAKE verson: 2.8.7
c. QNX (operating system) version: 6.5.0
And the code has a segfault whilst freeing some memory and exiting from a function (not dying on any code, just on the exit from a function).
The weird things about this are:
The code does it in release mode but not debug mode:
a. The code is threaded so this indicates a race condition.
b. I cannot debug by putting it in debug mode.
The code when compiled on a workmates machine with the same versions of everything, does not have this problem.
a. The wierd things about this are that the workmates code works, but also that the binary created from compiling on his machine, which is the same, is about 6mB bigger.
Now annoyingly I cannot post the code because it is too big and also for work. But can anyone point me along a path to fixing this.
Since I am using QNX I am limited for my debug tools, I cannot use Valgrind and since it is not supported in QNX, GDB doesn't really help.
I am looking for anyone who has had a similar/same problem and what the cause was and how they fixed it.
EDIT:
Sooo... I found out what it was, but im still a bit confused about how it happened.
The culprit code was this:
Eigen::VectorXd msBb = data.modelSearcher->getMinimumBoundingBox();
where the definition for getMinimumBoundingBox is this:
Eigen::VectorXd ModelSearcher::getMinimumBoundingBox();
and it returns a VectorXd which is always initialised as VectorXd output(6, 1). So I immediately thought, right it must be because the VectorXd is not being initialised, but changing it to this:
Eigen::VectorXd msBb(6, 1); msBb = data.modelSearcher->getMinimumBoundingBox();
But this didn't work. In fact I had to fix it by changing the definition of the function to this:
void ModelSearcher::getMinimumBoundingBox(Eigen::MatrixXd& input);
and the call to this
Eigen::VectorXd msBb(6, 1); data.modelSearcher->getMinimumBoundingBox(msBb);
So now the new question:
What the hell? Why didn't the first change work but the second did, why do I have to pass by reference? Oh and the big question, how the hell didn't this break when my co-worker compiled it and I ran it? Its a straight out memory error, surely it shouldn't depend on which computer compiles it, especially since the compiler and all the other important things are the same!!??
Thanks for your help guys.
... the binary created from compiling on his machine, which is the same, is about 6mB bigger
It's worth figuring out what the difference is (even if it's just the case that his build hides, while yours exposes, a real bug):
double-check you're compiling exactly the same code (no un-committed local changes, no extra headers in the include search path, etc.)
triple-check by adding a -E switch to your gcc arguments in cmake, so it will pre-process your files with the same include path as regular compilation; diff the pre-processor output
compare output from nm or objdump or whatever you have to for your two linked executables: if some system or 3rd-party library is a different version on one box, it may show up here
compare output from ldd if it's dynamically linked, make sure they're both getting the same library versions
compare the library versions it actually gets at runtime too, if possible. Hopefully you can do one of: run pldd, compare the .so entries in /proc/pid/map, run the process under strace/dtrace/truss and compare the runtime linker activity
As for the code ... if this doesn't work:
Eigen::VectorXd ModelSearcher::getMinimumBoundingBox();
// ...
Eigen::VectorXd msBb(6, 1); msBb = data.modelSearcher->getMinimumBoundingBox();
and this does:
void ModelSearcher::getMinimumBoundingBox(Eigen::MatrixXd& input);
// ...
Eigen::VectorXd msBb(6, 1); data.modelSearcher->getMinimumBoundingBox(msBb);
you presumably have a problem with the assignment operator. If it does a shallow copy and there is dynamically-allocated memory in the vector, you'll end up with two vectors holding the same pointer, and they'll both free/delete it.
Note that if the operator isn't defined at all, the default is to do this shallow copy.
You said you have to change from:
void ModelSearcher::getMinimumBoundingBox(Eigen::MatrixXd& input);
What was it before?
If it was:
void ModelSearcher::getMinimumBoundingBox(Eigen::MatrixXd input);
and the copy constructors / assignment operators weren't implemented properly it might have caused the problem.
Please do check how they are both implemented. Here's some info that might help.