0

I have a problem with a object of class A that has inherited a base class B with some pure virtual functions and i have a list of ptr objects A where i'm adding objects of type B. The problem is that sometimes when i try to access a virtual method from a object in the list the __vfptr table is corrupted. The objects are there in the list and are not deleted, i'll pot a pic with the autos. Does anybody has some idea of why this is happening? Thing is that if i start one or two instances of the application that error doesn't occur, but when i start more instances, it gives access violation reading at the third or the forth instance of the application, strange.

Or at least do you have any idea on how to track when that pointer to the vftable is changing? because that method gets called from a bunch of places and i can't possibly track all down with the debugger let alone that this error occurs randomly.

Thank you a lot

enter image description here

UPDATE 1

example here: http://rextester.com/live/MRHR24728

//Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x86

#include <iostream>
#include <stdint.h>

typedef struct
{
    uint8_t name;
}sName;

class Base1
{
public:
    virtual ~Base1(){};

    virtual const sName* GetName() = 0;
};

class Base2 : public Base1
{
public:
    Base2(){};
    virtual ~Base2(){}

    virtual const sName* GetName() { return &_name; }

private:
    sName _name;
};

class Base3 : public Base2
{
public:
    Base3(){}
    virtual ~Base3(){}
};

class Object : public Base3
{
public:
    Object(){}
    ~Object(){}
};

int main()
{
    Object object;
    Base1 *_logicalDevices[1] = {&object};

    const sName * test = _logicalDevices[0]->GetName(); // this is where it breaks sometimes when trying to access the GetName method
    std::cout<<test->name;
}
underscore_d
  • 6,309
  • 3
  • 38
  • 64
Mihai
  • 972
  • 2
  • 13
  • 35
  • Please, post some code – stryku Aug 12 '16 at 09:36
  • there are hundred of thousands of lines of code and large classes, i'll try to synthesize the whole thing then @stryku – Mihai Aug 12 '16 at 09:39
  • Does the example crash with the microsoft compiler? – Rudi Aug 12 '16 at 10:04
  • yes, using vs2013 @Rudi – Mihai Aug 12 '16 at 10:05
  • I strongly believe your object has been deleted somehow. put some log and verify. – Gilson PJ Aug 12 '16 at 10:21
  • The trivial example does nothing wrong that I can see and produces no warnings or crash when compiled with `g++ -std=c++14 -Wall -Werror -Wpedantic`. As for `// this is where it breaks sometimes` - right, so of course, you ran a stack trace after said breakage. What did that tell you? – underscore_d Aug 12 '16 at 10:30
  • ...never mind. Your question does not contain all the code from the link. Very poor reporting. You access `test->name` uninitialised and therefore invoke undefined behaviour. _Next._ – underscore_d Aug 12 '16 at 10:33
  • `bahrep reviewed this 12 mins ago: Reject This edit defaces the post in order to promote a product or service, or is deliberately destructive.` ...are you OK? – underscore_d Aug 12 '16 at 13:11
  • @mihaipop This is far too broad without actual code. e.g. `i have a list of ptr objects A` Is that `std::list`? or some other container & if so, are you adhering to all rules of iterator invalidation? Also, regarding the idea that you have to run a large number of instances before the problem will manifest: is this 100% definitely caused by number of instances, not e.g. total duration of execution or volume of calls (across all instances)? If yes, are these instances (intentionally or not) attempting to share any memory, files or other resources? There are far, **far** too many unknown factors – underscore_d Aug 12 '16 at 15:46

1 Answers1

3

In your code snipet Object object is default initialized, user provided default constructor is called. The problem is in your Base2 default ctor you don't have initialization of _name field, so it's initialized to indeterminate value. I suggest to change your Base2 constructor and add constructor for sName structure:

 struct sName
 {
   uint8_t name;
   sName() : name(0) {}
 };

 class Base2 : public Base1
 {
   public:
     Base2()
      : _name()    // <--- Default ctor of sName called
     {};
     virtual ~Base2(){}

     virtual const sName* GetName() { return &_name; }

   private:
     sName _name;
};
Nikita
  • 6,270
  • 2
  • 24
  • 37
  • `so it's initialized to indeterminate value` So what? They never read its value, only the address of the member, which must always be valid. Until they read the uninitialised _value_, no undefined behaviour is involved. So unless they're not posting the full code and the crashing program really dereferences the returned pointer and reads the uninitialised value it points at, that can't be a reason for any problem. – underscore_d Aug 12 '16 at 10:27
  • ...which they do, but not in the question, only at the link: `std::cout<name;` so +1 – underscore_d Aug 12 '16 at 10:33
  • even if it's initialized to indeterminate value, the error access violation reading is appearing when trying to call the virtual method, not when trying to access the _name – Mihai Aug 12 '16 at 10:33
  • 1
    @mihaipop So? (A) Some compilers occasionally or reliably produce wrong reports of where a problem occurred. (B) Undefined behaviour can result in anything. [Undefined behaviour can result in time travel.](http://stackoverflow.com/questions/24527401/undefined-behavior-causing-time-travel) – underscore_d Aug 12 '16 at 10:35
  • @Nikita Actually, I think this answer is lacking. Surely the OP must also explicitly initialise or assign the innermost `uint8_t name`, because simply default-constructing its parent `struct sName _name` is merely moving the problem - lack of a default constructor for basic types, hence lack of a defined value, hence UB - to a different level but not solving it. – underscore_d Aug 12 '16 at 10:51
  • 1
    @underscore_d You right, thnx. Updated the answer. Added ctor for the `sName` struct. – Nikita Aug 12 '16 at 11:01
  • @mihaipop Have you updated your program to avoid reading uninitialised variables and all other forms of UB? What was the result? – underscore_d Aug 12 '16 at 14:09
  • @underscore_d yep, did that, didn't helped unfortunately. Could this occur if that method is called from multiple places? maybe simultaneously? – Mihai Aug 12 '16 at 14:12
  • @mihaipop Dunno. Without seeing the entire program, we have no way of determining whether it is definitely free of UB, so there is no point in speculating. Have you used a debugger to run a stack trace after encountering the error? – underscore_d Aug 12 '16 at 14:17
  • @underscore_d unfortunately i can't post the real code, and yes, analysed the stack trace but i can't see where that ptr is changed, because the trace is going back in different objects in different files – Mihai Aug 12 '16 at 14:21
  • @mihaipop So you still get the same problem with even the minimal example now shown in the OP - after fixing it not to read uninitialised `uint8_t name`? If so, please upload it in full. If not...if this is difficult for you, you must see it's infinitely worse for everyone else, given the unknowable real program vs the tiny amount of code you've shown... which wasn't representative before & seemingly _never can be_: `// this is where it breaks sometimes when trying to access the GetName method` where "sometimes" implies that you really run this more than once & probably in different situations – underscore_d Aug 12 '16 at 14:30
  • @mihaipop Also, re tracing: `because that method gets called from a bunch of places and i can't possibly track all down with the debugger`: not really true, as you could put a breakpoint on entering the function & backtrace at each call before continuing, till you' enumerated them all. However, that might not tell you much if it only reveals a hint of _when_ the vptr is _sometimes_ being corrupted, not _why_ - & if UB is the culprit, that _why_ might prove to be very elusive indeed. If VC++ has any kind of runtime UB detection like UBSan available in Clang & GCC, please run with that. – underscore_d Aug 12 '16 at 15:36