LinuxQuestions.org
Visit the LQ Articles and Editorials section
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 12-07-2012, 03:47 PM   #1
gothrog
Member
 
Registered: Jun 2004
Distribution: Yellow Dog, Fedora, RedHat, Centos, Ubuntu, Suse Linux
Posts: 98

Rep: Reputation: 15
void pointer casting of vector within a vector C++


Hi All,

I've been trying to figure out why one program keeps having a random crash.

I have this common code that is used for 4 of the programs and use generics to trigger how threads, containers, listeners instantiate. The only real difference for each instantiation is what data structure gets used.

All the programs launch, run, and can go through all instances of unit testing with out a failure. Except for the first iteration of a certain testcase. Later iterations will work as long as I don't recompile.

The one and "only" data structure that segfaults during run time contains a vector within a vector. I use void* pointer to pass the location and then recast it within the common code. Since I can't find anything that would be causing this to crash I'm making an assumption that maybe some how I'm doing the explicit cast wrong and there is a loss of a proper memory allocation.

My question is should I be using dynamic_cast or reinterpret_cast instead of how I do it now?

Example of some of the code used in the casting.
Code:
Common Code
VectorTemplate.h
   void Insert( typename vector<T>::iterator it, const T& data );

.h
   void *m_pforDataType;

.cpp
void TheVector::Insert( void *itptr, void *dataptr )
{
....
    else if ( 2 == m_vectorDataType )
   {
      VectorTemplate<TheDataType::DT1> *rxVector = 
         (VectorTemplate<TheDataType::DT1>*)m_pforDataType;

      TheDataType::DT1 *pstrValue = (TheDataType::DT1*)dataptr;

      vector<TheDataType::DT1>::iterator *pIt = 
         (vector<TheDataType::DT1>::iterator*)itptr;
      vector<TheDataType::DT1>::iterator it = *pIt;
      
      rxVector->Insert(it,*pstrValue);
   }
It crashes when it sets a string "actionName" to nothing.
Error:
Code:
Program received signal SIGSEGV, Segmentation fault.
[Switching to thread 7972.0x1f84]
0x6c4b8d40 in cygstdc++-6!_ZNSs6assignEPKcj () from /usr/bin/cygstdc++-6.dll
(gdb) up
#1  0x6c4ba125 in cygstdc++-6!_ZNSsaSEPKc () from /usr/bin/cygstdc++-6.dll
(gdb) up
#2  0x00448735 in TheDataType::DT1::clear (this=0xd58101)
    at ../Common/TheDataType.h:161
161              actionName = "";

Last edited by gothrog; 12-07-2012 at 03:51 PM.
 
Old 12-08-2012, 08:59 AM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,523

Rep: Reputation: 332Reputation: 332Reputation: 332Reputation: 332
It's hard to tell what you are doing, much less whether you have embarked on a bad design.

Nevertheless, this piece of code stood out:
Code:
vector<TheDataType::DT1>::iterator it = *pIt;
Try to see if you can change that to:
Code:
vector<TheDataType::DT1>::iterator& it = *pIt;     // Note the change in the declaration
You should consider using C++-style casting in lieu of C-style. As for the results, from experience I have witnessed, they probably will not offer you anything better, with the exception of dynamic_cast which will return a null-pointer should the cast fail to promote a base-class to a derived-class.
 
1 members found this post helpful.
Old 12-08-2012, 09:13 AM   #3
johnsfine
Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,107

Rep: Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114
I'm not going to try to understand the fragment of code that was posted. I doubt it contains the right information and anyway I can make a pretty good guess at the cause of the bug without understanding the details.

You are using an iterator into a vector far from where the iterator was produced and I think you are modifying the vector in related code.

You should know that a vector iterator is no longer valid if you insert anything anywhere in the vector after you produce the iterator.


I don't think you showed enough of the relevant code for me to see whether, after producing the iterator, you made some change to the vector which makes the iterator invalid. But that guess is a perfect fit for the problem you describe and is a very likely bug in the style of code you seem to have written.

But regarding the question you asked:
Quote:
Originally Posted by gothrog View Post
My question is should I be using dynamic_cast or reinterpret_cast instead of how I do it now?
A C style cast to or from a void* is always functionally a reinterpret_cast. As a matter of style and clarity, I always use a reinterpret_cast instead of a C style cast when I want to reinterpret a pointer. That way anyone reading the code can be clear on what I intended.

When casting from a void*, you are required to cast to exactly the same type that you had cast the void* from. For example, given
class A : public B { ... };
I have seen many examples where someone casts an A* to a void* and then casts that void* to a B*
That code often works, but is always wrong. It may stop working due to a distant change that has little evident connection to the code that stops working.

When you must cast from A* to void* to B*, you need to use a double cast to get from void* to B* (reinterpret_cast void* to A* then static_cast A* to B*)

Quote:
It crashes when it sets a string "actionName" to nothing.
That crash almost certainly implies the this pointer is stale (points to an object that has been moved/deleted).

I don't get much info from the cryptic gdb output, so I don't know where the call to clear() is that passed the state pointer to clear(). You didn't show us source code for any call to clear(). Do you know where that call to clear() is in your source code? If not, how many places call that class's clear() function?

After you find the right call to clear(), how does it get the object pointer? Is that pointer or iterator stale? Or did it get that directly out of a nested vector object implying the pointer or iterator to the whole nested vector object was state?

Last edited by johnsfine; 12-08-2012 at 09:39 AM.
 
1 members found this post helpful.
Old 12-09-2012, 12:09 AM   #4
gothrog
Member
 
Registered: Jun 2004
Distribution: Yellow Dog, Fedora, RedHat, Centos, Ubuntu, Suse Linux
Posts: 98

Original Poster
Rep: Reputation: 15
Thank you for your responses.

I used the reinterpret_cast with static_cast. I read that you are not supposed to use reinterpret_cast with a void*. Can I just use static_cast without the additional reinterpret_cast?

The casting is really just going from A -> void* -> A. There is no conversion of the datatype to a different datatype. My apologize if I confused you with asking the questions about dynamic and reinterpret casts.

Quote:
You should know that a vector iterator is no longer valid if you insert anything anywhere in the vector after you produce the iterator.
I went back to check this. I know that I avoided this possible scenario by launching the testcase in a serial order and I implemented the following code to get out of the iterator as soon as possible. However I'm not sure if it is done completely right. I know that an "insert" will ruin the iterator, but is it still possible to change values within the element without it causing a problem? I originally thought it was fine, but I'm double checking every possibility.

Code:
   TheVector *pVector = pRSThreadDev->m_pPOI->TT_POI_Content->m_pTA->m_ptheVector;
   TheDataType::DT1 *pDTCheck = NULL;

   vector<TheDataType::DT1>::iterator itBegTest =
      pVector->getBeginDT1();
   vector<TheDataType::DT1>::iterator itEndTest =
      pVector->getEndDT1();

   unsigned short ElemIndex = 0;
   bool found = false;
   for ( itBegTest;  itBegTest < itEndTest && !found; ++itBegTest )
   {
      // Increase performance, only reference pointer
      if ( uniqueMsgID == (*itBegTest).MsgID )
      {
         found = true;
         pDTCheck = &(*itBegTest);    // <------ Can this cause an issue by using the iterator like this?
      }
      else
         ElemIndex++;
   }

   // Making assignment change to an attribute in the element.
   if (found)
     pDTCheck->value = 2; 

   //  Leave the element in the vector and stop pointing to it
   pDTCheck = NULL;
   
   ....
   // Eventually something will trigger the DT1 datatype element to be removed through the following call.
   pRSThreadDev->m_pPOI->removePOI(uniqueMsgID);

   // The removePOI function does the above code, except change the assignment pDTCheck->value=2 to below:
   pVector->Erase(ElemIndex);

   Vector.cpp
   void TheVector::Erase( unsigned short index )
   ...

   VectorTemplate<TheDataType::DT1> *rxVector = 
      reinterpret_cast<VectorTemplate<TheDataType::DT1>*>(m_pforDataType);
   VectorTemplate<TheDataType::DT1> *rxVector2 = 
      static_cast<VectorTemplate<TheDataType::DT1>*>(rxVector);
   rxVector2->Erase(index);

   VectorTemplate.h
      inline void Erase(unsigned short index)
      {
         if ( Size() > 0 )
         {
            // set unlock handler and lock the state
            pthread_mutex_lock(&m_tLock);
            while (m_theVector.empty())
            {
               pthread_cond_wait(&m_ReadyEvent,&m_tLock);
            }

            m_theVector.erase(m_theVector.begin()+index);

   TheDataType.h
   //  Example Clear:
      void clear()
      {
         actionName = "";
         foundAtDepth = 0;
         elementfrequency = 0;
         probability = 0;
      }
Note: The custom clears are not meant to remove elements, just zero out the attribute values.

Last edited by gothrog; 12-09-2012 at 12:12 AM.
 
Old 12-09-2012, 07:16 AM   #5
johnsfine
Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,107

Rep: Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114Reputation: 1114
Quote:
Originally Posted by gothrog View Post
I read that you are not supposed to use reinterpret_cast with a void*.
Do you have a URL where you read that? I'd like to give an opinion on whether you misunderstood it, or whether the author was giving incorrect advise or just advocating a style I disagree with.

Quote:
Can I just use static_cast without the additional reinterpret_cast?

The casting is really just going from A -> void* -> A.
Then there is no reason to involve a static_cast at all.

A C cast will run the same as a reinterpret_cast. A reinterpret_cast is only better because it communicates the actual operation to anyone reading the code.
Quote:
The custom clears are not meant to remove elements, just zero out the attribute values.
What custom clears? I still don't see any call to clear() in the code you posted, just the definition of clear().

The crash occurred because a call to clear used a stale pointer or iterator for the object to be cleared. You should start at that call to clear() and try to back track to why that pointer or iterator was stale.

Quote:
Code:
pDTCheck = &(*itBegTest);    // <------ Can this cause an issue by using the iterator like this?
...
pDTCheck->value = 2;
That is fine. Converting an iterator to a pointer with &* subverts a lot of checking some debugging environments do for whether you are using a stale iterator (in my experience that checking is often flawed and needs to be subverted). But functionally it doesn't change whether the subsequent use is OK.

That time, you did a read only scan of the vector, then used a pointer captured during that scan. So the pointer is not stale.

Last edited by johnsfine; 12-09-2012 at 07:24 AM.
 
1 members found this post helpful.
Old 12-10-2012, 05:01 PM   #6
gothrog
Member
 
Registered: Jun 2004
Distribution: Yellow Dog, Fedora, RedHat, Centos, Ubuntu, Suse Linux
Posts: 98

Original Poster
Rep: Reputation: 15
John.... I thought I posted the link already. Here it is again..

http://stackoverflow.com/questions/3...id-to-whatever
 
Old 12-16-2012, 11:06 PM   #7
gothrog
Member
 
Registered: Jun 2004
Distribution: Yellow Dog, Fedora, RedHat, Centos, Ubuntu, Suse Linux
Posts: 98

Original Poster
Rep: Reputation: 15
Smile

John, I'd like to say thanks for your help and answering my questions as best as you could!!! I really appreciate it. It helped me figure out what is not the problem.

I don't want to jinx myself (still running regression tests and still need to do it on a pristine machine), but all the advanced stuff was being done right. I should have picked up this mistake sooner. For others reading and that may search on the post later, below is similar to what was wrong.

Code:
   if (!pDTCheck->aVector[index].myBoolVal )
   {
     .... do a bunch of stuff.....
     pDTCheck->aVector[index].myBoolVal= true;  // Since the condition value is part of a large 3D vector it caused a problem
   }

Quote:
Quote:
Quote:
It crashes when it sets a string "actionName" to nothing.
That crash almost certainly implies the this pointer is stale (points to an object that has been moved/deleted).
Code:
Program received signal SIGSEGV, Segmentation fault.
[Switching to thread 7972.0x1f84]
0x6c4b8d40 in cygstdc++-6!_ZNSs6assignEPKcj () from /usr/bin/cygstdc++-6.dll
(gdb) up
#1  0x6c4ba125 in cygstdc++-6!_ZNSsaSEPKc () from /usr/bin/cygstdc++-6.dll
(gdb) up
#2  0x00448735 in TheDataType::DT1::clear (this=0xd58101)
    at ../Common/TheDataType.h:161
161              actionName = "";
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] vector,matrices drawing software. some thing like android(Visual Vector Math) PoleStar Linux - Newbie 3 11-02-2012 10:45 PM
LXer: Tropic of Vector – a blog devoted to Vector Linux Light, plus the Vector Linux LXer Syndicated Linux News 0 09-17-2009 01:30 PM
C: Casting a pointer to (void **) jrtayloriv Programming 7 09-08-2009 05:52 PM
LXer: Vector Linux 5.9-Pseudo64-0.1 -- Finally, 64-bit Vector LXer Syndicated Linux News 0 09-12-2007 01:20 PM
pointer to vector aral Programming 13 10-05-2006 06:46 AM


All times are GMT -5. The time now is 01:04 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration