--- title: "Code Content Guidelines" layout: default permalink: /page_code_content.html ---
DynamoRIO
|
See also Development Workflow and Coding Style Conventions.
core/lib/statsx.h
for anything we might want to keep track of.core/utils.h
.strcpy
or sprintf
: use strncpy
and snprintf
instead. Use BUFFER_SIZE_ELEMENTS() for the size of statically-sized buffers. Always null-terminate buffers after calling strncpy
or snprintf
: for statically-sized buffers, use NULL_TERMINATE_BUFFER().Variable placement: .data is read-only!
For self-protection from inadvertent or malicious application activity, DynamoRIO uses a non-standard data section layout with five separate sections:
.rdata = read-only data
Mark all non-written variables as const
to get them into this section.
.data = rarely-written data
Variables that are written only during initialization, cleanup, or a handful of times during execution. This section is write-protected by default and only unprotected for small, infrequent windows of time. This is the default location for a variable (even if in .bss, if on Windows, though not on Linux currently due to PR 213296), so if you write to your new default-location variable after initialization DynamoRIO will crash! In debug builds a special self-protection message will alert you to crashes coming from attempts to write to .data.
If you must write to a variable after initialization, you can either unprotect it with this pair of macros (however, see the next item):
SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
Or you can move it to another section, probably .fspdata, like this:
DECLARE_FREQPROT_VAR(static vartype myvar, initial-value);
Only unprotect if you write very infrequently, as in zero times on any critical path. Keep an eye on the stats for unprotection calls and make sure you're not affecting performance and not opening up too many windows where the entire .data section is unprotected.
Do not keep pointers in a data section other than .data. If they must be writable, use indirection and keep them on the heap.
Think about whether non-pointers (booleans, counters) can be exploited before throwing them into unprotected sections. Can an overwrite of the variable in question cause us to stop protecting the application, or to lose control of the application?
Place all locks in .cspdata.
Be aware that DO_ONCE
introduces a window where .data is unprotected (see PR 212510).
.fspdata = frequently-written self-protected data
Variables that are written enough that we do not want to unprotect .data every time. We place them in a separate section called .fspdata (for "frequently self-protected data", referring to the number of times we need to change the page protections, which is proportional to the number of post-init writes) both for security and performance reasons. We moved any pointers in this category into structures on the heap, enabling us to move their base pointers into .data. Currently the heap is better protected than our data sections due to its better randomization and its guard pages. Try not to put new variables here as we hope to eventually eliminate this section. Note that this is not yet protected at all: PR 212508.
.cspdata = context-switch-written self-protected data
This is our section for locks, which are written so frequently that unprotecting them is best done at each context switch. Note that this is not yet protected at all: PR 212508.
.nspdata = not self-protected data
Debug-build-only variables, statistics, or data that is not persistent across code cache execution fall into this category of variables that we never protect. This section is always writable.
DynamoRIO has several other features for self-protection:
The DynamoRIO core must be absolutely transparent. It cannot interfere with the application's semantics. This means that extra care must be taken when using any operating system or shared library resources that might interact with the application's use of those resources. See the API documentation for more details. The following guidelines list some common mistakes to avoid.
Wait*
API routine. Use the system calls instead, which let you specify whether it should be alertable or not.heap_alloc
) or the global heap (via global_heap_alloc
). (In certain circumstances, such as inside signal handlers, other heaps should be used.) Always de-allocate memory. We cannot assume we will last as long as the application, since we may be detached before the application exits.stderr
or stdout
– due to FILE
problems on windows we use HANDLE
on windows and hide the distinction behind the file_t
type. Use the STDERR
and STDOUT
macros.save_fpstate
and restore_fpstate
(includes mmx & sse state) around your code if you really need floating point operations.