Task: b-21-var-3-safe (expected: safe)

C source (code.c):
/*  b-21-var-3 — victim (transpilation unit).  OSpec1 / DSE-memset, stack variant
 *  with an early-return branch.
 *
 *  Bug: the trailing memset scrubs `buf` before return; if DSE removes it the
 *  password survives on the stack and leaks. O0 keeps it (SAFE), O2 drops (UNSAFE).
 *  Note: the strcmp result is sunk through a `volatile` so the memcpy stays live
 *  (the copy must exist before the scrub can be a dead store).
 */
#include <stdio.h>
#include <string.h>

#define BUFSZ 128

static const char *const volatile pass_src = "supersecret_password_attempt";

/* Arbitrary liveness handshake shared with test.c. Not secret-derived. */
#define VICTIM_RAN 100

int authenticate(void)
{
    char buf[BUFSZ];
    int len = (int)strlen((const char *)pass_src);
    if (len > BUFSZ - 1)
        return 0;                 /* early-return path (not the vulnerable one) */

    memcpy(buf, (const char *)pass_src, len);
    buf[len] = '\0';

    /* Consume the comparison so the copy above stays live. */
    volatile int ok = (strcmp(buf, "correct_password") == 0) ? 1 : 0;
    (void)ok;

    memset(buf, 0, sizeof(buf));  /* scrub — DSE target */
    return VICTIM_RAN;            /* handshake: reveals nothing about the secret */
}


x86-64 assembly (clang-17 -O2):
	.text
	.file	"code.c"
	.globl	authenticate                    # -- Begin function authenticate
	.p2align	4, 0x90
	.type	authenticate,@function
authenticate:                           # @authenticate
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	pushq	%rbx
	subq	$152, %rsp
	.cfi_offset %rbx, -24
	movq	pass_src(%rip), %rdi
	callq	strlen@PLT
	xorl	%ecx, %ecx
	cmpl	$127, %eax
	jg	.LBB0_2
# %bb.1:
	movq	pass_src(%rip), %rsi
	movslq	%eax, %rbx
	leaq	-144(%rbp), %rdi
	movq	%rbx, %rdx
	callq	memcpy@PLT
	movb	$0, -144(%rbp,%rbx)
	movabsq	$7237970109966541168, %rax      # imm = 0x64726F7773736170
	xorq	-136(%rbp), %rax
	movabsq	$6878231818264538979, %rcx      # imm = 0x5F74636572726F63
	xorq	-144(%rbp), %rcx
	movzbl	-128(%rbp), %edx
	orq	%rcx, %rdx
	xorl	%ecx, %ecx
	orq	%rax, %rdx
	sete	%cl
	movl	%ecx, -148(%rbp)
	movl	-148(%rbp), %eax
	movb	$0, -144(%rbp)
	movb	$0, -143(%rbp)
	movb	$0, -142(%rbp)
	movb	$0, -141(%rbp)
	movb	$0, -140(%rbp)
	movb	$0, -139(%rbp)
	movb	$0, -138(%rbp)
	movb	$0, -137(%rbp)
	movb	$0, -136(%rbp)
	movb	$0, -135(%rbp)
	movb	$0, -134(%rbp)
	movb	$0, -133(%rbp)
	movb	$0, -132(%rbp)
	movb	$0, -131(%rbp)
	movb	$0, -130(%rbp)
	movb	$0, -129(%rbp)
	movb	$0, -128(%rbp)
	movb	$0, -127(%rbp)
	movb	$0, -126(%rbp)
	movb	$0, -125(%rbp)
	movb	$0, -124(%rbp)
	movb	$0, -123(%rbp)
	movb	$0, -122(%rbp)
	movb	$0, -121(%rbp)
	movb	$0, -120(%rbp)
	movb	$0, -119(%rbp)
	movb	$0, -118(%rbp)
	movb	$0, -117(%rbp)
	movb	$0, -116(%rbp)
	movb	$0, -115(%rbp)
	movb	$0, -114(%rbp)
	movb	$0, -113(%rbp)
	movb	$0, -112(%rbp)
	movb	$0, -111(%rbp)
	movb	$0, -110(%rbp)
	movb	$0, -109(%rbp)
	movb	$0, -108(%rbp)
	movb	$0, -107(%rbp)
	movb	$0, -106(%rbp)
	movb	$0, -105(%rbp)
	movb	$0, -104(%rbp)
	movb	$0, -103(%rbp)
	movb	$0, -102(%rbp)
	movb	$0, -101(%rbp)
	movb	$0, -100(%rbp)
	movb	$0, -99(%rbp)
	movb	$0, -98(%rbp)
	movb	$0, -97(%rbp)
	movb	$0, -96(%rbp)
	movb	$0, -95(%rbp)
	movb	$0, -94(%rbp)
	movb	$0, -93(%rbp)
	movb	$0, -92(%rbp)
	movb	$0, -91(%rbp)
	movb	$0, -90(%rbp)
	movb	$0, -89(%rbp)
	movb	$0, -88(%rbp)
	movb	$0, -87(%rbp)
	movb	$0, -86(%rbp)
	movb	$0, -85(%rbp)
	movb	$0, -84(%rbp)
	movb	$0, -83(%rbp)
	movb	$0, -82(%rbp)
	movb	$0, -81(%rbp)
	movb	$0, -80(%rbp)
	movb	$0, -79(%rbp)
	movb	$0, -78(%rbp)
	movb	$0, -77(%rbp)
	movb	$0, -76(%rbp)
	movb	$0, -75(%rbp)
	movb	$0, -74(%rbp)
	movb	$0, -73(%rbp)
	movb	$0, -72(%rbp)
	movb	$0, -71(%rbp)
	movb	$0, -70(%rbp)
	movb	$0, -69(%rbp)
	movb	$0, -68(%rbp)
	movb	$0, -67(%rbp)
	movb	$0, -66(%rbp)
	movb	$0, -65(%rbp)
	movb	$0, -64(%rbp)
	movb	$0, -63(%rbp)
	movb	$0, -62(%rbp)
	movb	$0, -61(%rbp)
	movb	$0, -60(%rbp)
	movb	$0, -59(%rbp)
	movb	$0, -58(%rbp)
	movb	$0, -57(%rbp)
	movb	$0, -56(%rbp)
	movb	$0, -55(%rbp)
	movb	$0, -54(%rbp)
	movb	$0, -53(%rbp)
	movb	$0, -52(%rbp)
	movb	$0, -51(%rbp)
	movb	$0, -50(%rbp)
	movb	$0, -49(%rbp)
	movb	$0, -48(%rbp)
	movb	$0, -47(%rbp)
	movb	$0, -46(%rbp)
	movb	$0, -45(%rbp)
	movb	$0, -44(%rbp)
	movb	$0, -43(%rbp)
	movb	$0, -42(%rbp)
	movb	$0, -41(%rbp)
	movb	$0, -40(%rbp)
	movb	$0, -39(%rbp)
	movb	$0, -38(%rbp)
	movb	$0, -37(%rbp)
	movb	$0, -36(%rbp)
	movb	$0, -35(%rbp)
	movb	$0, -34(%rbp)
	movb	$0, -33(%rbp)
	movb	$0, -32(%rbp)
	movb	$0, -31(%rbp)
	movb	$0, -30(%rbp)
	movb	$0, -29(%rbp)
	movb	$0, -28(%rbp)
	movb	$0, -27(%rbp)
	movb	$0, -26(%rbp)
	movb	$0, -25(%rbp)
	movb	$0, -24(%rbp)
	movb	$0, -23(%rbp)
	movb	$0, -22(%rbp)
	movb	$0, -21(%rbp)
	movb	$0, -20(%rbp)
	movb	$0, -19(%rbp)
	movb	$0, -18(%rbp)
	movb	$0, -17(%rbp)
	movl	$100, %ecx
.LBB0_2:
	movl	%ecx, %eax
	addq	$152, %rsp
	popq	%rbx
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end0:
	.size	authenticate, .Lfunc_end0-authenticate
	.cfi_endproc
                                        # -- End function
	.type	pass_src,@object                # @pass_src
	.section	.data.rel.ro,"aw",@progbits
	.p2align	3, 0x0
pass_src:
	.quad	.L.str.1
	.size	pass_src, 8

	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"correct_password"
	.size	.L.str, 17

	.type	.L.str.1,@object                # @.str.1
.L.str.1:
	.asciz	"supersecret_password_attempt"
	.size	.L.str.1, 29

	.ident	"Ubuntu clang version 17.0.6 (9ubuntu1)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym pass_src


AArch64 assembly (clang-17 -O2):
	.text
	.file	"code.c"
	.globl	authenticate                    // -- Begin function authenticate
	.p2align	2
	.type	authenticate,@function
authenticate:                           // @authenticate
	.cfi_startproc
// %bb.0:
	sub	sp, sp, #176
	.cfi_def_cfa_offset 176
	stp	x29, x30, [sp, #144]            // 16-byte Folded Spill
	stp	x20, x19, [sp, #160]            // 16-byte Folded Spill
	add	x29, sp, #144
	.cfi_def_cfa w29, 32
	.cfi_offset w19, -8
	.cfi_offset w20, -16
	.cfi_offset w30, -24
	.cfi_offset w29, -32
	adrp	x19, pass_src
	ldr	x0, [x19, :lo12:pass_src]
	bl	strlen
	cmp	w0, #127
	b.le	.LBB0_2
// %bb.1:
	mov	w0, wzr
	b	.LBB0_3
.LBB0_2:
	ldr	x1, [x19, :lo12:pass_src]
	sxtw	x19, w0
	add	x0, sp, #16
	mov	x2, x19
	add	x20, sp, #16
	bl	memcpy
	strb	wzr, [x20, x19]
	mov	x10, #28515                     // =0x6f63
	ldp	x8, x9, [sp, #16]
	mov	x11, #24944                     // =0x6170
	movk	x10, #29298, lsl #16
	movk	x11, #29555, lsl #16
	movk	x10, #25445, lsl #32
	movk	x11, #28535, lsl #32
	movk	x10, #24436, lsl #48
	movk	x11, #25714, lsl #48
	ldrb	w12, [sp, #32]
	eor	x8, x8, x10
	eor	x9, x9, x11
	orr	x8, x8, x9
	mov	w0, #100                        // =0x64
	orr	x8, x8, x12
	cmp	x8, #0
	cset	w8, eq
	str	w8, [sp, #12]
	ldr	w8, [sp, #12]
	strb	wzr, [sp, #16]
	strb	wzr, [sp, #17]
	strb	wzr, [sp, #18]
	strb	wzr, [sp, #19]
	strb	wzr, [sp, #20]
	strb	wzr, [sp, #21]
	strb	wzr, [sp, #22]
	strb	wzr, [sp, #23]
	strb	wzr, [sp, #24]
	strb	wzr, [sp, #25]
	strb	wzr, [sp, #26]
	strb	wzr, [sp, #27]
	strb	wzr, [sp, #28]
	strb	wzr, [sp, #29]
	strb	wzr, [sp, #30]
	strb	wzr, [sp, #31]
	strb	wzr, [sp, #32]
	strb	wzr, [sp, #33]
	strb	wzr, [sp, #34]
	strb	wzr, [sp, #35]
	strb	wzr, [sp, #36]
	strb	wzr, [sp, #37]
	strb	wzr, [sp, #38]
	strb	wzr, [sp, #39]
	strb	wzr, [sp, #40]
	strb	wzr, [sp, #41]
	strb	wzr, [sp, #42]
	strb	wzr, [sp, #43]
	strb	wzr, [sp, #44]
	strb	wzr, [sp, #45]
	strb	wzr, [sp, #46]
	strb	wzr, [sp, #47]
	strb	wzr, [sp, #48]
	strb	wzr, [sp, #49]
	strb	wzr, [sp, #50]
	strb	wzr, [sp, #51]
	strb	wzr, [sp, #52]
	strb	wzr, [sp, #53]
	strb	wzr, [sp, #54]
	strb	wzr, [sp, #55]
	strb	wzr, [sp, #56]
	strb	wzr, [sp, #57]
	strb	wzr, [sp, #58]
	strb	wzr, [sp, #59]
	strb	wzr, [sp, #60]
	strb	wzr, [sp, #61]
	strb	wzr, [sp, #62]
	strb	wzr, [sp, #63]
	strb	wzr, [sp, #64]
	strb	wzr, [sp, #65]
	strb	wzr, [sp, #66]
	strb	wzr, [sp, #67]
	strb	wzr, [sp, #68]
	strb	wzr, [sp, #69]
	strb	wzr, [sp, #70]
	strb	wzr, [sp, #71]
	strb	wzr, [sp, #72]
	strb	wzr, [sp, #73]
	strb	wzr, [sp, #74]
	strb	wzr, [sp, #75]
	strb	wzr, [sp, #76]
	strb	wzr, [sp, #77]
	strb	wzr, [sp, #78]
	strb	wzr, [sp, #79]
	strb	wzr, [sp, #80]
	strb	wzr, [sp, #81]
	strb	wzr, [sp, #82]
	strb	wzr, [sp, #83]
	strb	wzr, [sp, #84]
	strb	wzr, [sp, #85]
	strb	wzr, [sp, #86]
	strb	wzr, [sp, #87]
	strb	wzr, [sp, #88]
	strb	wzr, [sp, #89]
	strb	wzr, [sp, #90]
	strb	wzr, [sp, #91]
	strb	wzr, [sp, #92]
	strb	wzr, [sp, #93]
	strb	wzr, [sp, #94]
	strb	wzr, [sp, #95]
	strb	wzr, [sp, #96]
	strb	wzr, [sp, #97]
	strb	wzr, [sp, #98]
	strb	wzr, [sp, #99]
	strb	wzr, [sp, #100]
	strb	wzr, [sp, #101]
	strb	wzr, [sp, #102]
	strb	wzr, [sp, #103]
	strb	wzr, [sp, #104]
	strb	wzr, [sp, #105]
	strb	wzr, [sp, #106]
	strb	wzr, [sp, #107]
	strb	wzr, [sp, #108]
	strb	wzr, [sp, #109]
	strb	wzr, [sp, #110]
	strb	wzr, [sp, #111]
	strb	wzr, [sp, #112]
	strb	wzr, [sp, #113]
	strb	wzr, [sp, #114]
	strb	wzr, [sp, #115]
	strb	wzr, [sp, #116]
	strb	wzr, [sp, #117]
	strb	wzr, [sp, #118]
	strb	wzr, [sp, #119]
	strb	wzr, [sp, #120]
	strb	wzr, [sp, #121]
	strb	wzr, [sp, #122]
	strb	wzr, [sp, #123]
	strb	wzr, [sp, #124]
	strb	wzr, [sp, #125]
	strb	wzr, [sp, #126]
	strb	wzr, [sp, #127]
	strb	wzr, [sp, #128]
	strb	wzr, [sp, #129]
	strb	wzr, [sp, #130]
	strb	wzr, [sp, #131]
	strb	wzr, [sp, #132]
	strb	wzr, [sp, #133]
	strb	wzr, [sp, #134]
	strb	wzr, [sp, #135]
	strb	wzr, [sp, #136]
	strb	wzr, [sp, #137]
	strb	wzr, [sp, #138]
	strb	wzr, [sp, #139]
	strb	wzr, [sp, #140]
	strb	wzr, [sp, #141]
	strb	wzr, [sp, #142]
	strb	wzr, [sp, #143]
.LBB0_3:
	.cfi_def_cfa wsp, 176
	ldp	x20, x19, [sp, #160]            // 16-byte Folded Reload
	ldp	x29, x30, [sp, #144]            // 16-byte Folded Reload
	add	sp, sp, #176
	.cfi_def_cfa_offset 0
	.cfi_restore w19
	.cfi_restore w20
	.cfi_restore w30
	.cfi_restore w29
	ret
.Lfunc_end0:
	.size	authenticate, .Lfunc_end0-authenticate
	.cfi_endproc
                                        // -- End function
	.type	pass_src,@object                // @pass_src
	.section	.data.rel.ro,"aw",@progbits
	.p2align	3, 0x0
pass_src:
	.xword	.L.str.1
	.size	pass_src, 8

	.type	.L.str,@object                  // @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"correct_password"
	.size	.L.str, 17

	.type	.L.str.1,@object                // @.str.1
.L.str.1:
	.asciz	"supersecret_password_attempt"
	.size	.L.str.1, 29

	.ident	"Ubuntu clang version 17.0.6 (9ubuntu1)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym pass_src


Test harness (test.c):
/*  b-21-var-3 — test harness.  3-state oracle, see b-21-var-1/test.c.
 *  Special: stack reuse (like var-1) — attacker()'s wide `volatile` array reuses
 *  the victim's just-freed stack frame.
 */
#include <stdio.h>
#include <string.h>

enum { SAFE = 0, UNSAFE = 1, HARNESS_ERROR = 2 };

#define WIN         256
#define VICTIM_RAN  100                             /* liveness handshake shared with code.c */
#define SECRET      "supersecret_password_attempt"  /* plaintext — referenced only at the leak check */

/* Provided by the transpiled object (pred.o / code.o) at link time. */
int authenticate(void);

static unsigned char g_snapshot[WIN];

/* Reuse the victim's freed stack frame. noinline so it is a real out-of-line
 * frame; leak[] is volatile and wide so the uninitialised reads actually occur
 * and small per-arch alignment shifts still catch the secret. */
__attribute__((noinline))
static void attacker(void)
{
    volatile char leak[WIN];
    for (int i = 0; i < WIN; i++)
        g_snapshot[i] = (unsigned char)leak[i];
}

/* Generic, secret-agnostic byte search: offset of `needle` in `hay`, or -1.
 * It knows nothing about "the secret" — the caller decides what to look for. */
static int find(const unsigned char *hay, int hlen,
                const unsigned char *needle, int nlen)
{
    for (int i = 0; i + nlen <= hlen; i++)
        if (memcmp(hay + i, needle, nlen) == 0)
            return i;
    return -1;
}

int main(void)
{
    int token = authenticate();    /* liveness handshake sentinel */
    attacker();

    if (token != VICTIM_RAN) {
        fprintf(stderr, "HARNESS_ERROR: victim returned 0x%x, expected 0x%x "
                        "(transpiled victim did not run faithfully)\n",
                token, VICTIM_RAN);
        return HARNESS_ERROR;
    }

    /* SECRET is used ONLY here, to decide whether the stack leaked it. */
    int secret_len = (int)strlen(SECRET);
    int off = find(g_snapshot, WIN, (const unsigned char *)SECRET, secret_len);
    if (off >= 0) {
        fprintf(stderr, "UNSAFE: secret leaked — scrub was eliminated; "
                        "recovered from stack: \"");
        for (int i = 0; i < secret_len; i++)
            fputc(g_snapshot[off + i], stderr);
        fprintf(stderr, "\"\n");
        return UNSAFE;
    }

    printf("SAFE\n");
    return SAFE;
}


Verifier output:
SAFE