Hey,
I have C# code calling a managed C++ dll, which in turn calls an unmanaged C++ static library linked into the managed C++ dll, all compiled with VS 2008 on Windows. I'm calling the following simple code from the unmanaged C++ part
FILE* pf = fopen("text.txt", "rt");
fgets(buf, sizeof(buf) - 1, pf);
and get an exception in _lock_file (_file.c):
if ( (pf >= _iob) && (pf <= (&_iob[_IOB_ENTRIES-1])) )
{
_lock( _STREAM_LOCKS + (int)(pf - _iob) );
pf->_flag |= _IOLOCKED;
}
else
EnterCriticalSection( &(((_FILEX *)pf)->lock) );
where pf->lock is NULL. I've made sure that the text.txt exists, the buffer is valid and everything, that's definitely not the problem. What I understand so far is that in different versions of the CRT Microsoft used two different ways to store locks: In some external array called _iob or directly inside the FILE struct casting FILE to a _FILEX struct containing the actual FILE* and a lock (
see here). What appears to be happening is that fopen and fgets use different versions of the _iob array. fopen creates pf by using an _iob array starting at 0x1..., but fgets uses some _iob at 0x7..., so the "else" code path is taken causing the crash.
Now I can understand the problem when you're calling fopen from one version of the CRT and pass the FILE* into a function compiled against another version of the CRT. That appears to be the problem that most people have. But I'm not doing that. I'm calling fopen and in the next line fgets, so how could those two lines use two different CRT versions? Even more odd, when I replace fgets with fread, it works! Stepping through the code, it also goes into _lock_file, but has the correct _iob array starting at 0x1...
I'm really puzzled here. The project structure is pretty complex and I can't give all the details. But has anyone ever experienced a similar problem? I had similar issues with std::string where the default constructor would crash. I'm assuming that some project settings might be weird, but I don't know where to start. Any help appreciated.
- Lutz