Pointer in Struct - unknown array size

I am trying to execute a TLV (Type-Length-Value) in C, however I am having problems getting a dynamic size for it to work correctly.

My structure is as follows:

typedef struct __attribute__((packed)){
   unsigned char type;
   unsigned char length;
   unsigned char * value;
} TLV;

I am trying to pass an array to a structure so that I can easily access the type and length. For example, an array:

unsigned char test[5] = {(unsigned char)'T', 0x03, 0x01, 0x02, 0x03};

Where "T" in the array is the type, the first 0x03 is the length.

I impose an array on the structure as follows:

TLV* tlv = (TLV*)test; 

However, when I try to access an array of values, I get a segmentation error even when I try to access the first element of the address of the values ​​memory (which should be the first element in the array after the length).

How can I get around this segmentation error?

+4
3

, unsigned char value[].

typedef struct __attribute__((packed))
{
   unsigned char type;
   unsigned char length;
   unsigned char value[];
} TLV;

, .

+6

value , ( - ). ( ), unsigned char value[1].

typedef struct __attribute__((packed)) {
    unsigned char type;
    unsigned char length;
    unsigned char value[1];
} TLV;

1 . UB, , .

GCC 0. , , 0 C.

Edit:

. , .

: gcc, . .

:

typedef struct {
    char p[20];
} sa;

typedef struct {
    char *p;
} sp;

:

sa x = { "Hello, world" };
sp y = { "Howdy, world" };

?

printf("%s\n", x.p); // prints "Hello, world"
printf("%s\n", y.p); // prints "Howdy, world"

?

printf("address of x = %p\n", &x); // On my machine it prints 0x7fffacce9b20
printf("address of y = %p\n", &y); // 0x7fffacce9b10

, , , ... - - , , - .

printf("address of x.p = %p\n", &x.p); // 0x7fffacce9b20
printf("address of y.p = %p\n", &y.p); // 0x7fffacce9b10

. .

printf("address of x.p[0] = %p\n", &x.p[0]); // 0x7fffacce9b20 - same as before
printf("address of y.p[0] = %p\n", &y.p[0]); // 0x400764 - could be anything

. "Hello, world" , x, "Howdy, world" - - , - , , , - .

: - , , - , "-".

- "" - . , .

, TLV UB, , "", . .

0

, 0 C. GCC, , :

typedef struct {
    unsigned char type;
    unsigned char length;
    unsigned char value[0];
} TLV;

int required_length = 10;
TLV *tlv = (TLV *) malloc(sizeof(TLV) + required_length);

0 ( ", " ) - .

+3

, , UB - , test , .

() - , struct TLV .

, __attribute__((packed)).

, 100% UB.

, value , , , . , sizeof(unsigned char) 1, . , malloc(n*sizeof(T)) T, n T. C , unsigned char , char ( ).

, ​​assert(.), . , , - , .

:

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>


typedef struct {
   unsigned char type;
   unsigned char length;
   unsigned char value;
} TLV;

static TLV dummy;

int main(void) {

    //There no standard way to verify this at compile time.
    //NB: If you stick with packing or leave all the members of TLV the same type
    //Then this is almost certainly NOT an issue.
    //However the cast of test implicitly assumes the following is the case.
    //Here a run-time check of a static constraint.
    assert(offsetof(TLV,value)==(sizeof(dummy.type)+sizeof(dummy.length)));

    unsigned char test[5] = {(unsigned char)'T', 0x03, 0x01, 0x02, 0x03};

    TLV* tlv=(TLV*)test;

    for(unsigned char i=0;i<tlv->length;++i){
        printf("%u\n",(&tlv->value)[i]);
    }

    (&tlv->value)[0]=253;
    (&tlv->value)[1]=254;
    (&tlv->value)[2]=255;

    for(unsigned char i=0;i<tlv->length;++i){
        printf("%u\n",(&tlv->value)[i]);
    }

    return EXIT_SUCCESS;
}

(C99 ) :

#include <stdlib.h>
#include <stdio.h>

typedef struct {
   unsigned char type;
   unsigned char length;
   unsigned char value[];//Variable length member.
} TLV;

int main(void) {

    TLV* tlv=malloc(sizeof(TLV)+3*sizeof(unsigned char));

    tlv->type='T';
    tlv->length=3;
    tlv->value[0]=1;
    tlv->value[1]=2;
    tlv->value[2]=3;

    for(unsigned char i=0;i<tlv->length;++i){
        printf("%u\n",tlv->value[i]);
    }

    tlv->value[0]=253;
    tlv->value[1]=254;
    tlv->value[2]=255;

    for(unsigned char i=0;i<tlv->length;++i){
        printf("%u\n",tlv->value[i]);
    }

    free(tlv);

    return EXIT_SUCCESS;
}

, , (, , ) , , char .

() , , , , value ( - ), TLV. , , length size_t - "" .

The current length limit of 255 (on almost all platforms) is frankly mean. That was in 1993 at Turbo Pascal. In 2015, he jumps. At least, implement it lengthas an `unsigned int 'if you do not know that such a stretch ceiling is enough.

-1
source

Source: https://habr.com/ru/post/1570858/


All Articles