1

I tried to replace a void* member of a struct with a flexible array member using the more accepted idiom:

typedef struct Entry {
    int counter;
    //void* block2; // This used to be what I had
    unsigned char block[1];
}

I then add entries into a continuous memory block:

void *memPtr = mmap(NULL, someSize*1024, PROT_READ|PROT_WRITE, 
                        MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

as such:

int number = 0;

int AddEntry(void *data) {
   Entry *entry;
   entry = malloc(sizeof(Entry) + ((SECTOR_SIZE-1) * sizeof(unsigned char));
   entry->counter = 1;
   memcpy(entry->block, data, SECTOR_SIZE);

   // make sure number doesn't overflow space, etc...
   memcpy(&memPtr[number], entry, sizeof(Entry) + ((SECTOR_SIZE-1) * sizeof(unsigned char));
   number++;
   return 0;
}

The problem is unpacking this data once I need it. For example, if I do:

void * returnBlock(int i) {
    Entry * entry  = &memPtr[i];
    printf("Entry counter is %d\n", entry->counter); // returns 1, reliably
    return entry->block; // Gives me gibberish but not if I uncomment void* block2.
}

Is there a reason this could be? I don't necessarily think I'm stomping on stuff anywhere, and it used to work with the void* approach. The weird thing is that if I put a dummy void* back into the struct, it works. It doesn't work if I put in a dummy int.

Edit: actually, it also fails if number in AddEntry is not 0. What am I stepping on, if anything?

3
  • 1
    You cannot make an array of a structure that contains a flexible array member. Commented Feb 27, 2012 at 3:36
  • What is memptr[i] exactly? You cannot subscript a void pointer. Commented Feb 27, 2012 at 4:15
  • As @R.. says, it makes no sense to have an array of flexible arrays. All the idea of flexible array members is that you have the "header" part of the data structure and the array itself contiguous. So if you really need your Entrys of different size, you'd need an array of pointers to that type. Commented Feb 27, 2012 at 8:45

1 Answer 1

2

Your problem is here:

&memPtr[number]

Since memPtr is a void * pointer, this isn't actually allowed in C at all. Some compilers do allow arithmetic on void * pointers as a language extension - however they treat it as if it were a char * pointer.

That means that &memPtr[number] is likely indexing only number bytes into your memory block - so the second Entry structure copied in will overlap the first one, and so on.

Your allocation line appears to be assuming 1024 bytes per Entry (if someSize is a number of Entry structures), so you probably want something like:

((char *)memPtr + number * 1024)

(and similar in the returnBlock() function).

However, if you do this you will notice that there is no point in using the flexible array member - because you're creating a contiguous array of these structures, and don't have a separate index, you have to assume each one is a fixed size. This means that you might as well make each one a fixed size:

typedef struct Entry {
    int counter;
    unsigned char block[1024 - sizeof counter];
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.