Eroxl's Notes
05 - Memory Management and Reference Counting (CPSC 213 Practice)

Problem 1

Select the statement that best describes the use of malloc and free in the following questions. Assume that copy, foo, and bar are all in different module. Also assume that foo is initially called from the main function. (Assume n>0, and malloc and free are properly called for x in main.)

char* copy(char* from, int n){
 char* to = malloc(n);
 for(int i=0; i<n; i++)
     to[i] = from[i];
 free(to);
 return to;
}

void foo(char* x, int n){
 char* y = copy(x, n);
 printf("%s", y);
}
  • [ ] (a) There is no memory leak or dangling pointer; and malloc and free are in the right place.
  • [ ] (b) There is no memory leak or dangling pointer, but the code would be improved by moving malloc or free elsewhere.
  • [ ] (c) There is a possible memory leak that is best resolved by adding, removing or moving malloc or free in copy and/or foo.
  • [ ] (d) There is a possible memory leak that is best resolved by adding reference counting.
  • [x] (e) There is a possible dangling pointer that is best resolved by adding, removing or moving malloc or free in copy and/or foo.
  • [ ] (f) There is a possible dangling pointer that is best resolved by adding reference counting.
  • [ ] (g) There is either a possible dangling pointer or memory leak that is best resolved by adding reference counting.
char* copy(char* from, char* to, int n){
 for (int i=0; i<n; i++)
     to[i] = from[i];
 return to;
}

void foo(char* x, int n){
 char* y = malloc(n);
 copy(x, y, n);
 printf("%s", y);
}
  • [ ] (a) There is no memory leak or dangling pointer; and malloc and free are in the right place.
  • [ ] (b) There is no memory leak or dangling pointer, but the code would be improved by moving malloc or free elsewhere.
  • [x] (c) There is a possible memory leak that is best resolved by adding, removing or moving malloc or free in copy and/or foo.
  • [ ] (d) There is a possible memory leak that is best resolved by adding reference counting.
  • [ ] (e) There is a possible dangling pointer that is best resolved by adding, removing or moving malloc or free in copy and/or foo.
  • [ ] (f) There is a possible dangling pointer that is best resolved by adding reference counting.
  • [ ] (g) There is either a possible dangling pointer or memory leak that is best resolved by adding reference counting.
char* copy(char* from, char* to, int n){
 for(int i=0; i<n; i++)
     to[i] = from[i];
 return to;
}

void foo(char* x, int n){
 char* y = malloc(n);
 bar(y);
 copy (x, y, n);
 printf ("%s", y);
}
  • [ ] (a) There is no memory leak or dangling pointer; and malloc and free are in the right place.
  • [ ] (b) There is no memory leak or dangling pointer, but the code would be improved by moving malloc or free elsewhere.
  • [ ] (c) There is a possible memory leak that is best resolved by adding, removing or moving malloc or free in copy and/or foo.
  • [ ] (d) There is a possible memory leak that is best resolved by adding reference counting.
  • [ ] (e) There is a possible dangling pointer that is best resolved by adding, removing or moving malloc or free in copy and/or foo.
  • [ ] (f) There is a possible dangling pointer that is best resolved by adding reference counting.
  • [x] (g) There is either a possible dangling pointer or memory leak that is best resolved by adding reference counting.

Problem 2

Consider the following code:

int* create(int length) {
    int* result = rc_malloc(sizeof(*result) * length);

    return result;
}

int* even = NULL;
int* odd  = NULL;

void process(int* a) {
    if (*a & 1 == 0) {
        if (even != NULL)
            rc_free_ref(even);
        even = a;
    }
    else {
        if (odd != NULL) {
            rc_free_ref(odd);
            //**** [1] odd?
        }

        odd = a;
    }

    rc_keep_ref(a);
    //**** [2] a?
}

void do(int i) {
    int* x = create(1);

    //**** [3] x?
    *x = i;
    process(x);

    rc_free_ref(x);
}

int main (int argc, char** argv) {
    for (int i=1; i < argc; i++)
        do(atoi(argv[i]));
}

For each of the numbered comment lines indicate the value of the reference count at this point in the execution for the object pointed to by the specified variable. And if the object has been freed, indicate that as well.

Options:

  • 0
  • 1
  • 2
  • 3
  • 4
  • 0 (object has been freed)
  • 1 (object has been freed)
  • 2 (object has been freed)
  • 3 (object has been freed)
  • 4 (object has been freed)
  • Unable to determine from information provided
  • None of the above

[1]: 0 (object has been freed) [2]: 2 [3]: 1

Problem 3

int* w = NULL;
int* x = NULL;
int* y = NULL;
int* z = NULL;

void foo() {
	int* a = rc_malloc(sizeof(int));
	x = a;
	y = x;
	z = y;
	w = z;
}

If this code had implemented reference counting correctly, after foo returns, what should the reference count of the object pointed to by the variable y be?

  • [ ] (a) 0
  • [ ] (b) 1
  • [ ] (c) 2
  • [ ] (d) 3
  • [x] (e) 4
  • [ ] (f) 5
  • [ ] (g) y is NULL
  • [ ] (h) y is a dangling pointer
  • [ ] (i) Unable to determine from the information given
  • [ ] (j) None of the above

Problem 4

Consider the following program where we do not know what foo() does.

struct A {
    int* x;
};

struct A* create(int length) {
    struct A* a = malloc(sizeof(*a)); //**** [1]
    a->x = malloc(sizeof(*a->x) * length); //**** [3]
    return a;
}

void do() {
    struct A* l = create(100);
    foo(l);
    //**** [2]
    //**** [4]
}

For each of the four commented lines indicate what should be added or changed (if anything) in order manage the dynamic allocation this code performs in the best way possible

Options:

  • rc_keep_ref(l)
  • rc_keep_ref(l->x)
  • rc_free_ref(l)
  • rc_free_ref(l->x)
  • change or add nothing
  • change to use rc_malloc
  • free(x)
  • free(l->x)

[1]: change to use rc_malloc [2]: rc_free_ref(l->x) [3]: change to use rc_malloc [4]: rc_free_ref(l)