Solved

Reinterpret cast generates fatal stack overflow error?

Posted on 2007-03-17
43
684 Views
Last Modified: 2008-05-10
I am using MFC and managed code in the same file.
When using a reinterpret_cast to cast an internet connection pointer, I get a fatal stack overflow error.  The problem is intermittent in that it might fail twice, and then on the next 2 tries it will work.  The code is:
CInternetSession mysession;
CInternetFile* pFile = NULL;
try
   {
   // We know for sure that this is an Internet File so the cast is safe
   cout << "Inside TRY BLOCK" << endl;
   pFile = NULL;
   pFile = reinterpret_cast<CInternetFile*>(mysession.OpenURL(pszURL));
   cout << "pFile in TRY is : " << pFile << endl;
   }

The output statements are for runtime diagnostics.
0
Comment
Question by:Dave_Shields
  • 17
  • 10
  • 8
  • +3
43 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 18741249
The cast itself for sure will not cause any ovreflow problems. Actually, it is not even necessary. Just make that

   pFile = mysession.OpenURL(pszURL);

Are you sure the error code is not misinterpreted?
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18741401
I'm personally would never casting up for foreign code in addition
"You never create a CInternetFile object directly."
http://msdn2.microsoft.com/en-us/library/3c69cwt5(VS.80).aspx
What is your stack look like when error come? I agree with Jkr - problem is somewhere else.
0
 
LVL 11

Expert Comment

by:DeepuAbrahamK
ID: 18742862
Looks like some exceptions are happening in this case? How are you calling the try-catch, are you calling goto? This problem is not with reinterpret_cast as I also agree with  the previous posts.Some code is getting called in a loop.Use CInternetException class. Put try- catch block for all the functions.
Best Regards,
DeepuAbrahamK
0
 

Author Comment

by:Dave_Shields
ID: 18743914
JKR
When the code is compiled without the cast it doesn't compile, but gives the error

error C2275: 'CInternetFile' : illegal use of this type as an expression                                    
0
 

Author Comment

by:Dave_Shields
ID: 18743920
DeepuAbrahamK:
One cannot catch a stack overflow exception with try-catch, as the catch itself would have to use the stack.
0
 

Author Comment

by:Dave_Shields
ID: 18743928
AlexNek:
How can one see the stack after a stack overflow error?  Happy to try anything.
0
 

Author Comment

by:Dave_Shields
ID: 18743938
ALL
This is an intermittent problem.  How this is possible with a computer program I don't know.
Here are my results.  F = fail; S = succeed
reinterpret_cast
FFSSSFFFSFFFFFSFFFFSSF
old cast
FFFFFFSSSSFFSFSFSFFFSF
dynamic_cast
SSFFFSFFFSFFFFFFFSSFF
0
 
LVL 86

Expert Comment

by:jkr
ID: 18743953
Hm, 'OpenURL()' returns a 'CStdioFile*', which is a base class for a 'CInternetFile', thus the conversion should work implicitly. Does

pFile = (CInternetFile*)mysession.OpenURL(pszURL);

work? Also, ist the URL argument valid when that happens? You could test that using

ASSERT(IsBadStringPointer(pszURL,REASONABLE_MAX_VALUE));
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18743961
You search in the wrong place, I think. Randomly fault can be produced by randomly data, like not initialized variable.
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18743968
>How can one see the stack after a stack overflow error
Under debug mode in the Call  Stack Window. You can see a long, long list of calls. I saw it already.
0
 

Author Comment

by:Dave_Shields
ID: 18744125
jkr:
pFile = (CInternetFile*)mysession.OpenURL(pszURL);
gives
FFFFFFSSSSFFSFSFSFFFSF
0
 
LVL 86

Expert Comment

by:jkr
ID: 18744141
What about verifying the URL parameter?
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18744170
Try to ceate a logging class something like it.

CMyLog {
  public:
      CMyLog(cons char* pText) { m_Text = pText; //write m_pText in file - Started}
      ~CMyLog() {//write m_Text in file, Finished}
  private:
   CString m_Text'
};

{
     CMyLog("Debug point 1");
......

}
0
 
LVL 11

Expert Comment

by:DeepuAbrahamK
ID: 18744741
Stack would get corrupted if you have any goto statement in catch (If it is not handled properly).If the connection is failing why don't you write the code in such a way that it try a few attempts till it connects.I remember I had done some time back while writing an ftp client in windows which connects to mainframe system.Writing logs/audit trail is also not a bad idea.
Best Regards,
DeepuAbrahamK
0
 

Author Comment

by:Dave_Shields
ID: 18748189
jkr
The URL parameter is the same as an MFC program which connects and reads text.
Dave
0
 

Author Comment

by:Dave_Shields
ID: 18748207
AlexNek:
I would need more help to  set up and use a logging class.
Dave
0
 

Author Comment

by:Dave_Shields
ID: 18748234
DeepuAbrahamK:
The catch code follows:
catch (CInternetException* pEx)
{
   // If anything went wrong catch it here
   pscUnconnectable->Add(path);
   cout << "Problem setting up pFile"  << endl;
   cout << pEx << endl;
   pFile = NULL;
}      
0
 

Author Comment

by:Dave_Shields
ID: 18748307
ALL
The code is from Kate Gregory's book "Special edition using Visual C++.Net, Capter 10, page 310 - MFC applicaion called Query.  It works well.  As a matter of fact if it receieves a 404 error, it will read and display the error page.
The only difference is that Query is a totally MFC project, and my code is in a combination of MFC and managed code.
The main mystery is that my project will work randomly, and fail equally randomly in successive trials.  I could understand better if it failed every time.   But repeated trials with no changes results in random success and failure.
Perplexed, Dave
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18748540
>I would need more help to  set up and use a logging class.
It is no problem but is very easy class. You can realize it with cout too and you need only one line instead two.
cout << "Inside TRY BLOCK" << endl;
....
 cout << "pFile in TRY is : "  << endl;

In my opinion it is important to know from which place apllication is crashed.


0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18748583
>>>> returns a 'CStdioFile*', which is a base class for a
>>>> 'CInternetFile', thus the conversion should work implicitly.
No, if  'CInternetFile' is derived from ''CStdioFile' you can't assign a CStdioFile* to a  CInternet* without a cast. In case the memory wasn't already corrupted, a dynamic_cast is required between pointers of derived classes. A C cast also should do it. A reinterpret cast would ignore virtual pointer tables what isn't appropriate here (but nevertheless should give no problems here as no multiple inheritance is involved).

You easily should see that the cast is not the problem by replacing

    CInternetFile* pFile = NULL;

by

     CStdioFile* pFile = NULL;

You should get the same kind of failures/success as with using the cast. I would think that it is a problem of mixing managed and unmanaged code but without further information it is only a shot from the hip.

Regards, Alex
 
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 

Author Comment

by:Dave_Shields
ID: 18751158
itsmeandnobodyelse:
When I substitute CStdioFile* for CInternetFile* I get
error C2664: 'ScriptRemover' : cannot convert parameter 1 from 'CStdioFile *' to 'CInternetFile *'
failure rate is about the same for a C style cast.  A function style cast will not compile.
If the garbage collector were to move an MFC pointer at the wrong time, intermittent failure would be the result.  Is it possible to __pin an MFC pointer such as CInternetFile*??

0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18751280
I can't imagine such an error in this construction
CStdioFile* pFile = NULL;
   pFile = mysession.OpenURL(pszURL);

Do you run your code in additional thread?
Where is exatly definition of mysession: in the function or as data member in your application class?
0
 

Author Comment

by:Dave_Shields
ID: 18751680
AlexNek
I am not using threads in the program.  It is not a very long program, so it is written as one long program with few functions.  The code that I've quoted is in the "Main" part of the program.
I have a screenshot of the debug output.  It is at
http://aquilifer-web-design.com/query_error_mar-19-2007.htm
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18751771
>>>> error C2664: 'ScriptRemover' : cannot convert parameter 1 from
>>>> 'CStdioFile *' to 'CInternetFile *'
Without casting you can't call member functions of CinternetFile that were not virtual. The purpose of the substuitution was not to provide a fully working alternative but to show that the problem exists without cast as well.
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18751898
Do you know that under Debug/Exceptions you can set options "Break when an exption is:" Trown?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18754399
The first exception you got is an access violation (0x00000005). That is a typical for illegal pointer access, e. g. using a NULL pointer or work with a pointer that already was deleted. The latter would explain why it works sometimes. If the memory the (invalid) pointer was pointing to was not reused it works. Otherwise it fails. Try that what AlexNek had suggested. Go to the Debug\Exceptions page and select "Access Violation" from the list of general exceptions. Then, you can set that the debugger will stop immediately when the exception occurs. Run your prog and when it breaks check the call stack to find out what statement and what pointer have caused the (first) access violation. Also check the this pointer which might be invalid as well.

Regards, Alex
 
0
 

Author Comment

by:Dave_Shields
ID: 18756632
itsmeandnobodyelse:
I set the debug/exceptions as you suggested.
I the ran the program from Debug > Start 15 times without failure.
I the ran the program from Debug > Start without debugging.  It failed the first time.  The debug output is at http://www.aquilifer-web-design.com/query_debug_output_mar20-2007.htm
I don't know enough to read it.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18757305
Yes, that is the problem with invalid pointers. If you change something - here to force the debugger to watch on the first-chance exceptions - it changes its memory management ... and the error wasn't reproducable because of that ...

The debug output simply means that there is no error (beside of not loading some debugger symbols for system libraries).

Ok, I hoped to get the statement where the wrong pointer was used but if the error doesn't occur, we need to make a different approach. Add after any statement which might crash because of a pointer or call the following statement:

    <original statement>
    OutputDebugString("<original statement> \n";

e. g.  

     pFile = reinterpret_cast<CInternetFile*>(mysession.OpenURL(pszURL));
     OutputDebugString("pFile = reinterpret_cast<CInternetFile*>(mysession.OpenURL(pszURL));\n");

Instead of outputting the statement you also can output a number which was incremented for the next statement:

     pFile = reinterpret_cast<CInternetFile*>(mysession.OpenURL(pszURL));
     OutputDebugString("20\n");
     cout << "pFile in TRY is : " << pFile << endl;
     OutputDebugString("21\n");

These output statements hwich show in the output window of the IDE should tell how far it comes before crash. Try to reproduce the crash. Check where the output stops and evaluate the next statement where the output wasn't shown. Set a breakpoint there and examine all variables. If it is a call step into until crash. If the function you stepped in is your function you may use more OutputDebugString calls to spot the statement which crashes.

What you can do additionally is to check *all* member variables were initialized in the constructor. Initialize *all* local variables espcially pointers. Never use a pointer in two containers. If using a pointer to a local variable never return that pointer cause the object was deleted after leaving the function and the pointer becomes invalid.


Regards, Alex
 

0
 

Author Comment

by:Dave_Shields
ID: 18757310
itsmeandnobodyelse:
I found the pFile had not been closed or deleted, so I added that code to stop the memory leak.
Ran the program from Debug > Start 14 times without failure.
From Debug > Start without debugging it failed on the fourth attempt.
The stack output is at:
http://www.aquilifer-web-design.com/query_error_stack_mar20-2007.htm
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18758849
The stack overflow is due to a NULL pointer (function), which you can see in the call stack.

In one of your previosu posts we saw two first-chance exceptions ("access violation"). First chance exceptions were exceptions caught by a try catch block. So, they normally can ignored cause the developer added code to handle them. However access violation means use of invalid or NULL pointer what hardly can be handled properly even if it is in a try catch handler. Still you need to find out what pointer goes invalid.

>>>> so I added that code to stop the memory leak.
Your main problem is not memory leaks but the contrary - a pointer which has no valid allocation, either cause it was freed or either it was not properly initialized.

>>>> without debugging it failed on the fourth attempt.
That looked like timing problems. You don't have a crash when you slow down things by the debugger. You said you have no threads? But it really looked like a multi-threading issue. Maybe when calling unmanaged code from managed code. Can you tell how you do that? Is the code above running in a dll? How does it get it's inputs and how does it return the results?

Regards, Alex
0
 

Author Comment

by:Dave_Shields
ID: 18758902
itsmeandnobodyelse:
At the moment I cannot step through the code, as the debugger just runs through it all, right through breakpoints.  Besides it doesn't fail in debugger mode.
It only fails when starting without debugging.
When it fails, the output lines indicate that the trouble lies with
pFile = reinterpret_cast<CInternetFile*>(mysession.OpenURL(pszURL));
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18759130
Did you try to use Bounds Checker or somthing similar?
0
 

Author Comment

by:Dave_Shields
ID: 18759317
itsmeandnobodyelse:
The interlink between managed and unmanaged code is solely through CString and String*.  CString to interface with MFC, and String* to handle the strings when files are read.
//  CString  to String*
String* cstrtostrp(CString cstr)
{
      String* str(cstr);
      return str;
}
//  String* to CString
CString strptocstr(String *str)
{
      CString Cstr3(str);
      return Cstr3;
}
I can't see any difficulty on this front, as everything looks fine when printed out.

One interesting point - the Compiler will not let me close session with session.Close(), as it should.
Any idea why??
0
 

Author Comment

by:Dave_Shields
ID: 18759330
AlexNek:
Did you try to use Bounds Checker or somthing similar?

I'm not familiar with Bounds Checker.  will research a little.

0
 

Author Comment

by:Dave_Shields
ID: 18760787
itsmeandnobodyelse:
By trial and error I have found that when the following code is commented out, the program works 20 times without fail.  when the code is included, it will only run 7 or 8 times before failing.
for (i=0; i < n; i++)
      {
            dprevious[i] = 0.0;
            assert (i < n);
            Console::WriteLine(S"Previous # {0}\n", __box(i) );
      }
Any idea why??
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 250 total points
ID: 18762263
Only a shoot from the hip.

Console::WriteLine(S"Previous # {0}\n", __box(i) );

most probably allocates some new memory what spoils one of the already freed pointers. Did you try OutputDebugString? I doubt that the cast statement you get showed after crash is responsible. The problem with handled (first-chance) exceptions is that the debugger was much too late to find out what had happened. If you work with a invalid pointer waht is my assumption you may be able to run thru hundreds of statements before finally you end at a NULL pointer.

>>>> __box(i)

What is  that? Is it a private variable or supplied by the system?

>>>> assert (i < n);
that is nonsense. The loop counter never will reach the loop boundaries. Remove that assert statement.
You'll better check that n is valid and that both dprevious and __box have been allocated for at least n entries.

Regards, Alex
 
0
 
LVL 16

Assisted Solution

by:AlexNek
AlexNek earned 250 total points
ID: 18762448
if function __box(i) do nothing with memory then this code can only be "an offset"  to really "bad" code.
Try to comment other parts of programm up to it "works" 100% safe. You can try from big chunks and then make it shorter.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18762649
>>>> up to it "works" 100% safe
How will you make that sure? Even if it crashes once a month it most likely is not acceptable. You better would try to reliable make it crash rather than commenting statements which look suspicious. For example you can clear all member data (set to 0 or space)  prior to delete a class instance. Set the value 0xdeaddead to all pointers that were deleted. If you see that address later in the debugger you know it was a deleted pointer which made the trouble. You also could set the debugger to stop immediately at access violation *and* make automatic tests - say 1000 or 10000 calls - where maybe one will crash and show you the pointer that was wrong.

Regards, Alex
 
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 18762706
>>> The interlink between managed and unmanaged code is solely through CString
I don't know much of managed code but the first thing when mixing managed and unmanaged is that the unmanaged runs in a separate dll. Can you post the exported interface of that dll? You know that allocating memory in your prog and deleting that memory in the dll most likely doesn't work? So, all interfaces should provide a fxed sized buffer (string, array, variables)  where the receiving dll makes no changes of the size. E. g. a CString passed by pointer or by reference to the dll may *not* be expanded within the dll cause that definitively makes problems when freeing the memory. Moreover, it also makes problems in the dll cause CString works with static members which exist both in the dll and in the managed prog (or marshaler). So CStrings should be passed by value (the dll makes a copy then) or by const pointer or const reference only. If you want to receive data via a CString, you need to allocate a big enough buffer at the sender side, e. g. by CString::GetBuffer(). The dll only may use the passed buffer and never try to increase it, e. g. by operator+=.

Regards, Alex
0
 
LVL 16

Expert Comment

by:AlexNek
ID: 18763038
>How will you make that sure? Even if it crashes once a month it most likely is not acceptable.
I would be agree with you if we are talking in general. In general I'll never be 100% sure that our program has no more errors. But now we want to catch only one error. We know that this error must to come in X tries if it not come we can decide that this errornot presewntin code. Ok, ok our decision can we wrong but possibility to isolate the wrong part of code is very high, I think. Of course, I can suggest this method only if any others give us nothing.
0
 
LVL 6

Expert Comment

by:SeanDurkin
ID: 21436116
No comment has been added to this question in more than 21 days, so it is now classified as abandoned.

I will leave the following recommendation for this question in the Cleanup Zone:
  Split: itsmeandnobodyelse {http:#18762263} & AlexNek {http:#18762448}

Any objections should be posted here in the next 4 days. After that time, the question will be closed.

Sean
EE Cleanup Volunteer
0

Featured Post

Zoho SalesIQ

Hassle-free live chat software re-imagined for business growth. 2 users, always free.

Join & Write a Comment

In Q3 of last year, Experts Exchange introduced a new Messaging System, allowing any member to communicate directly with other members. During an especially long thread with a member, I wanted to go back to previous messages in the exchange to re…
A high-level exploration of how our ever-increasing access to information has changed the way we do our jobs.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now