Showing Call Stack and Determine which object is not valid LARGE CHUNK OF CODE 
Author Message
 Showing Call Stack and Determine which object is not valid LARGE CHUNK OF CODE

I am getting the following exception and can not bring up a call stack at
any time while running in the de{*filter*}. And most all variables are often
listed as out of scope.  Can someone explain how managed C++ is handling
objects?

If anyone has access to a SQL Server with Northwind left on it, this will
run with plugging your Server Name/IP, user name and password.

System.NullReferenceException: Object reference not set to an instance of an
object.
   at new(UInt32 )
   at StringToNewCharPtr(SByte** newChar, String inStr) in c:\documents and
settings\kory\my documents\visual studio
projects\databasededupetest\databasededupetest.cpp:line 101
   at getDataIntoCharPtr(SqlDataReader myReader, String field, SByte**
currentHolder) in c:\documents and settings\kory\my documents\visual studio
projects\databasededupetest\databasededupetest.cpp:line 117
   at main() in c:\documents and settings\kory\my documents\visual studio
projects\databasededupetest\databasededupetest.cpp:line 172

// This is the main project file for VC++ application project
// generated using an Application Wizard.

#include "stdafx.h"

//Standard
#using <mscorlib.dll>
#using <System.dll>
#using <system.data.dll> // This is required for the ADO.NET Provider
#include <tchar.h>
#include <vector>

using namespace System;
using namespace System::Data;
using namespace System::Data::SqlClient;
using namespace System::Text;

//class DataRecordHolder {
//public:
// DataRecordHolder( void ) {};
// ~DataRecordHolder(void ) {};
//private:
class DataRec {
public:
 DataRec() {
  fName = 0;
  lName = 0;
  title = 0;
  address = 0;
 };
 DataRec( const DataRec& dr ) {
  char* temp = 0;
  if ( dr.fName ) {
   //temp = new char( strlen( dr.fName ) );
   //strcpy( temp, dr.fName );
   //fName = temp;
   fName = dr.fName;
  } else {
   fName = 0;
  }

  if ( dr.lName ) {
   //temp = new char( strlen( dr.lName ) );
   //strcpy( temp, dr.lName );
   //lName = temp;
   lName = dr.lName;
  } else {
   lName = 0;
  }

  if ( dr.title ) {
   //temp = new char( strlen( dr.title ) );
   //strcpy( temp, dr.title );
   //title = temp;
   title = dr.title;
  } else {
   title = 0;
  }

  if ( dr.address ) {
   //temp = new char( strlen( dr.address ) );
   //strcpy( temp, dr.address );
   //address = temp;
   address = dr.address;
  } else {
   address = 0;
  }
 };

 ~DataRec() {
   /*// Crashing on delete - garbage collection might not allow?!?
  if ( fName ) { // clean up
   //delete[] fName;
   fName = 0;
  }
  if ( lName ) { // clean up
   //delete[] lName;
   lName = 0;
  }
  if ( title ) { // clean up
   //delete[] title;
   title = 0;
  }
  if ( address ) { // clean up
   //delete[] address;
   address = 0;
  }
  */
 }
 char* fName;
 char* lName;
 char* title;
 char* address;

Quote:
};

bool StringToNewCharPtr(char*& newChar,  String* inStr) {
 int maxSize = inStr->get_Length();
 if ( 0 >= maxSize ) {
  return false;
 }
 newChar = new char( maxSize + 1 );
 for (int j = 0; j < maxSize; ++j ) {
  newChar[j] =
   (char)inStr->get_Chars(j);
 }
 newChar[maxSize] = '\0';
 return true;

Quote:
}

bool getDataIntoCharPtr( SqlDataReader* myReader, String* field, char*&
currentHolder )
{
 if ( myReader->get_IsClosed() ) {
  return false;
 }
 if ( myReader->get_Item( field ) ) { // throws exception if invalid
  String* data = myReader->get_Item( field )->ToString();
  StringToNewCharPtr( currentHolder, data );
  return true;
 }
 else {
  return false;
 }

Quote:
}

int _tmain(void) // This is the entry point for this application
{
 Console::WriteLine( "Starting Application" );

 SqlConnection      * mySQLConnection;
    SqlCommand         * mySQL;
    SqlDataReader      * myReader;

    try
    {
  StringBuilder* sb = new StringBuilder;
  sb->Append( "Initial Catalog=Northwind;" );
//  sb->Append( "Data Source= SERVER NAME;" );
  sb->Append( "Data Source= SERVER IP;" );
  sb->Append( "User ID= USER;" );
  sb->Append( "Password= PASSWORD" );
  String* connectionString = sb->ToString();

  sb->Remove( 0, sb->Length );
  sb->Append( "SELECT * FROM Employees" );
  String* queryString = sb->ToString();

  Console::WriteLine( "Query String" );
  Console::WriteLine( queryString );

  mySQLConnection = new SqlConnection( connectionString );
        mySQL = new SqlCommand ( queryString, mySQLConnection );

        mySQLConnection->Open (); // Open up the connection
        myReader = mySQL->ExecuteReader ();

  Console::WriteLine( "--- Results : ");
  std::vector<DataRec> RecVec;
  unsigned int entryNum;
  while( myReader->Read() ) {
   ++entryNum;
   DataRec dr;
   sb->Remove( 0, sb->Length );
   if ( 1 == entryNum ) {
    for ( int fieldNum = 0; fieldNum < myReader->get_FieldCount();
++fieldNum ) {
     sb->Append( myReader->GetName( fieldNum ) );
     if ( myReader->get_FieldCount() - 1 > fieldNum ) {
      sb->Append( "-" );
     }
    }
   }
   sb->Append( "\n" );
   getDataIntoCharPtr( myReader, "FirstName", dr.fName );
   getDataIntoCharPtr( myReader, "LastName", dr.lName );
   getDataIntoCharPtr( myReader, "Title", dr.title );
   getDataIntoCharPtr( myReader, "Address", dr.address ); //= "WHERE AM I?"
;
   sb->Append( "Entry # " );
   sb->Append( entryNum );
   sb->Append( "\n" );
   for ( int x = 0; x < myReader->get_FieldCount(); ++x ) {
    sb->Append( myReader->get_Item( x )->ToString() );
    if ( ( myReader->get_FieldCount() - 1 ) > x) {
     sb->Append( "-" );
    }
   }
   sb->Append( "\n" );
   sb->Append( " ---- Entry" );
   RecVec.push_back( dr );
   dr.fName = 0;
   dr.lName = 0;
   dr.title = 0;
   dr.address = 0;
   Console::WriteLine( );
   Console::WriteLine( sb->ToString() );
   Console::WriteLine( );
  }
  Console::Write( "Total Entries = " );
  Console::WriteLine( entryNum );
  Console::Write("RecVec Size = " );
  Console::WriteLine( RecVec.size() );
  if ( RecVec.size() != entryNum ) {
   Console::WriteLine ( "Data Record and Entries sizes are not matching
 " );
  }
  for ( std::vector<DataRec>::iterator recIter = RecVec.begin(); recIter !=
RecVec.end(); ++recIter ) {
   Console::WriteLine( (*recIter).fName );
   Console::WriteLine( (*recIter).lName );
   Console::WriteLine( (*recIter).title );
   Console::WriteLine( (*recIter).address );
  }
    }
    catch( Exception* e )
    {
        Console::Write( e->ToString() );
    }
    __finally
    {
  if ( myReader ) {
   myReader->Close ();
  }
        mySQLConnection->Close();
    }
    return 0;

Quote:
}



Sat, 03 Sep 2005 04:45:03 GMT  
 Showing Call Stack and Determine which object is not valid LARGE CHUNK OF CODE
Comments inline.



Quote:
> I am getting the following exception and can not bring up a call stack at
> any time while running in the de{*filter*}. And most all variables are often
> listed as out of scope.  Can someone explain how managed C++ is handling
> objects?

Hard to say with all the problems your
code induces.  I suggest you cure those,
then see if the de{*filter*} doesn't make a
little more sense of things.

Quote:
> If anyone has access to a SQL Server with Northwind left on it, this will
> run with plugging your Server Name/IP, user name and password.

I believe you will do the debugging.

Quote:
> System.NullReferenceException: Object reference not set to an instance of an
> object.
>    at new(UInt32 )

I will try to tie this to a line of code
below.  It would help if you had marked
it yourself in your post.

Quote:
>    at StringToNewCharPtr(SByte** newChar, String inStr) in c:\documents and
> settings\kory\my documents\visual studio
> projects\databasededupetest\databasededupetest.cpp:line 101
>    at getDataIntoCharPtr(SqlDataReader myReader, String field, SByte**
> currentHolder) in c:\documents and settings\kory\my documents\visual studio
> projects\databasededupetest\databasededupetest.cpp:line 117
>    at main() in c:\documents and settings\kory\my documents\visual studio
> projects\databasededupetest\databasededupetest.cpp:line 172

> // This is the main project file for VC++ application project
> // generated using an Application Wizard.

> #include "stdafx.h"

> //Standard
> #using <mscorlib.dll>
> #using <System.dll>
> #using <system.data.dll> // This is required for the ADO.NET Provider
> #include <tchar.h>
> #include <vector>

> using namespace System;
> using namespace System::Data;
> using namespace System::Data::SqlClient;
> using namespace System::Text;
...
> class DataRec {
> public:
>  DataRec() {
>   fName = 0;
>   lName = 0;
>   title = 0;
>   address = 0;
>  };
>  DataRec( const DataRec& dr ) {
>   char* temp = 0;
>   if ( dr.fName ) {
>    //temp = new char( strlen( dr.fName ) );
>    //strcpy( temp, dr.fName );
>    //fName = temp;
>    fName = dr.fName;
>   } else {
>    fName = 0;
>   }

>   if ( dr.lName ) {
>    //temp = new char( strlen( dr.lName ) );
>    //strcpy( temp, dr.lName );
>    //lName = temp;
>    lName = dr.lName;
>   } else {
>    lName = 0;
>   }

>   if ( dr.title ) {
>    //temp = new char( strlen( dr.title ) );
>    //strcpy( temp, dr.title );
>    //title = temp;
>    title = dr.title;
>   } else {
>    title = 0;
>   }

>   if ( dr.address ) {
>    //temp = new char( strlen( dr.address ) );
>    //strcpy( temp, dr.address );
>    //address = temp;
>    address = dr.address;
>   } else {
>    address = 0;
>   }
>  };

The above is not a valid copy constructor because
both the original and the copy are subject to a
later destructor call, leading to a duplicated
delete on the copied pointers.  Such duplicated
deletions induce undefined behavior and likely
lead to corrupt heap data structures.

Quote:
>  ~DataRec() {
>    /*// Crashing on delete - garbage collection might not allow?!?

As I told you earlier, GC is not the issue.  The
problem is duplicate deletes, as explained above.

I note, also, that there is still no assignment
operator for this class.  That also is going to
lead to problems if the class is ever used in
an assignment.  If you do not want to write a
valid operator=, you should declare one with
private access to prevent improper use of the
one that will otherwise exist by default and
which will produce problems if used at all.

- Show quoted text -

Quote:
>   if ( fName ) { // clean up
>    //delete[] fName;
>    fName = 0;
>   }
>   if ( lName ) { // clean up
>    //delete[] lName;
>    lName = 0;
>   }
>   if ( title ) { // clean up
>    //delete[] title;
>    title = 0;
>   }
>   if ( address ) { // clean up
>    //delete[] address;
>    address = 0;
>   }

There is no need to test pointers against 0
prior to delete or delete[].  The runtime does
that for you.  Few C++ programmers duplicate
that code.

Quote:
>   */
>  }
>  char* fName;
>  char* lName;
>  char* title;
>  char* address;
> };

> bool StringToNewCharPtr(char*& newChar,  String* inStr) {
>  int maxSize = inStr->get_Length();

I suspect this is the line at which the
null reference exception is thrown.

Quote:
>  if ( 0 >= maxSize ) {
>   return false;
>  }
>  newChar = new char( maxSize + 1 );

The above statement does not allocate
an array of char's.  It allocates a
single char initialized to maxSize+1.
For any value of maxSize > 1, the code
below induces undefined behavior, and
probably clobbers heap data structures
by overwriting past the allocation.

This function is bound to leak memory
if used upon an incoming newChar that
already holds an allocation.  It would
be smarter to free the existing one as
indicated by a non-zero incoming value.

- Show quoted text -

Quote:
>  for (int j = 0; j < maxSize; ++j ) {
>   newChar[j] =
>    (char)inStr->get_Chars(j);
>  }
>  newChar[maxSize] = '\0';
>  return true;
> }

> bool getDataIntoCharPtr( SqlDataReader* myReader, String* field, char*&
> currentHolder )
> {
>  if ( myReader->get_IsClosed() ) {
>   return false;
>  }
>  if ( myReader->get_Item( field ) ) { // throws exception if invalid
>   String* data = myReader->get_Item( field )->ToString();

I note that the possible null returns from
get_Item(string) are not handled except by
also throwing a null reference exception.

Quote:
>   StringToNewCharPtr( currentHolder, data );
>   return true;
>  }
>  else {
>   return false;
>  }
> }

[in main() or similar]

Quote:
>   std::vector<DataRec> RecVec;
>   unsigned int entryNum;

It appears that entryNum is not initialized
before it is used.  The compiler will warn
about this at appropriate warning levels.

Quote:
>   while( myReader->Read() ) {
>    ++entryNum;
>    DataRec dr;
>    sb->Remove( 0, sb->Length );
>    if ( 1 == entryNum ) {
>     for ( int fieldNum = 0; fieldNum < myReader->get_FieldCount();
> ++fieldNum ) {
>      sb->Append( myReader->GetName( fieldNum ) );
>      if ( myReader->get_FieldCount() - 1 > fieldNum ) {
>       sb->Append( "-" );
>      }
>     }
>    }
>    sb->Append( "\n" );

I'm surprised that compiles.  There is no
public overload for a char * argument in the
StringBuilder.Append(...) set.  The proper
literal would be S"\n" .

- Show quoted text -

Quote:
>    getDataIntoCharPtr( myReader, "FirstName", dr.fName );
>    getDataIntoCharPtr( myReader, "LastName", dr.lName );
>    getDataIntoCharPtr( myReader, "Title", dr.title );
>    getDataIntoCharPtr( myReader, "Address", dr.address ); //= "WHERE AM I?"
> ;
>    sb->Append( "Entry # " );
>    sb->Append( entryNum );
>    sb->Append( "\n" );
>    for ( int x = 0; x < myReader->get_FieldCount(); ++x ) {
>     sb->Append( myReader->get_Item( x )->ToString() );
>     if ( ( myReader->get_FieldCount() - 1 ) > x) {
>      sb->Append( "-" );
>     }
>    }
>    sb->Append( "\n" );
>    sb->Append( " ---- Entry" );
>    RecVec.push_back( dr );

Note that dr is copied here.  Note also
that it is destructed once per loop,
along with the pointers copied by the
invalid copy constructor.  (That is why
you found the next few lines to "help".)

Quote:
>    dr.fName = 0;
>    dr.lName = 0;
>    dr.title = 0;
>    dr.address = 0;

With a proper copy constructor, the above
member resets would not be necessary.

- Show quoted text -

Quote:
>    Console::WriteLine( );
>    Console::WriteLine( sb->ToString() );
>    Console::WriteLine( );
>   }
>   Console::Write( "Total Entries = " );
>   Console::WriteLine( entryNum );
>   Console::Write("RecVec Size = " );
>   Console::WriteLine( RecVec.size() );
>   if ( RecVec.size() != entryNum ) {
>    Console::WriteLine ( "Data Record and Entries sizes are not matching
>  " );
>   }
>   for ( std::vector<DataRec>::iterator recIter = RecVec.begin(); recIter !=
> RecVec.end(); ++recIter ) {
>    Console::WriteLine( (*recIter).fName );
>    Console::WriteLine( (*recIter).lName );
>    Console::WriteLine( (*recIter).title );
>    Console::WriteLine( (*recIter).address );
>   }
>     }
>     catch( Exception* e )
>     {
>         Console::Write( e->ToString() );
>     }
>     __finally
>     {
>   if ( myReader ) {
>    myReader->Close ();
>   }
>         mySQLConnection->Close();
>     }
>     return 0;
> }

If you do not understand the above comments,
please either ask enough questions to allow
you to learn what is wrong here, or stop
coming here hoping for a more magical
solution to this program's problems.

--
-Larry Brasfield
(address munged, s/sn/h/ to reply)



Sat, 03 Sep 2005 10:36:18 GMT  
 Showing Call Stack and Determine which object is not valid LARGE CHUNK OF CODE
Thanks. Can you further explain what a valid copy constructor entails?

What must a valid copy and assignment ctors do to work with managed c++?

class foo{
    foo(){
c = 0;

Quote:
}

    ~foo(){
c = 0;
Quote:
}

    foo( const foo& f ) {
c = new char(strlen(f.c) );
c = &f.c;
Quote:
}

    foo& operator= ( const foo& f ) {
c = new char(strlen(f.c) );
 c = &f.c;
return *this;
Quote:
}
    char* c
}



Sun, 04 Sep 2005 00:28:08 GMT  
 Showing Call Stack and Determine which object is not valid LARGE CHUNK OF CODE


Quote:
> Thanks. Can you further explain what a valid copy constructor entails?

At a minimum, it creates a copy which continues to
satisfy the class invariants.  Your class design
may establish other invariants, but one that must
always exist is that the destructor can run (once
per object) without inducing undefined behavior.

Quote:
> What must a valid copy and assignment ctors do to work with managed c++?

I doubt the following class is managed, so I have
to wonder whether you consider that question
relevant to the following code.  There are no user-
-defined copy constructors or assignment operators
in managed classes.  (And a clue that foo is not
managed is that the compiler let you define them.)

Quote:
> class foo{
>     foo(){
> c = 0;
> }
>     ~foo(){
> c = 0;
> }
>     foo( const foo& f ) {
> c = new char(strlen(f.c) );
> c = &f.c;

That last (above) statement merely copies
the char pointer.  What you could do is:
   c = new char[strlen(f.c) + 1];
   strcpy(c, f.c);
Note carefully that I have changed your
parenthesis to square brackets.  I tried
to inform you of that problem earlier,
but it did not take for some reason.

Quote:
> }
>     foo& operator= ( const foo& f ) {
> c = new char(strlen(f.c) );
>  c = &f.c;

The same treatement is required here, but
you should first delete[] the old value of
c.  Try to remember this:  A constructor
creates a new object from raw memory.  An
assignment changes the value of an object
that already exists.

Quote:
> return *this;
> }
>     char* c
> }

You really ought to consider using std::string
instead of char pointers.  If you did, then a
correct copy ctor and operator= would be created
for you, automatically, by the compiler.  If you
are trying to learn the nitty gritty details of
manual memory management, then your raw char
pointers may make sense.  If that is the case,
some study of C++ "special member functions"
would be in order.  If that is not the case,
if you are trying to get a useful and reliable
result, std::string is your friend and definitely
your employer's friend.

--
-Larry Brasfield
(address munged, s/sn/h/ to reply)



Sun, 04 Sep 2005 07:52:55 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. Call Stack not showing up?

2. Call stack never shows our own code

3. Determining When an Object is valid

4. Crash Call Stack shows NTDLL several times

5. Good malloc routine for large chunks

6. Crashing when sending a pointer to a large chunk of shared memory via an IPC SendMessage

7. UserControl does not show on running form and properies do not show

8. IIS Automation object: how do I get a call stack when it crashes

9. FOREACH does not determine Object type?

10. Calling stack vanish after using asemly code

11. Calling stack vanish after using asemly code

12. Print Preview does not show the clipped objects.

 

 
Powered by phpBB® Forum Software