Logic in the synchroniser path is the most common structural violation, and it takes two forms: gates between the source flop and the first synchroniser flop, and gates between the two synchroniser flops. Both destroy the guarantee the circuit is built on.
A gate between the source flop and the first flop reintroduces glitches. The source flop's output is clean, but the gate's output can spike while its inputs settle, and the first flop samples those spikes as data. The synchroniser then faithfully delivers a glitch to the destination.
// bad-example: a decoder output feeding the synchroniser can glitch
always_comb ready_sel = dec_a & dec_b; // spikes while dec_a/dec_b settle
sync2 u_sync (.clk(clk_b), .d(ready_sel), .q(ready_b)); // captures the spikeThe fix is to register the decoded value in the source domain and cross the register output, so the synchroniser input changes at most once per source cycle.
A gate between the two flops is worse: it eats directly into the resolution time the first flop was promised, and its output can glitch exactly when the second flop samples. There is also a reconvergence angle: if the first flop's output fans out to two gates whose results recombine, the two paths can sample its hovering output differently and the recombined value is corrupt even though each path looked synchronised.
The fix is structural: keep the synchroniser a self-contained two-flop module with no inputs except the source bit and no taps except the final output. Any needed logic goes after the second flop, in the destination domain, where it is ordinary synchronous logic.
Structural analysis traces the path from the first synchroniser flop to the second and flags any combinational cell on it, and likewise traces the source flop to the first flop. Review hygiene: the synchroniser lives in its own wrapper module, so there is nowhere for stray logic to hide.
The mux output can glitch when the select or inputs change. Either register the mux output in the source domain before the synchroniser, or synchronise the two signals separately and mux after the second flops in the destination domain.
The hovering output can be read differently on the two paths, so the OR can produce a value that is neither the old nor the new one. This is reconvergence on a possibly metastable signal; only the second flop's output may fan out.