0
#include <cstring>
#include <cstdio>
#include <cstdlib>

struct Block {
    int32_t size;
    u_int8_t data[0];
};

int main(int argc, char **argv) {
    Block block;
    Block *ptr = &block;
    u_int8_t data_buffer[] = {1, 3, 0, 1, 3, 4, 5, 5, 6, 2, 2, 3};
    void *sdata = (void *)data_buffer;
    void *ndata = (void*)ptr->data;
    printf("data ptr: %p\n", ptr->data);      // 0x7ffe53275340
    printf("ndata: %p\n", ndata);             // 0x7ffe53275340
    memcpy((void*)ndata, &data_buffer, sizeof(void*));
    printf("ndata: %p\n", ndata);            // 0x505040301000301
    printf("*(&data_buffer): %p\n", *(&data_buffer)); // 0x7ffe53275330
    printf("data ptr: %p\n", ptr->data);     // 0x7ffe53275340
    for(int i{0}; i<12; i++) {
        printf("%d ", (((u_int8_t*)(ptr->data))[i]));
    }
    printf("\n");
    return 0;
}

The code block is as above,

I am so confused that after memcpy function, why ndata would be changed to 0x505040301000301, a so strange value?

I have googled flexible array, but can not find exactly this kind of example. Any help would be great appreciated.

11
  • What do you believe is the size of the memory buffer that ndata (aka ptr->data aka block.data) points to? Your program exhibits undefined behavior by way of a buffer overrun. You are scribbling all over the stack, overwriting your own local variables. 0x505040301000301 happens to be the contents of data_buffer Commented Jul 27, 2024 at 15:38
  • The above code does not compile. First problem is Block is a struct, and when you declare a variable to be that struct you need to declare it as "struct Block block;". I'm not bothering to look any further. Fix the code in your question so that it compiles. Commented Jul 27, 2024 at 15:40
  • 2
    u_int8_t data[0]; is not a flexible array member. It's a "struct hack" and it's undefined behavior. u_int8_t data[]; would be a flexible array member. Zero-sized arrays used like that are a buggy GCC extension. Don't use them. Commented Jul 27, 2024 at 15:41
  • 5
    Flexible array is not part of C++, You might fix the header and remove C++11 tag. Commented Jul 27, 2024 at 15:45
  • Note that C++ has fundamental problems with flexible array members because of inheritance. Commented Jul 27, 2024 at 15:55

1 Answer 1

2

The size of a struct with a flexible array member doesn't include space for that member. So if you declare such a structure on the stack, you can't actually access those elements because they don't exist. What you're doing is undefined behavior because you're accessing memory past the bounds of the object.

What you need to do is declare a pointer to this struct and allocate space for the struct plus as many members as you need.

u_int8_t data_buffer[] = {1, 3, 0, 1, 3, 4, 5, 5, 6, 2, 2, 3};
struct Block *ptr = malloc(sizeof *ptr + sizeof data_buffer);

Also:

  • Using 0 as the array size is a GCC extension. You should instead leave the size blank which is the C standard compliant way to do this.
  • This code appears to be C++ based on the headers you're using, but it otherwise looks like C code, not to mention that flexible array members are not part of standard C++ at all. If you actually want to use C, use the C standard headers (i.e. stdio.h instead of cstdio), use the struct keyword when declaring structs, and compile as a C program.
Sign up to request clarification or add additional context in comments.

4 Comments

Minor: Interesting use of sizeof: sizing a type and an object. I recommend sizing 2 objects ptr = malloc(sizeof *ptr + sizeof data_buffer);
I advise to use malloc at all, in the C++ core guidelines it is even recommend to no longer use new/delete (except INSIDE datastructures). There are good reasons for this, specialy with regard to memory managment bugs and safety requirements. So I do not consider this to be a valid (or at least not an up-to-date) C++ answer.
@PepijnKramer As flexible array members don't exist in C++, OP is obviously writing C code in a C++ environment and is meaning to write C code but doesn't understand the difference, hence the recommendation to get rid of the C++-isms.
I know.. but OP tagged C++ too and he uses the "C++" style struct syntax... so he is relying on the C++ compiler too

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.