Where does the bug appear (feature/product)?
- Cloud Agents & Automations
Describe the Bug
A Cursor Cloud Agent intermittently loses the contents of the Intel AMX TILEDATA registers across scheduling/blocking.
I reduced this to a small standalone C reproducer with no dependency on OpenVINO, oneDNN, Python, or any application code.
The program:
- requests AMX TILEDATA permission;
- loads a known non-zero pattern into all 8 AMX tile registers;
- performs a 1 ms
nanosleep using a direct syscall;
- stores the tiles back and compares them with the original data.
On failing iterations, all 8192 bytes of TILEDATA come back as zero, while TILECFG is unchanged and the syscall succeeds.
There are no function calls while the AMX tiles are live. I verified the generated code with both GCC and Clang.
The same minimal reproducer was independently tested by a Linux x86 maintainer on upstream kernel configurations for 100,000 trials without a failure. Their recommendation was to test the same Cursor worker class with an upstream guest kernel.
The affected Cursor worker currently runs a custom 6.12.94+ guest kernel.
Steps to Reproduce
Save the attached amx_min.c, then:
gcc -O2 -g -Wall -Wextra -Werror -mamx-tile -fno-plt \
amx_min.c -o amx_min
Run it on an allowed CPU:
timeout --kill-after=2s 20s taskset -c 0 ./amx_min
Control:
timeout --kill-after=2s 20s taskset -c 0 ./amx_min getpid
On this Cloud Agent, repeated runs produced:
GCC 13.3.0
nanosleep: 5/300, 5/300, 4/300 failures
getpid: 0/300, 0/300 failures
Clang 18.1.3
nanosleep: 3/300 failures
getpid: 0/300 failures
A typical failure is:
First mismatch: 8192/8192 bytes are zero; TILECFG unchanged
The failure is intermittent, so one clean run does not necessarily mean the environment is unaffected.
Under CPU contention it reproduces much more reliably; a separate test with no syscall in the live-tile interval also reproduces the loss.
Expected Behavior
AMX TILEDATA belonging to the process should be preserved when the process is scheduled out and resumed.
After nanosleep returns, the values stored from the AMX tiles should match the values loaded before the sleep.
They should not silently become zero.
Screenshots / Screen Recordings
Not applicable.
I can provide:
- the minimal standalone C reproducer;
- failing output and binary dumps;
- disassembly from GCC and Clang;
- the more extensive diagnostic suite;
- the response from the Linux x86 maintainer who tested the reproducer upstream.
Operating System
Cloud Agent guest:
Linux cursor 6.12.94+
#1 SMP PREEMPT_DYNAMIC Mon Sep 7 16:15:06 UTC 2026 x86_64 GNU/Linux
CPU exposed to guest:
Intel Xeon
family 6, model 207, stepping 2
4 vCPUs
AMX_TILE / AMX_BF16 / AMX_INT8 exposed
Virtualization detected from the guest:
KVM
Firecracker
Version Information
This is a Cloud Agent infrastructure/kernel issue rather than an IDE or Cursor CLI issue.
Relevant guest environment:
Guest kernel: 6.12.94+
Kernel build: "#1 SMP PREEMPT_DYNAMIC Mon Sep 7 16:15:06 UTC 2026"
Architecture: x86_64
VMM visible from guest: Firecracker / KVM
Compiler reproductions:
GCC: 13.3.0
Clang: 18.1.3
For AI issues: which model did you use?
Not applicable. The issue reproduces in a standalone native C program and does not involve an AI model.
For AI issues: add Request ID with privacy disabled
Not applicable.
Additional Information
Linux x86 upstream tested the same minimal reproducer and reported 0 failures over 100,000 trials using:
- a v7.2 guest kernel with a v6.12-based host kernel;
- a v7.2 guest kernel with a vanilla v7.3-rc2 host kernel.
Their recommendation was to rerun the reproducer on the Cursor infrastructure with an upstream guest kernel to distinguish the Cursor custom guest kernel from the host/VMM.
I tried to perform that control experiment from inside the Cloud Agent, but nested KVM is not usable on this worker.
The environment exposes VMX and KVM:
CPUID.VMX=1
nested=Y
KVM_CREATE_VM succeeds
KVM_CAP_NESTED_STATE=8320
but a minimal program calling KVM_CREATE_VCPU(0) causes the Cursor guest kernel to BUG:
kernel BUG at arch/x86/kvm/x86.c:702
RIP: kvm_spurious_fault+0xe/0x10
alloc_loaded_vmcs+0x108/0x190
vmx_vcpu_create+0xa7/0x490
kvm_arch_vcpu_create
kvm_vm_ioctl_create_vcpu
I investigated this separately and localized the fault to VMCLEAR inside alloc_loaded_vmcs().
I am not claiming that this nested-KVM problem causes the AMX corruption. They may be unrelated. It only prevents me from running the upstream-guest-kernel control experiment requested by the Linux maintainer.
The most useful next step from the Cursor infrastructure side would therefore be either:
- run
amx_min.c on the same Cloud Agent worker class with an upstream guest kernel (v6.12.94, current stable, or similar); or
- provide the exact source/patchset and
.config used to build Cursor’s 6.12.94+ guest kernel.
That single comparison should tell us whether to investigate primarily the Cursor guest kernel or the host/VMM side.
I have standalone reproducers and full logs for both issues and am happy to provide anything useful for debugging.
Does this stop you from using Cursor?
- No - Cursor works, but with this issue
It does not make Cursor itself unusable, but workloads using AMX can silently produce incorrect results on the affected Cloud Agent, which is considerably more serious than a crash for those workloads.
/*
* Minimal KVM ioctl probe: open /dev/kvm, KVM_GET_API_VERSION,
* KVM_CREATE_VM, KVM_CREATE_VCPU. Does not start a guest.
*
* One-shot diagnostic for Cursor Cloud Agent nested VMX.
*/
#include <errno.h>
#include <fcntl.h>
#include <linux/kvm.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main(void)
{
int kvm, vm, vcpu;
int api;
printf("pid=%d\n", getpid());
fflush(stdout);
kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
if (kvm < 0) {
fprintf(stderr, "open(/dev/kvm) failed: %s\n", strerror(errno));
return 1;
}
printf("open(/dev/kvm)=%d\n", kvm);
fflush(stdout);
api = ioctl(kvm, KVM_GET_API_VERSION, 0);
if (api < 0) {
fprintf(stderr, "KVM_GET_API_VERSION failed: %s\n", strerror(errno));
return 1;
}
printf("KVM_GET_API_VERSION=%d (expected %d)\n", api, KVM_API_VERSION);
fflush(stdout);
printf("KVM_CAP_NR_VCPUS=%d\n", ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS));
printf("KVM_CAP_NR_MEMSLOTS=%d\n", ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_NR_MEMSLOTS));
printf("KVM_CAP_NESTED_STATE=%d\n", ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_NESTED_STATE));
fflush(stdout);
printf("calling KVM_CREATE_VM\n");
fflush(stdout);
vm = ioctl(kvm, KVM_CREATE_VM, 0);
if (vm < 0) {
fprintf(stderr, "KVM_CREATE_VM failed: %s\n", strerror(errno));
return 2;
}
printf("KVM_CREATE_VM fd=%d SUCCESS\n", vm);
fflush(stdout);
printf("calling KVM_CREATE_VCPU(0) ioctl=0x%lx\n",
(unsigned long)KVM_CREATE_VCPU);
fflush(stdout);
vcpu = ioctl(vm, KVM_CREATE_VCPU, 0);
if (vcpu < 0) {
fprintf(stderr, "KVM_CREATE_VCPU failed: errno=%d %s\n",
errno, strerror(errno));
return 3;
}
printf("KVM_CREATE_VCPU fd=%d SUCCESS (unexpected on this host)\n", vcpu);
fflush(stdout);
return 0;
}
/* amx_min.c */
#define _GNU_SOURCE
#include <cpuid.h>
#include <errno.h>
#include <immintrin.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
static _Alignas(64) unsigned char cfg[64], cfg_after[64];
static _Alignas(64) unsigned char src[8][1024], dst[8][1024];
static const struct timespec delay = { .tv_nsec = 1000000 };
#define TILES(OP) OP(0); OP(1); OP(2); OP(3); OP(4); OP(5); OP(6); OP(7)
#define LOAD(t) _tile_loadd(t, src[t], 64)
#define STORE(t) _tile_stored(t, dst[t], 64)
/* No function calls from LDTILECFG until TILERELEASE. */
__attribute__((noinline)) long roundtrip(long nr)
{
_tile_loadconfig(cfg);
TILES(LOAD);
long ret;
__asm__ volatile("syscall" : "=a"(ret)
: "0"(nr), "D"(&delay), "S"(0L)
: "rcx", "r11", "memory", "cc");
_tile_storeconfig(cfg_after);
for (int i = 0; i < 64; i++) {
if (cfg[i] != ((volatile unsigned char *)cfg_after)[i]) {
_tile_release();
return -4096; /* Configuration changed; do not store tiles. */
}
}
TILES(STORE);
_mm_mfence();
_tile_release();
return ret;
}
int main(int argc, char **argv)
{
if (argc > 2 || (argc == 2 && strcmp(argv[1], "getpid"))) {
fprintf(stderr, "Usage: %s [getpid]\n", argv[0]);
return 2;
}
unsigned a, b, c, d;
if (!__get_cpuid_count(7, 0, &a, &b, &c, &d) || !(d & (1u << 24))) {
puts("SKIP: AMX_TILE not exposed");
return 77;
}
if (syscall(SYS_arch_prctl, 0x1023 /* ARCH_REQ_XCOMP_PERM */, 18L)) {
perror("ARCH_REQ_XCOMP_PERM");
return 77;
}
cfg[0] = 1;
for (int t = 0; t < 8; t++) {
cfg[16 + 2*t] = 64;
cfg[48 + t] = 16;
for (int i = 0; i < 1024; i++)
src[t][i] = 1 + ((t*1024 + i) % 251);
}
int bad = 0;
for (int n = 0; n < 300; n++) {
memset(dst, 0xcc, sizeof dst);
memset(cfg_after, 0xcc, sizeof cfg_after);
long ret = roundtrip(argc == 2 ? SYS_getpid : SYS_nanosleep);
if (ret == -4096) { puts("FAIL: TILECFG changed"); return 2; }
if (ret < 0) { errno = (int)-ret; perror("syscall"); return 2; }
if (memcmp(src, dst, sizeof src)) {
if (bad++ == 0) {
int zeros = 0;
for (int t = 0; t < 8; t++)
for (int i = 0; i < 1024; i++) zeros += dst[t][i] == 0;
printf("First mismatch: %d/8192 bytes are zero; TILECFG unchanged\n", zeros);
}
}
}
printf("%d/300 trials lost tile data (%s)\n", bad, argc == 2 ? "getpid" : "nanosleep");
return bad ? 1 : 0;
}