0

I have a C structure like this :

 typedef struct ip_esp_private {         /* keep track of things privately */
    u_int32_t type;        
    u_int32_t ivlen;       
    u_int32_t icvlen;      
    u_int32_t keylen;       /* length of "Encryption key */
    u_int32_t akeylen;      /*length of authn key */
  //  u_int32_t key[0];       /* key itself */
  //  u_int32_t akey[0];      /*authn key itself */

    u_int32_t *key;       /* as suggested  */
    u_int32_t *akey;      /* as suggested */

 } esp_private;

Now the problem should be obvious from here when I try to write to key , the akey will be overwritten .

I am not sure how can I protect it ???

keylen and akeylen provide length of key and akey array and whole structure is to be filled at run time.

Please provide some suggestions .

EDIT :

  1. yes ... u_int32_t is a typedef so dont bother about that

  2. I have changed the zero length array to pointers as edited above.This is how I need to fill in the structure ..

    case 'k':       /* Key */
            length = stringargument(arg, &temp);
            priv->keylen = length;
    
            priv->key=malloc(priv->keylen * sizeof(u_int32_t));
            /*as suggested added this step*/          
    
    
            /*as suggested commented this step*/
            priv = (esp_private *)realloc(priv,
                            sizeof(esp_private) + length);
    
    
    
            memcpy(priv->key, temp, priv->keylen);
            pack->private = priv;
            pack->modified |= ESP_MOD_KEY;
            break;
    
    case 'K':       /* Authentication  Key */       
            length = stringargument(arg, &temp);
            priv->akeylen = length;
    
            priv->akey=malloc(priv->akeylen * sizeof(u_int32_t));
            /*as suggested added this step*/
    
    
            /*as suggested commented this step*/
            priv = (esp_private *)realloc(priv,
                            sizeof(esp_private) + length);
    
    
    
            memcpy(priv->akey, temp, priv->akeylen);
            pack->private = priv;
            pack->modified |= ESP_MOD_AKEY;
    

but not working out .. may be not re-allocating carefully please suggest on this edit also.

EDIT 2:

Even after commenting the realloc as suggested , its not working out.The key and akey were supposed to take value mentioned as arg on command line but they are taking some random values.There is still something wrong here which need attention.

Please help me as the whole project has stuck in between just because of a minute error in this small piece of code.Need it soon ...

Udit Gupta
  • 3,162
  • 11
  • 43
  • 71
  • With your last edit (11 mins ago), you don't need the `realloc`s, you're dynamically allocating memory with `malloc` for the arrays. The struct's size stays as is, `key` and `akey` are now pointers so to change the size of those "arrays" you perform memory operations, `malloc`/`realloc`, using just those pointers (`priv->key` and `priv->akey`). – AusCBloke Oct 24 '11 at 02:24
  • oh but omitting that also does not working out ... – Udit Gupta Oct 24 '11 at 02:27

4 Answers4

3

So can't you just have key and akey as pointers and malloc memory for them upon creation of an esp_private struct?

 typedef struct ip_esp_private {  
    u_int32_t type;        
    u_int32_t ivlen;       
    u_int32_t icvlen;      
    u_int32_t keylen; 
    u_int32_t akeylen; 
    u_int32_t *key;  /* change */  
    u_int32_t *akey; /* change */
 } esp_private;

void esp_private_init(esp_private *ep, /* maybe some args here for type, ivlen, etc */
                     u_int32_t *key, u_int32_t keylen, u_int32_t *akey, u_int32_t akeylen)
{
   /* maybe set up type, ivlen, etc if neccesary */

   ep->keylen = keylen;
   ep->key = malloc(keylen * sizeof(u_int32_t));
   /* copy argument key into ep->key */

   ep->akeylen = akeylen;
   ep->akey = malloc(akeylen * sizeof(u_int32_t));
   /* copy argument akey into ep->akey */
}
AusCBloke
  • 18,014
  • 6
  • 40
  • 44
3

Basically, you can't do that. The offset of each member of a struct is fixed at compile time, which means you can't have more than one element whose size can vary.

Incidentally, that's not a variable-length array; it's a "struct hack". That form of it, using [0] is strictly not valid in C; the form with [1] is more or less ok, but it's been persuasively argued that its behavior is undefined.

C99 adds "flexible array members" as a standard replacement for the "struct hack".

You can use a single flexible array member for both key and akey, keeping track of where each one starts. Or you can declare them as u_int32_t* pointers rather than as arrays -- which of course means you have more memory management to do.

Incidentally, is u_int32_t a typo for uint32_t (defined in <stdint.h>)?

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • The link , but I'm is to the comp.lang.c FAQ, but I'm currently not able to connect to it. – Keith Thompson Oct 24 '11 at 01:36
  • I was wondering the same thing about `u_int32_t`, he must just be using the typedefs from ``. – AusCBloke Oct 24 '11 at 01:40
  • @KeithThompson if possible hava a look on this one .. I tried with your suggestion http://stackoverflow.com/questions/7876273/error-when-dealing-with-memory-mremap-chunk-assertion – Udit Gupta Oct 24 '11 at 13:38
1

Either use a dynamic array, or use a single variable length array to store both key and akey.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
0

Why don't you just use normal pointers instead of arrays of 0 (or 1) elements for key and akey and allocate as much memory as necessary? For example:

#include <assert.h>

// the rest of includes and other things can go here.

typedef struct ip_esp_private {         /* keep track of things privately */
    u_int32_t type;        
    u_int32_t ivlen;       
    u_int32_t icvlen;      
    u_int32_t keylen;       /* length of "Encryption key */
    u_int32_t akeylen;      /*length of authn key */
    u_int32_t* key;       /* key itself */
    u_int32_t* akey;      /*authn key itself */
 } esp_private;

esp_private* CreateStruct(u_int32_t KeyLength, u_int32_t AKeyLength)
{
  esp_private* p = malloc(sizeof(esp_private));
  if (p == NULL) return NULL;

  /* Allocate KeyLength and AKeyLength elements to p->key and p->akey */
  p->key = malloc(KeyLength * sizeof(u_int32_t));
  p->akey = malloc(AKeyLength * sizeof(u_int32_t));

  if ((p->key == NULL) || (p->akey == NULL))
  {
    if (p->key != NULL) free(p->key);
    if (p->akey != NULL) free(p->akey);
    free(p);
    p = NULL;
  }
  else
  {
    p->keylen = KeyLength;
    p->akeylen = AKeyLength;
  }

  return p;
}

void DestroyStruct(esp_private* p)
{
  assert(p != NULL);
  assert(p->key != NULL);
  assert(p->akey != NULL);
  free(p->key);
  free(p->akey);
  free(p);
}

int main(void)
{
    /* allocate a structure */
    esp_private* p = CreateStruct(5 /*KeyLength*/, 10 /*AKeyLength*/)
    assert(p != NULL);

    /* use the structure */
    p->key[0] = 0;
    p->key[4] = 0x44444444;
    p->akey[0] = 0;
    p->akey[9] = 0x99999999;

    /* deallocate the structure */
    DestroyStruct(p);
    return 0;
}
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • Just made a comment on your edit, but for clarity's sake I'll add it here also: With your last edit (11 mins ago), you don't need the `realloc`s, you're dynamically allocating memory with `malloc` for the arrays. The struct's size stays as is, `key` and `akey` are now pointers so to change the size of those "arrays" you perform memory operations, `malloc`/`realloc`, using just those pointers (`priv->key` and `priv->akey`). – AusCBloke Oct 24 '11 at 02:27