c++arrays

Read access violation when reading buffer block (C++)


I'm trying to implement a buffer block class in C++, along with another class that handles a least-recently-used (LRU) approach to buffers. My problem is that, when I try to access specific chars within buffer blocks, VS2017 throws an error at the line space[i] = bufferblocks[1][(i + pos) % 4];:

Exception thrown: read access violation. 
Bufferblock::operator[](...) returned 0xCDCDD173.

This is strange because, as far as I can tell, block (in the Bufferblock class) is initialized in the constructor to be a char array of 4096 chars, each of which is set to NULL (though I've also tried setting them to 'A' and the same thing happens). But then, when I cout the sizeof(block), it prints "4".

Why is block 4 chars long and not 4096?

Here is what should be a minimal reproducible example of my code (mydatafile.txt is just a really long text file - its contents shouldn't really matter):

#include <fstream>
#include <iostream>

using namespace std;

class Bufferblock {
public:

    int blockID;
    char* block;
    int blockSize;

    Bufferblock()
    {
        blockSize = 4096;
        blockID = 1;
        char *block = new char[4096];
        for (int i = 0; i < 4096; i++)
        {
            block[i] = (char)NULL; // this works fine, looping through 4096 chars in block.
        }
    }

    char& operator[](int index)
    {
        std::cout << sizeof(block) << std::endl; // prints 4, not 4096
        return block[index % 4096]; // triggers exception that is thrown later


    }
};


class LRUBufferPool {
private:
        Bufferblock* bufferblocks;
public:

    LRUBufferPool(string filename, int poolSize = 5, int blockSize = 4096)
    {
        bufferblocks = new Bufferblock[poolSize];
        fstream input;
        input.open(filename.c_str(), fstream::in, fstream::binary);
        for (int i = 0; i < 5; i++)
        {
            input.read(bufferblocks[i].block, blockSize);
        }
    }

    void getBytes(char* space, int sz, int pos) {

        space = new char[sz];
        for (int i = 0; i < sz; i++)
        {
            space[i] = bufferblocks[1][(i + pos) % 4096];
        }

    };

};

void initializeCharArray(int sz, char* ch) {
    for (int i = 0; i < sz; i++) {
        ch[i] = (char)NULL;
    }
}

int main() {

    LRUBufferPool* bp = new LRUBufferPool("mydatafile.txt", 5, 4096);
    
    char* data = new char[10];
    bp->getBytes(data, 10, 5030);

    return 0;
} 

(Please note that this project is very much in the beginning development phase. I'm not worried about memory leaks or really anything other than figuring this out just yet.)

Also, I tried modding by 4 instead of 4096 and it still doesn't work - it throws the same exception. This makes me thing that the issue might be with the initialization.

So, my questions are:


Solution

  • I have to say it: Your code has many issues. You should not keep it for later to fix them. The longer you wait the more bugs similar to the current one will be encountered.

    Just to name some:

    Your problem reduced is:

    struct Bufferblock {
        int blockID;
        char* block;
        int blockSize;
        Bufferblock() {
            blockSize = 4096;
            blockID = 1;
            char *block = new char[4096];
            for (int i = 0; i < 4096; i++)
            {
                block[i] = (char)NULL;
            }
        }
    };
    

    Your constructor has a local variable called block that you initialize to point to an array of 4096 chars. The member block has the same name but is left uninitialized. Later trying to acces block[1] dereferences an invalid pointer.

    If you use std::vector and the member initializer list the code is simpler and the problem gone:

    struct Bufferblock {
        int blockID;
        std::vector<char> block;
        Bufferblock() : blockID(1),block(4096) {}
    };
    

    If the block size is always 4096 you can use std::array instead. In either case the blockSize member is not needed and should be removed.