.
CPSC 213 – 2018 Winter Term 2
Exam Review: Memory-Related Bugs and Reference Counting
1 [1 marks] Consider each of the following pieces of C code to determine whether it contains (or may contain) a memory-related problem. Label each of the following code snippets as one of the following:
A: There is no memory leak or dangling pointer; nothing needs to be changed with malloc or free.
B: There is no memory leak or dangling pointer, but the code would be improved by moving malloc or free. C: There is a possible memory leak that is best resolved by adding, removing or moving malloc or free.
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. F: There is a possible dangling pointer that is best resolved by adding reference counting.
You can assume that the starting point for each snippet of code is a call to foo, and that copy is in a different module. Do not fix any bugs; for each part, fill in a single multiple choice bubble based off of the options above. Most of the code snippets are very similar. Changes from previous versions and/or key things to look for in bold font.
1a
1b
1c
int* copy(int s) {
int d = s;
return &d;
void foo(int s) {
int* d = copy(s);
printf(“value is %d”, *d);
}}
ABCDEF
E. Dangling pointer. Returning the address of a local variable.
int* copy(int s) {
int* d = malloc(sizeof(int));
*d = s;
void foo (int s) {
int* d = copy(s); printf(“value is %d”, *d); free(d);
ABCDEF
B. There is no memory leak or dangling pointer, but the code would be improved by moving malloc or free
return d; }}
1d
void copy(int s, int* d) {
void foo (int s) {
int d = 0;
copy(s, &d);
printf(“value is %d”, d);
}
int* copy(int s) {
int* d = malloc(sizeof(int)); *d = s;
free(d);
return d;
void foo (int s) {
int* d = copy(s);
printf(“value is %d”, *d);
}
}
E: There is a possible dangling pointer that is best resolved by adding, removing or moving malloc and/or free.
}
ABCDEF
*d = s;
ABCDEF
A: There is no memory leak or dangling pointer; nothing needs to be changed with malloc or free.
1f
void copy(int s, int* d) {
*d = s;
.
1e
void copy(int s, int* d) {
*d = s;
}
void foo (int s) {
int* d = malloc (sizeof(int));
copy(s, d);
free(d);
printf(“value is %d”, *d);
}
ABCDEF
E: There is a possible dangling pointer that is best resolved by adding, removing or moving malloc and/or free.
}
void foo (int s) {
int* d = malloc (sizeof(int)); copy(s, d);
printf(“value is %d”, *d); free(d);
}
ABCDEF
1g
void copy(int s, int* d) {
*d = s;
A: There is no memory leak or dangling pointer; nothing needs to be changed with malloc or free.
}
void foo (int s) {
int* d = malloc (sizeof(int)); copy(s, d);
printf(“value is %d”, *d); process(d);
free(d);
}
ABCDEF
F: There is a possible dangling pointer that is best resolved by adding reference counting.
1h
void foo (int s) {
int* d = malloc (sizeof(int)); copy(s, d);
printf(“value is %d”, *d); process(*d);
free(d);
}
ABCDEF
void copy(int s, int* d) {
*d = s;
}
A: There is no memory leak or dangling pointer; nothing needs to be changed with malloc or free.
2
.
2 [1 marks]
Consider the following C code.
int* b;
void set (int i) { b [i] = i;
}
Is there a bug in this code? If so, carefully describe what it is.
Yes; this code does not provide the caller with a way to ensure that the procedure does not overflow the array b. The proceduresetshouldhaveanadditionalparameternandtheassignment¡°b [i] = i¡±shouldbepredicatedbythe ifstatement¡°if (i < n¡±
3 [1 marks]
Consider the following C code.
int* one () { int loc = 1;
return &loc;
}}
void two () { int zot = 2;
}
3a Isthereabuginthiscode?Ifso,carefullydescribewhatitis.
3b Whatisthevalueof¡°*ret¡±attheendofthree?Explaincarefully.
2, because the local variable zot will occupy the same memory location as the local variable loc did.
void three () {
int* ret = one(); two();
Yes; one returns the address of a local variable and three saves it in the variable ret and thus ret is a dangling pointer. Luckily the code does not dereference this dandling pointer and so the code would execute okay. But adding a statement of the form *ret to three would be a serious problem.
3
.
4 [1 marks] The following code attempts to implement reference counting, but the reference counts are not handled correctly.
4a Whatisthereferencecountvalueoutput(intheboldprintfstatement). 4
4b Determinewhatthereferencecountshouldbeoutputbytheprintfstatementifreferencecountinghadbeen correctly implemented.
1
4c Modifythecode(mostlybyadding/removingadd_refand/ordec_refprocedurecalls),sotheprogram correctly implements reference counting.
struct item {
int ref_count;
int data;
};
struct item *adder = NULL;
int number = 0;
void inc_ref(struct item *i)
{
i->ref_count++;
}
void dec_ref(struct item* i) {
i->ref_count–;
if (i->ref_count == 0)
free(i); }
struct item *process(struct item *temp) { if (adder) dec_ref(adder);
adder = temp;
inc_ref(adder);
adder->data = adder->data + 1;
return adder;
}
struct item *make_item() {
struct item* i = (struct item*)malloc(sizeof(struct item));
i->ref_count = 1;
i->data = number++;
struct item *j = process(i);
// inc_ref(j);
return i;
}
int main (void) {
struct item *i1 = make_item();
// inc_ref(i1);
struct item *i2 = make_item();
// inc_ref(i2);
printf(“i1¡¯s ref count: %d”, i1->ref_count); //What should i1->ref_count be here?
…
}
4
.
5 [1 marks] There are four memory related errors in the program below. For each error, explain what type of error it is, and indicate how to fix it.
[1] struct Transcript {
[2] int cs_id;
[3] int gpa;
[4] int refcount;
[5] };
[6]
[7] struct Transcript *top;
[8]
[9] void maybe_top_student(struct Transcript *cur) {
[10] if ((top == NULL) ll (top && cur->gpa > top->gpa)) {
[11] if (top != NULL) {
[12] dec_ref(top);
[13] }
[14] top = cur;
[15] }
[16] }
[17]
[18] int convert_to_gpa(int grade) { /*assume this correctly returns gpa* }
[19]
[20] void init(int *a, int n, struct Transcript* t) {
[21] int sum=0;
[22] int high[5];
[23] for
[24]
[25]
[26] }
[27] t->gpa = sum/n;
[28] }
(inti=0;i
[33] t->cs_id = cs_id;
[34] init(nums, size, t);
[35] return t;
[36] }
[37]
[38] void print_info(struct Transcript* t) {
[39] printf(“student id: %d, gpa: %d”, t->cs_id, t->gpa);
[40] free(t);
[41] }
[42]
[43] int main() {
[44] // ASSUME all variables have been correctly initialized here
[45] // nums is a 2d-array of integers; size is the number of grade
[46] // entries at each index of nums; and cs_ids is the associated id.
[47]
[48] for (int i = 0; i < NUM_STUDENTS; i++) {
[49] struct Transcript* s1 = create_transcript(nums[i], size[i], cs_ids[i]);
[50] maybe_top_student(s1);
[51] print_info(s1);
[52] }
[53] printf("The top student in the class is:");
[54] print_info(top);
[55] }
5
.
5a Error1: explanation:
fix:
5b Error2: explanation:
fix:
5c Error3: explanation:
fix:
5d Error4: explanation:
fix:
1. line 15, ref count value incorrect, add inc ref(top);
2. line 23, array bounds problem, make sure n is never greater than 5 3. line 32, ref count value incorrect, refcount = 1
4. line 40, free will cause dangling pointer, change to dec ref(t);
6
.
6 [1 marks] Consider the following code that is implemented in three independent modules (and a main module) that share dynamically allocated objects that should be managed using reference counting. The call to rc_malloc has been added for you; recall that rc_malloc sets the allocated object¡¯s reference count to 1.
6a Whatdoesthisprogramprintwhenitexecutes? 20 10
6b Addcallstorc_keep_refandrc_free_reftocorrectimplementreferencecountingforthisprogram (all modules).
6c Assuming part 1b was completed so that the program implements reference counting correctly, give the reference counts of the following two objects when printf is called from main?
*p: 3 *q: 5
6d Add code at point TODO so that the program is free of memory leaks and dangling pointers. Your code may call any of the procedures shown here as well as rc_free_ref. It may not directly access the global variable b_values (note that this variable is not listed in the ¡°header file contents¡± section of the code and so it would not be in scope in main if the modules were implemented is separate files).
7
/***********
* Module a
*/
int* a_create(int i) {
int* value = rc_malloc(sizeof(int));
*value = i;
return value;
}
/**********
* Module b
*/
#define B_SIZE 4
int* b_values[B_SIZE];
void b_init() {
for (int i=0; i