-1

Dynamic cast fails in same function where it was working. Dynamic cast is working before calling commitTransaction and fails after commitTransaction. In commitTransaction, copy operator is called where delete and new operations are performed. Any thoughts as to what is going on here? I read that heap corruption can cause dynamic_cast to fail. Can anyone please explain why this is happening?

#include <iostream>
#include <string>

using namespace std;
#define num 10000
#define numOfWords 10000
class RollbackAllocator                                                                           
{    
    public:
    int*  memBitMap;
    RollbackAllocator & operator=(const RollbackAllocator& rollBack)                                              
    {                                                                                                             
        delete[] memBitMap;                                                                                       

        if(rollBack.memBitMap)                                                                                    
        {                                                                                                         
            memBitMap = new int[num];                                                                          
            for(int i = 0;i<num;i++)                                                                           
            {                                                                                                     
                memBitMap[i] = rollBack.memBitMap[i];                                                             
            }                               
        }                                                                                                         
        else                                                                                                      
        {                                                                                                         
            memBitMap = 0;                                                                                        
        }                                                                                                         
        return *this;                                                                                             
    };
    void init()
    {
        memBitMap = new int[num];
    }

};

class ResourceAllocator
{
    public:
    int temp;
    virtual int tempMethod(){
        temp = 0;
        };
};

class KatanaResourceAllocator : public ResourceAllocator
{
    public:
    RollbackAllocator   mIFPBPDUEntryIndexAllocatorNM;
    RollbackAllocator   mIFPBPDUEntryIndexAllocatorNMShadow;
    void commitTransaction()
    {
        mIFPBPDUEntryIndexAllocatorNMShadow = mIFPBPDUEntryIndexAllocatorNM;
    }
};

int main() {

ResourceAllocator * resourceAllocator = new KatanaResourceAllocator();
    KatanaResourceAllocator * allocator = dynamic_cast<KatanaResourceAllocator *>(resourceAllocator); //dynamic_cast works fine type().name= P17ResourceAllocator
    cout<< " pre allocator=" << allocator;
    allocator->mIFPBPDUEntryIndexAllocatorNM.init();
    allocator->mIFPBPDUEntryIndexAllocatorNMShadow.init();
    allocator->commitTransaction();
    allocator = dynamic_cast<KatanaResourceAllocator *>(resourceAllocator); //allocator is null here type().name= P17ResourceAllocator
    cout<<" post allocator=" << allocator;

    return 0;
}
Tejas Pawar
  • 690
  • 8
  • 16
  • First of all, are there cases where memBitMap can be null before being called by operator= ? It might be worth checking that out before deleting the buffer. – AlexG May 03 '17 at 11:06
  • What's `cout << typeid(mPPSubSys->getResourceAllocator()).name` ? And is it not itself null? – n.caillou May 03 '17 at 11:10
  • @AlexG Won't delete check null internally? – Tejas Pawar May 03 '17 at 11:12
  • @n.caillou pre commit allocator=0x52489a90 resourceAllocator=0x52489a90 post commit allocator=0 resourceAllocator=0x52489a90 – Tejas Pawar May 03 '17 at 11:13
  • @TejasPawar no. – AlexG May 03 '17 at 11:14
  • @TejasPawar The address is secondary (an object can be destroyed and recreated with the same address). Please show the types before and after. – n.caillou May 03 '17 at 11:26
  • You forgot to give `main` a return type. – Lightness Races in Orbit May 03 '17 at 11:33
  • 1
    Please present your [MCVE]. What you've provided us with isn't even valid syntax. You've definitely been here long enough to know that a MCVE is needed. – Lightness Races in Orbit May 03 '17 at 11:33
  • @BoundaryImposition To keep the example minimal, I have tried to copy all the relevant code which is causing the issue. I have used main() just to indicate starting point to go through the example. – Tejas Pawar May 03 '17 at 11:41
  • @TejasPawar You need enough code so we can compile it and see what is going on. If we can't do that then most of the time we cannot help you. – NathanOliver May 03 '17 at 11:42
  • It's not minimal, but more importantly it's not complete. – Lightness Races in Orbit May 03 '17 at 11:47
  • @n.caillou before and after type().name() is same = P17ResourceAllocator. – Tejas Pawar May 04 '17 at 09:32
  • @BoundaryImposition I have added code which we can compile but when I am compiling on linux, it is not giving any error and dynamic cast works fine. Is there anything else which might cause dynamic cast to fail? – Tejas Pawar May 04 '17 at 09:36
  • 1
    @TejasPawar: UB elsewhere in your code. Hence the requirement for an MCVE; you've now found that you can't reproduce the issue, so we probably wouldn't be able to either! – Lightness Races in Orbit May 04 '17 at 10:12
  • @BoundaryImposition I read that writing out bound causes dynamic cast to fail. So I wrote random data at memBitMap[10003], memBitMap[10004], ..., memBitMap[10006] but still dynamic cast didn't fail. Can you please explain the relation between Heap corruption and dynamic casts? – Tejas Pawar May 04 '17 at 10:29
  • You can't "test" undefined behaviour like that, or in any other way. If you corrupt your memory in an unpredictable fashion, the results will be unpredictable. It's as simple as that. Just don't do it! – Lightness Races in Orbit May 04 '17 at 10:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/143392/discussion-between-tejas-pawar-and-boundaryimposition). – Tejas Pawar May 04 '17 at 10:59
  • @AlexG Yes it does. – Arthur Tacca May 04 '17 at 12:05
  • @ArthurTacca It will only check null if the pointer has been initialized/explicitly set to null which we don't know is the case here. – AlexG May 04 '17 at 12:40

1 Answers1

0

This code causes undefined behaviour by copying uninitialized int values. Specifically the line:

 memBitMap[i] = rollBack.memBitMap[i];  

but rollBack.memBitMap[i] denotes an int that was created by new int[num];, which does not initialize the values.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • My main concern is why dynamic_cast is failing? Will copying uninitialized int values cause dynamic cast failure? – Tejas Pawar May 04 '17 at 12:53
  • @TejasPawar you will need to post actual code showing the problem to get a more specific answer, the comments seem to suggest that you posted code which does not show the problem even for yourself (which is completely useless) – M.M May 04 '17 at 12:58