DynamoRIO
Container Data Structures

The drcontainers DynamoRIO Extension provides container data structures that use the DR API for memory allocation and synchronization.

Setup

To use drcontainers with your client simply include this line in your client's CMakeLists.txt file:

use_DynamoRIO_extension(clientname drcontainers)

That will automatically set up the include path and library dependence.

Hashtable

The hashtable supports integer, string, and custom hash keys, and has synchronization and memory allocation and deallocation parametrized for flexible usage. See hashtable_init_ex() and related functions.

DrVector

The drvector DynamoRIO Extension provides a simple resizable array (a vector).

Initialization

Initialize a vector with drvector_init():

drvector_init(&vec, /*initial_capacity=*/10, /*synch=*/true, free_callback);
bool drvector_init(drvector_t *vec, uint initial_capacity, bool synch, void(*free_data_func)(void *))
Definition: drvector.h:63

To provide additional configuration parameters, use drvector_init_ex():

drvector_config_t config = {/*size=*/sizeof(config), /*zero_alloc=*/true};
drvector_init_ex(&vec, /*initial_capacity=*/10, /*synch=*/true, free_callback, &config);
bool drvector_init_ex(drvector_t *vec, uint initial_capacity, bool synch, void(*free_data_func)(void *), drvector_config_t *config)
Definition: drvector.h:57

The initial_capacity can be 0, in which case the internal array is lazily allocated upon the first insertion (using an internal default initial size).

Operations

Entries can be added to the end of the vector using drvector_append():

drvector_append(&vec, data);
bool drvector_append(drvector_t *vec, void *data)

Entries can be retrieved or set by index:

void *data = drvector_get_entry(&vec, 5);
drvector_set_entry(&vec, 3, new_data);
bool drvector_set_entry(drvector_t *vec, uint idx, void *data)
void * drvector_get_entry(drvector_t *vec, uint idx)

drvector_get_entry() returns NULL if the index is out of bounds.

For an unsynchronized vector, the caller is free to directly access the array field of the drvector_t structure for better performance.

drvector_set_entry() will automatically resize the vector if the index is beyond the current capacity. It also updates the number of entries to be idx + 1 if the index is greater than or equal to the current number of entries. Note that entries in between the last set index and the current index are left uninitialized (unless drvector_config_t.zero_alloc is set), hence clearing or deleting a vector that has a free_callback set can be problematic, as the free_callback function will be called on uninitialized entries. It's the user's responsibility to set all entries prior to the free_callback being called.

Synchronization

The vector can be initialized to automatically synchronize each operation by passing true for the synch parameter to drvector_init() or drvector_init_ex().

Even when synch is false, the vector's lock is initialized and can be manually acquired and released:

/* perform multiple operations or access vec->array directly */
void drvector_unlock(drvector_t *vec)
void drvector_lock(drvector_t *vec)

Memory Management

A callback for freeing each data item can be provided to drvector_init() or drvector_init_ex(). This callback is called for each entry when drvector_delete() or drvector_clear() is called.

The drvector_config_t.zero_alloc field can be set to true to ensure that the memory allocated for the vector's internal storage is zeroed. This is typically set via drvector_init_ex(). When zero_alloc is true, drvector_clear() also zeros the entire storage after calling free_callback.

To completely free the vector's storage:

bool drvector_delete(drvector_t *vec)

To clear the vector without freeing its internal storage:

bool drvector_clear(drvector_t *vec)

Example

void free_data(void *ptr) {
dr_global_free(ptr, sizeof(int));
}
drvector_config_t config = {/*size=*/sizeof(config), /*zero_alloc=*/true};
drvector_init_ex(&vec, /*initial_capacity=*/0, /*synch=*/false, free_data, &config);
int *data = dr_global_alloc(sizeof(int));
*data = 42;
drvector_append(&vec, data);
/* Accessing by index */
int *val = (int *)drvector_get_entry(&vec, 0);
/* Direct access (unsynchronized) */
if (vec.entries > 0)
val = (int *)vec.array[0];
DR_API void dr_global_free(void *mem, size_t size)
DR_API void * dr_global_alloc(size_t size)
void ** array
Definition: drvector.h:66
uint entries
Definition: drvector.h:64

DrTable

The DrTable is a resizable array that does not relocate data, enabling a user to use pointers to access array entries directly.