Trace/BPT trap in very simple C code compiled with clang

I wonder if this is correct behavior. I was surprised to get this result when compiling and running the following C code with Apple clang version 14.0.0 (clang-1400.0.29.102) target arm64-apple-darwin21.6.0 on a M1 Pro 12.7.6 with cc -O2 file.c:

#include <stdio.h>
#include <stdlib.h>

unsigned long long factorial(int n)
{
  unsigned long long fac = 1;
  while (n > 0)
    fac *= n;
  return fac;
}

int main()
{
  return factorial(1);
}

Compiling with -O2 and running this code gives "Trace/BPT trap".

Checking with LLDB:

$ lldb ./a.out
(lldb) target create "./a.out"
Current executable set to '/Users/engelen/Projects/Euler/a.out' (arm64).
(lldb) run
Process 79580 launched: '/Users/engelen/Projects/Euler/a.out' (arm64)
Process 79580 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x100003fb4)
    frame #0: 0x0000000100003fb4 a.out`main at 20.c:9:3 [opt]
   6   	  unsigned long long fac = 1;
   7   	  while (n > 0)
   8   	    fac *= n;
-> 9   	  return fac;
   10  	}
   11  	
   12  	int main()

The loop is non-terminating. But a breakpoint trap is triggered at the return statement. The code should just hang in the loop IMO, not trap, because it never updates variable n (a correct factorial function should decrement n). Never seen this before (not since I started wiring C code in the 80s.)

If I change the update *= into += then there is no trap.

Trace/BPT trap in very simple C code compiled with clang
 
 
Q