Skip to content

Instantly share code, notes, and snippets.

@jhoblitt
Created March 6, 2026 23:19
Show Gist options
  • Select an option

  • Save jhoblitt/9ce718b3d0e9cbc15acc6946287bc757 to your computer and use it in GitHub Desktop.

Select an option

Save jhoblitt/9ce718b3d0e9cbc15acc6946287bc757 to your computer and use it in GitHub Desktop.
chatgpt's attempt to preproduce the git 2.52.0 clone failure seen on ganesha v9.4/v9.6 exports
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static const char *CONFIG_PATH = "config";
static const char *LOCK_PATH = "config.lock";
static void die(const char *msg) {
perror(msg);
exit(1);
}
static void safe_close(int fd, const char *what) {
if (close(fd) != 0) {
perror(what);
exit(1);
}
}
static void write_full(int fd, const void *buf, size_t len, const char *what) {
const char *p = buf;
size_t off = 0;
while (off < len) {
ssize_t n = write(fd, p + off, len - off);
if (n < 0) {
perror(what);
exit(1);
}
off += (size_t)n;
}
}
static void dump_hex(const void *buf, size_t len) {
const unsigned char *p = buf;
for (size_t i = 0; i < len; i++) {
printf("%02x", p[i]);
if ((i + 1) % 16 == 0 || i + 1 == len)
printf("\n");
else
printf(" ");
}
}
static void write_config_atomically(const char *content, size_t len, bool do_fsync) {
unlink(LOCK_PATH);
int fd = open(LOCK_PATH, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
if (fd < 0)
die("open config.lock");
if (fchmod(fd, 0644) != 0)
die("fchmod config.lock");
write_full(fd, content, len, "write config.lock");
if (do_fsync) {
if (fsync(fd) != 0)
die("fsync config.lock");
}
safe_close(fd, "close config.lock");
if (rename(LOCK_PATH, CONFIG_PATH) != 0)
die("rename config.lock -> config");
}
static void read_once_or_report(int iter, const char *expected, size_t expected_len) {
int fd = open(CONFIG_PATH, O_RDONLY);
if (fd < 0)
die("open config for read");
char buf[4096];
memset(buf, 0, sizeof(buf));
ssize_t n = read(fd, buf, 1024);
if (n < 0) {
fprintf(stderr,
"\nITER %d: read(config) failed: errno=%d (%s)\n",
iter, errno, strerror(errno));
safe_close(fd, "close config after failed read");
exit(2);
}
off_t off = lseek(fd, 0, SEEK_CUR);
if (off == (off_t)-1)
die("lseek after read");
printf("iter=%d simple-read: n=%zd off=%lld\n",
iter, n, (long long)off);
if ((size_t)n != expected_len || memcmp(buf, expected, expected_len) != 0) {
fprintf(stderr, "\nITER %d: content mismatch\n", iter);
fprintf(stderr, "expected_len=%zu got=%zd\n", expected_len, n);
fprintf(stderr, "expected:\n%.*s\n", (int)expected_len, expected);
fprintf(stderr, "got:\n%.*s\n", (int)n, buf);
fprintf(stderr, "got hex:\n");
dump_hex(buf, (size_t)n);
safe_close(fd, "close config after mismatch");
exit(3);
}
safe_close(fd, "close config after read");
}
static void git_like_read_mmap_copy(int iter) {
unlink(LOCK_PATH);
int lockfd = open(LOCK_PATH, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
if (lockfd < 0)
die("open lockfd for git-like copy");
if (fchmod(lockfd, 0644) != 0)
die("fchmod lockfd");
int fd1 = open(CONFIG_PATH, O_RDONLY);
if (fd1 < 0)
die("open fd1");
int fd2 = open(CONFIG_PATH, O_RDONLY);
if (fd2 < 0)
die("open fd2");
char tmp[1024];
ssize_t rn;
struct stat st;
if (fstat(fd2, &st) != 0)
die("fstat fd2");
rn = read(fd2, tmp, sizeof(tmp));
if (rn < 0) {
fprintf(stderr,
"\nITER %d: git-like read(fd2) failed: errno=%d (%s)\n",
iter, errno, strerror(errno));
safe_close(fd2, "close fd2 after failed read");
safe_close(fd1, "close fd1 after failed read");
safe_close(lockfd, "close lockfd after failed read");
exit(4);
}
printf("iter=%d git-like read(fd2): n=%zd st_size=%lld\n",
iter, rn, (long long)st.st_size);
safe_close(fd2, "close fd2");
if (fstat(fd1, &st) != 0)
die("fstat fd1");
void *addr = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
if (addr == MAP_FAILED)
die("mmap fd1");
safe_close(fd1, "close fd1");
write_full(lockfd, "[core]\n", 7, "write prefix 1");
write_full(lockfd, "\tbare = false\n", 14, "write prefix 2");
ssize_t wn = write(lockfd, addr, (size_t)st.st_size);
if (wn < 0) {
fprintf(stderr,
"\nITER %d: git-like write(lockfd, mmap_addr) failed: errno=%d (%s)\n",
iter, errno, strerror(errno));
munmap(addr, (size_t)st.st_size);
safe_close(lockfd, "close lockfd after failed mmap write");
exit(5);
}
printf("iter=%d git-like mmap-copy write: n=%zd\n", iter, wn);
if (munmap(addr, (size_t)st.st_size) != 0)
die("munmap");
safe_close(lockfd, "close lockfd");
}
int main(int argc, char **argv) {
int iterations = 1000;
bool do_fsync = false;
bool do_git_like = true;
if (argc > 1)
iterations = atoi(argv[1]);
if (argc > 2)
do_fsync = (atoi(argv[2]) != 0);
if (argc > 3)
do_git_like = (atoi(argv[3]) != 0);
const char *content1 =
"[core]\n"
"\trepositoryformatversion = 0\n";
const char *content2 =
"[core]\n"
"\trepositoryformatversion = 0\n"
"\tfilemode = true\n";
size_t len1 = strlen(content1);
size_t len2 = strlen(content2);
unlink(CONFIG_PATH);
unlink(LOCK_PATH);
for (int i = 1; i <= iterations; i++) {
const char *content = (i & 1) ? content1 : content2;
size_t len = (i & 1) ? len1 : len2;
printf("\n=== iter %d write len=%zu ===\n", i, len);
write_config_atomically(content, len, do_fsync);
read_once_or_report(i, content, len);
if (do_git_like)
git_like_read_mmap_copy(i);
}
printf("\ncompleted %d iterations without failure\n", iterations);
return 0;
}
rook-ceph-demo-nfs-auxtel-jhoblitt-test1:/data/auxtel/gittest$ strace ./c.out
execve("./c.out", ["./c.out"], 0x7ffc4ab71440 /* 16 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7f8bad9687b8) = 0
set_tid_address(0x7f8bad9688f0) = 600
brk(NULL) = 0x42b000
brk(0x42c000) = 0x42c000
readlink("/proc/self/exe", "/data/auxtel/gittest/c.out", 4096) = 26
execve("/lib/ld-musl-x86_64.so.1", ["ld-linux-x86-64.so.2", "--argv0", "./c.out", "--preload", "/lib/libgcompat.so.0 ", "--", "/data/auxtel/gittest/c.out"], 0x7ffd6b647dc8 /* 16 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7f520c409b28) = 0
set_tid_address(0x7f520c409f90) = 600
open("/data/auxtel/gittest/c.out", O_RDONLY|O_LARGEFILE) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\2\0>\0\1\0\0\0\360\4@\0\0\0\0\0"..., 960) = 960
mmap(0x400000, 16384, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x400000
mmap(0x401000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0x1000) = 0x401000
mmap(0x402000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x1000) = 0x402000
close(3) = 0
brk(NULL) = 0x555556ead000
brk(0x555556eaf000) = 0x555556eaf000
mmap(0x555556ead000, 4096, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x555556ead000
open("/lib/libgcompat.so.0", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=67184, ...}) = 0
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 960) = 960
mmap(NULL, 73728, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f520c352000
mmap(0x7f520c359000, 20480, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0x7000) = 0x7f520c359000
mmap(0x7f520c35e000, 12288, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0xc000) = 0x7f520c35e000
mmap(0x7f520c361000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xf000) = 0x7f520c361000
mmap(0x7f520c363000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f520c363000
close(3) = 0
open("/etc/ld-musl-x86_64.path", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib/libucontext.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/local/lib/libucontext.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/libucontext.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=13936, ...}) = 0
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 960) = 960
mmap(NULL, 20480, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f520c34d000
mmap(0x7f520c34e000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0x1000) = 0x7f520c34e000
mmap(0x7f520c34f000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0x2000) = 0x7f520c34f000
mmap(0x7f520c350000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x2000) = 0x7f520c350000
close(3) = 0
open("/lib/libobstack.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/local/lib/libobstack.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/libobstack.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=13944, ...}) = 0
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 960) = 960
mmap(NULL, 20480, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f520c348000
mmap(0x7f520c349000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0x1000) = 0x7f520c349000
mmap(0x7f520c34a000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0x2000) = 0x7f520c34a000
mmap(0x7f520c34b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x2000) = 0x7f520c34b000
close(3) = 0
mprotect(0x7f520c361000, 4096, PROT_READ) = 0
mprotect(0x7f520c406000, 4096, PROT_READ) = 0
mprotect(0x7f520c350000, 4096, PROT_READ) = 0
mprotect(0x7f520c34b000, 4096, PROT_READ) = 0
mprotect(0x402000, 4096, PROT_READ) = 0
unlink("config") = 0
unlink("config.lock") = -1 ENOENT (No such file or directory)
ioctl(1, TIOCGWINSZ, {ws_row=48, ws_col=190, ws_xpixel=0, ws_ypixel=0}) = 0
writev(1, [{iov_base="\n", iov_len=1}], 1
) = 1
writev(1, [{iov_base="=== iter 1 write len=36", iov_len=23}, {iov_base=" ===\n", iov_len=5}], 2=== iter 1 write len=36 ===
) = 28
unlink("config.lock") = -1 ENOENT (No such file or directory)
open("config.lock", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE|O_CLOEXEC, 0666) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
fchmod(3, 0644) = 0
write(3, "[core]\n\trepositoryformatversion "..., 36) = 36
close(3) = 0
rename("config.lock", "config") = 0
open("config", O_RDONLY|O_LARGEFILE) = 3
read(3, "[core]\n\trepositoryformatversion "..., 1024) = 36
lseek(3, 0, SEEK_CUR) = 36
writev(1, [{iov_base="iter=1 simple-read: n=36 off=36", iov_len=31}, {iov_base="\n", iov_len=1}], 2iter=1 simple-read: n=36 off=36
) = 32
close(3) = 0
unlink("config.lock") = -1 ENOENT (No such file or directory)
open("config.lock", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE|O_CLOEXEC, 0666) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
fchmod(3, 0644) = 0
open("config", O_RDONLY|O_LARGEFILE) = 4
open("config", O_RDONLY|O_LARGEFILE) = 5
fstat(5, {st_mode=S_IFREG|0644, st_size=36, ...}) = 0
read(5, "[core]\n\trepositoryformatversion "..., 1024) = 36
writev(1, [{iov_base="iter=1 git-like read(fd2): n=36 "..., iov_len=42}, {iov_base="\n", iov_len=1}], 2iter=1 git-like read(fd2): n=36 st_size=36
) = 43
close(5) = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=36, ...}) = 0
mmap(NULL, 36, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f520c347000
close(4) = 0
write(3, "[core]\n", 7) = 7
write(3, "\tbare = false\n", 14) = 14
write(3, "[core]\n\trepositoryformatversion "..., 36) = 36
writev(1, [{iov_base="iter=1 git-like mmap-copy write:"..., iov_len=37}, {iov_base="\n", iov_len=1}], 2iter=1 git-like mmap-copy write: n=36
) = 38
munmap(0x7f520c347000, 36) = 0
close(3) = 0
writev(1, [{iov_base="\n", iov_len=1}], 1
) = 1
writev(1, [{iov_base="=== iter 2 write len=53", iov_len=23}, {iov_base=" ===\n", iov_len=5}], 2=== iter 2 write len=53 ===
) = 28
unlink("config.lock") = 0
open("config.lock", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE|O_CLOEXEC, 0666) = 3
fcntl(3, F_SETFD, FD_CLOEXEC) = 0
fchmod(3, 0644) = 0
write(3, "[core]\n\trepositoryformatversion "..., 53) = 53
close(3) = 0
rename("config.lock", "config") = 0
open("config", O_RDONLY|O_LARGEFILE) = 3
read(3, 0x7fffacf4b590, 1024) = -1 EIO (I/O error)
writev(2, [{iov_base="\nITER 2: read(config) failed: er"..., iov_len=50}, {iov_base=NULL, iov_len=0}], 2
ITER 2: read(config) failed: errno=5 (I/O error)
) = 50
close(3) = 0
exit_group(2) = ?
+++ exited with 2 +++
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment