  Memory corruption errors in C/C++ programs remain the most common source of
security vulnerabilities in today's systems. Control-flow hijacking attacks
exploit memory corruption vulnerabilities to divert program execution away from
the intended control flow. Researchers have spent more than a decade studying
and refining defenses based on Control-Flow Integrity (CFI), and this technique
is now integrated into several production compilers. However, so far no study
has systematically compared the various proposed CFI mechanisms, nor is there
any protocol on how to compare such mechanisms.
  We compare a broad range of CFI mechanisms using a unified nomenclature based
on (i) a qualitative discussion of the conceptual security guarantees, (ii) a
quantitative security evaluation, and (iii) an empirical evaluation of their
performance in the same test environment. For each mechanism, we evaluate (i)
protected types of control-flow transfers, (ii) the precision of the protection
for forward and backward edges. For open-source compiler-based implementations,
we additionally evaluate (iii) the generated equivalence classes and target
sets, and (iv) the runtime performance.
