FutureAdvisor/RubyQP — pull request #5 by Umofomia (2012-03-29 03:43:02+00:00)
Title: Feature/memory handling

I split up the original `ruby_qp.c` file into multiple source and header files for better componentization of various functionality:

* `ruby_qp.h` contains core declarations.
* This includes core macro definitions used to handle memory allocation and deallocation (more on this below).
* `qp_gsl.h` contains GSL-related declarations.
* `qp_ipopt.h` contains Ipopt-related declarations.
* `qp_ipopt_callbacks.c` defines the callback functions that the Ipopt solver will call.
* `qp_ipopt_status.c` defines the functions that handle Ipopt status.
* `qp_types.h` contains declarations of custom data types used by RubyQP and functions used to convert data types.
* `qp_types.c` defines the functions to convert data types.

Most of the work went into systematizing how functions are defined and how memory is allocated and deallocated. This makes it much more easy to spot potential memory leaks.

All functions should follow these rules:

* Never return from the middle of a function.
* Never raise a Ruby exception from the middle of a function. They should only be raised only at the end of the cleanup section.
* Never allocate memory that is not freed at the end of the function.

The original code had several functions that allocated data structures that were returned to the caller; it was then the caller's responsibility to free these structures. This is no longer the case in the new code; functions now work on structures that the caller allocates and frees.

`QP_STATUS` is a type that was defined for functions that need to return a success or failure code. Any function that returns a `QP_STATUS` should be defined as follows:

```c
QP_STATUS
function_name(/* args */) {
QP_STATUS_INIT;

/*
Rest of function goes here.
Status can be set using QP_STATUS_SET(status); if status is not set, it defaults to QP_SUCCESS.
Status can be checked using QP_STATUS_FAILED or QP_STATUS_SUCCEEDED.
*/

QP_STATUS_RETURN;
}
```

Functions that allocate memory should have a `qp_cleanup:` section that frees any allocated memory. Macros have been defined to work with memory allocation and deallocation. The general macros include `QP_MALLOC`, `QP_MALLOC_N`, and `QP_FREE`, but some of the other headers define additional ones for their respective data types, such as `QP_GSL_MATRIX_ALLOC`, among others. All allocation and deallocation calls must go through these macros. These functions have the following structure:

```c
void
function_name(/* args */) {
// variable declaration section
int num1, num2;
data_struct *data1, *data2;
VALUE rubyObj;

// variable initialization section
num1 = num2 = 0;
data1 = data2 = NULL;
rubyObj = Qnil;

/*
Rest of function goes here.
Memory allocations look like:
QP_MALLOC(data1, data_struct);
Any allocations that fail go directly to the qp_cleanup section.
QP_CLEANUP can be called to go to the qp_cleanup section as well.
QP_CLEANUP_ON_NULL and QP_CLEANUP_ON_FAIL are helper macros that go to qp_cleanup
when the specified parameter is null or has a failed QP_STATUS, respectively.
*/

qp_cleanup:
QP_FREE(data1);
QP_FREE(data2);
}
```

Note that all local variables should be declared at the top and must be initialized. Numerical values can be initialized to `0`, pointers to `NULL`, and Ruby `VALUE`s to `Qnil`. Any pointers need to be freed in the cleanup section. As long as all of these are consistent, there should be no memory leak issues.

For functions that return both a status and allocate memory, the two can be combined:

```c
QP_STATUS
function_name(/* args */) {
QP_STATUS_INIT;

// variable declaration section
int num1, num2;
data_struct *data1, *data2;
VALUE rubyObj;

// variable initialization section
num1 = num2 = 0;
data1 = data2 = NULL;
rubyObj = Qnil;

/*
Rest of function goes here.
QP_CLEANUP_WITH_STATUS_ON_FAIL can be used to preserve the status code of a function
call with a failed QP_STATUS.
QP_CHECK can be used to set the status to failed and automatically jump to the cleanup
section if a expression fails to evaluate to true.
*/

qp_cleanup:
QP_FREE(data1);
QP_FREE(data2);

QP_STATUS_RETURN;
}
```