Using the __cleanup__ variable attribute in GCC

GCC’s C compiler allows you to define various variable attributes. One of them is the cleanup attribute (which you can also write as __cleanup__) which allows you to define a function to be called when the variable goes out of scope (for example, before returning from a function). This is useful, for example to never forget to close a file or freeing the memory you may have allocated. Next up is a demo example defining this attribute on an integer variable (which obviously has no practical value). I am using gcc (GCC) 4.7.2 20121109 on Fedora 18.

Demo

The next code listing declares an integer variable, avar with the cleanup attribute set such that the function clean_up is called before main() returns (Line no. 27).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# include <stdio.h>

/* Demo code showing the usage of the cleanup variable
   attribute. See:http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
*/

/* cleanup function
   the argument is a int * to accept the address
   to the final value
*/

void clean_up(int *final_value)
{
  printf("Cleaning up\n");
  printf("Final value: %d\n",*final_value);

}

int main(int argc, char **argv)
{
  /* declare cleanup attribute along with initiliazation
     Without the cleanup attribute, this is equivalent 
     to:
     int avar = 1;
  */
  
  int avar __attribute__ ((__cleanup__(clean_up))) = 1;
  avar = 5;

  return 0;
}

The clean_up function above accepts an argument which is an integer pointer. This is a pointer to the integer variable avar for which this function is called due to the __cleanup__ attribute being set. When you compile and execute the program, you should see the following output:

$ gcc -Wall cleanup_attribute_demo.c
$ ./a.out
Cleaning up
Final value: 5

Download cleanup_attribute_demo.c. Next, I will present a hopefull more useful example.

Cleaning up temporary files

In your programs, you may need to create one or more temporary files for some reason. Most likely, you would want to remove them after your program exits. Defining a __cleanup__ attribute on the FILE * variable (assuming stream I/O) and setting it to an appopriate cleanup function sounds like something which could be put to good use. We don’t have to manually call the cleanup function.

Here is the program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* Demo code showing the usage of the cleanup variable
   attribute. See:http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
*/

/* Defines two cleanup functions to close and delete a temporary file
   and free a buffer
*/

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

# define TMP_FILE "/tmp/tmp.file"

void free_buffer(char **buffer)
{
  printf("Freeing buffer\n");
  free(*buffer);
}

void cleanup_file(FILE **fp)
{
  printf("Closing file\n");
  fclose(*fp);

  printf("Deleting the file\n");
  remove(TMP_FILE);
}

int main(int argc, char **argv)
{
  char *buffer __attribute__ ((__cleanup__(free_buffer))) = malloc(20);
  FILE *fp __attribute__ ((__cleanup__(cleanup_file)));

  fp = fopen(TMP_FILE, "w+");
  
  if (fp != NULL)
    fprintf(fp, "%s", "Alinewithnospaces");

  fflush(fp);
  fseek(fp, 0L, SEEK_SET);
  fscanf(fp, "%s", buffer);
  printf("%s\n", buffer);
  
  return 0;
}

The above program creates a temporary file in the location specified by TMP_FILE, writes a line of text with no spaces, resets the file pointer to the beginning and reads it back. In line no.32, I declare a variable fp of type FILE* and define the __cleanup__ attribute such that the function cleanup__file will be called upon the return of the main() function. This function closes the file and also deletes it from the file system. When you run your program, you should see the following output:

Alinewithnospaces
Closing file
Deleting the file
Freeing buffer

If you check the existence of the file specified by TMP_FILE, you will see that it doesn’t exist. Note how I also use define the __cleanup__ attribute on the variable, buffer to automatically free memory as well.

Download cleanup_tempfile.c.

Resources

I first came across this attribute while reading Understanding and Using C Pointers (Link to my review) where the author discusses RAII. Take a look at how the RAII_VARIABLE macro is defined using the __cleanup__ attribute (In case you didn’t know, ## is concatenation in C macros).