_invalid_parameter_noinfo shows up as a problem most often as an “Unresolved external symbol” when you get some mix up between DEBUG and RELEASE modes. But it’s also a performance problem in situations where it’s compiled in unnecessarily.
So what is it? Well, it’s basically the function that gets called when the Microsoft Visual C++ compiled code detects a type of run-time error, such as a vector index out of range, or incrementing an iterator past the end of a container.
There are two functions: _invalid_parameter, which gets called in debug mode, and _invalid_parameter_noinfo, which gets called in non-debug mode. If you have a module compiled without _DEBUG defined, and you link with the debug library, then you will get the “Unresolved external symbol” error. This could be a problem with inconsistent #includes. See this thread on devmaster.net for some practical experiences.
What is _invalid_parameter_noinfo then? Well, first ask what _invalid_parameter is. _invalid_parameter is basically an assert. When an error is detected, _invalid_parameter is called, and is passed debug information, like the file name and line number pointers. It then calls _crt_debugger_hook and _invoke_watson. In non-debug mode (release mode), the debug info is not available, so invalid_parameter_noinfo simply calls invalid_parameter with NULL parameters. It’s actually an optimization, saving having the NULL parameters passed from every bit of your code, instead you code “just” needs to call this one function
You might also be having problems with _invalid_parameter_noinfo if you have code that crashes (on this function) on in release mode. That’s most likely some form of release-only bug, such as uninitialized memory, and the call to _invalid_parameter_noinfo is the end result. DO NOT IGNORE IT, or try to work around it. You need to find out exactly why it is being called.
But suppose your code works fine, and _invalid_parameter_noinfo is never called, you might be peeking through the disassembly, trying to figure out why it is so slow, and you see all these calls to _invalid_parameter_noinfo
Consider this code:
void CVerletPoint::SatisfyConstraints() { vector::iterator i; for (i = mp_constraints.begin(); i != mp_constraints.end(); i++) { (*i)->Satisfy(this); } }
A nice simple bit of code that just iterates over a vector of CVerletConstraint objects, and calls some function on each one. It compiles to this:
00405C20 push ebx 00405C21 push ebp 00405C22 push esi 00405C23 mov ebp,ecx 00405C25 mov esi,dword ptr [ebp+20h] 00405C28 cmp esi,dword ptr [ebp+24h] 00405C2B push edi 00405C2C lea edi,[ebp+1Ch] 00405C2F jbe CVerletPoint::SatisfyConstraints+16h (405C36h) 00405C31 call _invalid_parameter_noinfo (407A81h) 00405C36 mov ebx,dword ptr [edi+8] 00405C39 cmp dword ptr [edi+4],ebx 00405C3C jbe CVerletPoint::SatisfyConstraints+23h (405C43h) 00405C3E call _invalid_parameter_noinfo (407A81h) 00405C43 test edi,edi 00405C45 je CVerletPoint::SatisfyConstraints+2Bh (405C4Bh) 00405C47 cmp edi,edi 00405C49 je CVerletPoint::SatisfyConstraints+30h (405C50h) 00405C4B call _invalid_parameter_noinfo (407A81h) 00405C50 cmp esi,ebx 00405C52 je CVerletPoint::SatisfyConstraints+5Fh (405C7Fh) 00405C54 test edi,edi 00405C56 jne CVerletPoint::SatisfyConstraints+3Dh (405C5Dh) 00405C58 call _invalid_parameter_noinfo (407A81h) 00405C5D cmp esi,dword ptr [edi+8] 00405C60 jb CVerletPoint::SatisfyConstraints+47h (405C67h) 00405C62 call _invalid_parameter_noinfo (407A81h) 00405C67 mov ecx,dword ptr [esi] 00405C69 mov eax,dword ptr [ecx] 00405C6B mov edx,dword ptr [eax] 00405C6D push ebp 00405C6E call edx 00405C70 cmp esi,dword ptr [edi+8] 00405C73 jb CVerletPoint::SatisfyConstraints+5Ah (405C7Ah) 00405C75 call _invalid_parameter_noinfo (407A81h) 00405C7A add esi,4 00405C7D jmp CVerletPoint::SatisfyConstraints+16h (405C36h) 00405C7F pop edi 00405C80 pop esi 00405C81 pop ebp 00405C82 pop ebx 00405C83 ret
Yikes! What exactly is going on there? Lots of run time error checking, that’s what. Why is it doing this? Well, it’s to make your code “secure”, it makes it so that if something goes out of bounds, then the program will halt, preventing it from doing any harm (or being exploited by a hacker), and allowing you to debug it.
Is this a good thing? It depend on what you want. If you are writing code with lots of convoluted data structures and container interactions, then maybe this is something you want. But for code that operates on a data structure that does not change from frame to frame, then this code is just getting in the way. If it works the first frame, it will work forever. In release mode I do not expect this kind of error checking, and it certainly look like it would hurt performance. It is tests that always return true, skipping over a function that is never called.
So, you can turn it off with:
#ifndef _DEBUG #define _SECURE_SCL 0 #endif
You will need that either defined in every file, or have _SECURE_SCL defined as 0 in the release build process.
Effect: Our code from above now shrinks to:
00405AF0 push esi 00405AF1 push edi 00405AF2 mov edi,ecx 00405AF4 mov esi,dword ptr [edi+20h] 00405AF7 cmp esi,dword ptr [edi+24h] 00405AFA je CVerletPoint::SatisfyConstraints+21h (405B11h) 00405AFC lea esp,[esp] 00405B00 mov ecx,dword ptr [esi] 00405B02 mov eax,dword ptr [ecx] 00405B04 mov edx,dword ptr [eax] 00405B06 push edi 00405B07 call edx 00405B09 add esi,4 00405B0C cmp esi,dword ptr [edi+24h] 00405B0F jne CVerletPoint::SatisfyConstraints+10h (405B00h) 00405B11 pop edi 00405B12 pop esi 00405B13 ret
Much better. six tests have been eliminated. saving at least 12 lines of assembly code. And the big news, the framerate of my blob program goes from 150fps to 170fps.
Check here for an investigation of different ways of iterating over STL vectors:
http://einaros.blogspot.com/2007/02/iteration-techniques-put-on-benchmark.html
So, is turning off _SECURE_SCL a bad cowboy practice? Well for games I think it’s quite reasonable to switch it off for a “FINAL” build (i.e. the one you are going to release to the consumer). Leaving it on might be a useful debugging tool. Just be aware of the potential for significant performance degradation in instances like the one above. That kind of case might be ripe for some kind of refactoring with error checking that is only performed when the container changes.
You can also use unchecked iterators instead of checked iterators, although, the security risks introduced by a game with a flawed loop that crashes occasionally, this isn’t such a big issue and hence disabling the checked implementation probably causes no harm (except increasing the difficulty in debugging some of these crashes). I would suggest using unchecked iterators in your release builds for the high performance components of your code though, as it will tend to skew the profiling of your code when you’re trying to drill down and find those bottlenecks.
Comment by Washu — February 26, 2007 @ 9:09 am
Isn’t that what _SECURE_SCL 0 does? Microsoft Visual C++ versions 8+ have checked iterators on by default. Or is there a way of having them unchecked on a case-by-case basic? Maybe you were thinking of some other port of STL?
Comment by Mick West — February 26, 2007 @ 2:46 pm
In the stdext namespace are unchecked algorithms and iterators.
Comment by Washu — February 26, 2007 @ 3:09 pm
see: http://msdn2.microsoft.com/en-us/library/aa985965(VS.80).aspx
Comment by Washu — February 26, 2007 @ 3:13 pm
[…] to exploit that. I would suggest that if your interested in knowing more about this, check out this article, and the MSDN article on Checking […]
Pingback by CodeBot @ Work » Blog Archive » Exceptions Con’t — September 7, 2007 @ 7:35 am
[…] Invalid parameter info discussion […]
Pingback by Different World » Blog Archive » STL runtime errors — March 18, 2009 @ 6:27 am