Reinterpret cast generates fatal stack overflow error?

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.
Dave_ShieldsAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
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
AlexNekCommented:
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
Deepu AbrahamR & D Engineering ManagerCommented:
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
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

Dave_ShieldsAuthor Commented:
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
Dave_ShieldsAuthor Commented:
DeepuAbrahamK:
One cannot catch a stack overflow exception with try-catch, as the catch itself would have to use the stack.
0
Dave_ShieldsAuthor Commented:
AlexNek:
How can one see the stack after a stack overflow error?  Happy to try anything.
0
Dave_ShieldsAuthor Commented:
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
jkrCommented:
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
AlexNekCommented:
You search in the wrong place, I think. Randomly fault can be produced by randomly data, like not initialized variable.
0
AlexNekCommented:
>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
Dave_ShieldsAuthor Commented:
jkr:
pFile = (CInternetFile*)mysession.OpenURL(pszURL);
gives
FFFFFFSSSSFFSFSFSFFFSF
0
jkrCommented:
What about verifying the URL parameter?
0
AlexNekCommented:
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
Deepu AbrahamR & D Engineering ManagerCommented:
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
Dave_ShieldsAuthor Commented:
jkr
The URL parameter is the same as an MFC program which connects and reads text.
Dave
0
Dave_ShieldsAuthor Commented:
AlexNek:
I would need more help to  set up and use a logging class.
Dave
0
Dave_ShieldsAuthor Commented:
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
Dave_ShieldsAuthor Commented:
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
AlexNekCommented:
>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
itsmeandnobodyelseCommented:
>>>> 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
Dave_ShieldsAuthor Commented:
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
AlexNekCommented:
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
Dave_ShieldsAuthor Commented:
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
itsmeandnobodyelseCommented:
>>>> 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
AlexNekCommented:
Do you know that under Debug/Exceptions you can set options "Break when an exption is:" Trown?
0
itsmeandnobodyelseCommented:
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
Dave_ShieldsAuthor Commented:
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
itsmeandnobodyelseCommented:
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
Dave_ShieldsAuthor Commented:
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
itsmeandnobodyelseCommented:
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
Dave_ShieldsAuthor Commented:
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
AlexNekCommented:
Did you try to use Bounds Checker or somthing similar?
0
Dave_ShieldsAuthor Commented:
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
Dave_ShieldsAuthor Commented:
AlexNek:
Did you try to use Bounds Checker or somthing similar?

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

0
Dave_ShieldsAuthor Commented:
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
itsmeandnobodyelseCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
AlexNekCommented:
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
itsmeandnobodyelseCommented:
>>>> 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
itsmeandnobodyelseCommented:
>>> 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
AlexNekCommented:
>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
SeanDurkinCommented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.