Directional signs and double free

After some painful experiences, I understand the problem of dangling pointers and double freedom. I am looking for suitable solutions.

aStruct has several fields, including other arrays.

aStruct *A = NULL, *B = NULL;
A = (aStruct*) calloc(1, sizeof(sStruct));
B = A;
free_aStruct(A);
...
// Bunch of other code in various places.
...
free_aStruct(B);

Is it possible to write in free_aStruct(X)such a way that it free_aStruct(B)comes out gracefully?

void free_aStruct(aStruct *X) {
    if (X ! = NULL) {
        if (X->a != NULL) { free(X->a); x->a = NULL; }
        free(X); X = NULL;
    }
}

Doing the above only sets A = NULLwhen called free_aStruct(A);. Bnow hangs.

How can this situation be avoided or eliminated? Is link counting the only viable solution? Or are there other “defensive” approaches to freeing memory to prevent an free_aStruct(B);explosion?

+3
source share
5

C , :

B = A;

- , , , . - :

B = getref_aStruct(A);

. , , - , - . calloc() , free_aStruct(), . create_aStruct(), . , , .

, .

+5

, , C , , , , , !

void free_aStruct(aStruct *X){
  if (X ! = NULL){
      if (X->a != NULL){free(X->a); x->a = NULL;}
      free(X); X = NULL;
}
}

, if ... "x" "X"...

, , , aStruct *. ...

void free_aStruct(aStruct **X){
  if (*X ! = NULL){
      if (*X->a != NULL){
          free(*X->a); 
          *X->a = NULL;
      }
      free(*X); 
      *X = NULL;
  }
}

:

free_aStruct(&A);

, " " , ...

+2

free_aStruct (B), B, . "" .

+1

, , , , , C. valgrind ( ) . , .

+1

:

aStruct *astruct_getref(aStruct *m)
{
    m->refs++;
    return m;
}

aStruct *astruct_new(void)
{
    sStruct *new = calloc(1, sizeof *new);
    return astruct_getref(new);
}

void astruct_free(aStruct *m)
{
    if (--m->refs == 0)
        free(m);
}

( ).

:

aStruct *A = NULL, *B = NULL;
A = astruct_new();
B = astruct_getref(A);
astruct_free(A);
...
//bunch of other code in various places.
...
astruct_free(B);

. , , - , . . (, , astruct_getref() astruct_free() aStruct, - ).

, astruct_getref() astruct_free():

aStruct *astruct_getref(aStruct *m)
{
    mutex_lock(m->reflock);
    m->refs++;
    mutex_unlock(m->reflock);
    return m;
}

aStruct *astruct_new(void)
{
    sStruct *new = calloc(1, sizeof *new);
    mutex_init(new->reflock);
    return astruct_getref(new);
}

void astruct_free(aStruct *m)
{
    int refs;

    mutex_lock(m->reflock);
    refs = --m->refs;
    mutex_unlock(m->reflock);
    if (refs == 0)
        free(m);
}

... but note that any variables that contain pointers to structures that are subject to concurrent access also need their own locking (for example, if you have a global aStruct *fooone that is simultaneously accessible, it will need an maintainer foo_lock).

+1
source

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


All Articles