Skip to content

Commit dddddb0

Browse files
committed
Enforce alignment of stinger sub-structures.
STINGER makes one large contiguous allocation, then packs several sub- structures into this chunk of memory. The alignment of each struct within the chunk depends on the total length of all the structs and arrays before it. According to section 8.1.1 of the Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 3A, "Accesses to cacheable memory that are split across cache lines and page boundaries are not guaranteed to be atomic". Operations like readfe() and writeef() can cause deadlocks if they operate on pointers to unaligned 64-bit data. Most sub-structures are composed of int64_t's, so they are aligned regardless of size. But stinger_names includes char arrays, the size of which is specified by the configuration variable STINGER_NAME_STR_MAX, plus one for a null terminator byte. The default value of 255 works, but changing this value can break the alignment of the other structures, causing deadlocks. This patch adds several checks to ensure that the all of the STINGER sub-structures are aligned to an 8-byte boundary.
1 parent 92348d4 commit dddddb0

3 files changed

Lines changed: 41 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ set(STINGER_DEFAULT_NEB_FACTOR "4" CACHE STRING "Default number of edge blocks p
139139
set(STINGER_EDGEBLOCKSIZE "14" CACHE STRING "Number of edges per edge block")
140140
set(STINGER_NAME_STR_MAX "255" CACHE STRING "Max string length in physmap")
141141

142+
MATH(EXPR STINGER_NAME_STR_MAX_ALIGN "(${STINGER_NAME_STR_MAX}+1) % 8")
143+
if (NOT STINGER_NAME_STR_MAX_ALIGN EQUAL 0)
144+
MESSAGE(SEND_ERROR "STINGER_NAME_STR_MAX must be a multiple of 8 (minus one for null terminator).")
145+
endif()
146+
142147
configure_file(${CMAKE_SOURCE_DIR}/lib/stinger_core/inc/stinger_defs.h.in ${CMAKE_BINARY_DIR}/include/stinger_core/stinger_defs.h @ONLY)
143148
configure_file(${CMAKE_SOURCE_DIR}/lib/stinger_core/inc/stinger_names.h.in ${CMAKE_BINARY_DIR}/include/stinger_core/stinger_names.h @ONLY)
144149

lib/stinger_core/inc/stinger_names.h.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ extern "C" {
88

99
#define NAME_STR_MAX @STINGER_NAME_STR_MAX@
1010

11+
// STINGER names storage must be 8-byte aligned
12+
#if (NAME_STR_MAX+1) % 8 != 0
13+
#error STINGER_NAME_STR_MAX must be a multiple of 8 (minus one for null terminator)
14+
#endif
15+
1116
#ifdef NAME_USE_SQLITE
1217
#include "sqlite/sqlite3.h"
1318

lib/stinger_core/src/stinger.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,31 @@ stinger_graph_size (const struct stinger *S)
467467
return result;
468468
}
469469

470+
/**
471+
* Checks the size of a stinger sub-structure, to make sure we aren't
472+
* violating any alignment rules. malloc() will return a pointer that
473+
* is properly aligned for any struct or array of structs. But when we
474+
* pack multiple structures into the same allocation, we run the risk of
475+
* a struct being misaligned. As long as each sub-structure ends on an
476+
* 8-byte boundary, the next one will start on an 8-byte boundary.
477+
* @param sz Size of sub-structure, in bytes
478+
* @param substructure_name Name of sub-structure, used when printing an error
479+
*/
480+
static void
481+
check_alignment(int64_t sz, const char* substructure_name)
482+
{
483+
if (sz % sizeof(int64_t) != 0) {
484+
LOG_F_A(
485+
"The sub-structure %s is %lli bytes long.\n"
486+
"The following struct will not be aligned to an 8-byte boundary.\n"
487+
"This can cause deadlocks when x86 64-bit atomics cross a cache line. \n"
488+
"See section 8.1.1 of the Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 3A. \n"
489+
,substructure_name, (long long int)sz
490+
);
491+
abort();
492+
}
493+
}
494+
470495
/**
471496
* @brief Calculates the required memory to allocate a STINGER given a set of parameters
472497
*
@@ -484,21 +509,27 @@ struct stinger_size_t calculate_stinger_size(int64_t nv, int64_t nebs, int64_t n
484509

485510
ret.vertices_start = 0;
486511
sz += stinger_vertices_size(nv);
512+
check_alignment(sz - ret.vertices_start, "stinger_vertices");
487513

488514
ret.physmap_start = sz;
489515
sz += stinger_physmap_size(nv);
516+
check_alignment(sz - ret.physmap_start, "stinger_physmap");
490517

491518
ret.ebpool_start = sz;
492519
sz += netypes * stinger_ebpool_size(nebs);
520+
check_alignment(sz - ret.ebpool_start, "stinger_ebpool");
493521

494522
ret.etype_names_start = sz;
495523
sz += stinger_names_size(netypes);
524+
check_alignment(sz - ret.etype_names_start, "stinger_etype_names");
496525

497526
ret.vtype_names_start = sz;
498527
sz += stinger_names_size(nvtypes);
528+
check_alignment(sz - ret.vtype_names_start, "stinger_vtype_names");
499529

500530
ret.ETA_start = sz;
501531
sz += netypes * stinger_etype_array_size(nebs);
532+
check_alignment(sz - ret.ETA_start, "stinger_etype_array");
502533

503534
ret.size = sz;
504535

0 commit comments

Comments
 (0)