Cowboy Programming Game Development and General Hacking by the Old West

February 22, 2007

What is invalid parameter noinfo and how do I get rid of it?

Filed under: Cowboy Programming — Mick West @ 6:40 pm

_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.

6 Comments »

  1. 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

  2. You can also use unchecked iterators instead of checked iterators,

    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

  3. In the stdext namespace are unchecked algorithms and iterators.

    Comment by Washu — February 26, 2007 @ 3:09 pm

  4. see: http://msdn2.microsoft.com/en-us/library/aa985965(VS.80).aspx

    Comment by Washu — February 26, 2007 @ 3:13 pm

  5. […] 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

  6. […] Invalid parameter info discussion […]

    Pingback by Different World » Blog Archive » STL runtime errors — March 18, 2009 @ 6:27 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress