]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
testsuite,ci: mark recv-discard-nullderef CI skip and tighten its check master
authorAndrew Tridgell <andrew@tridgell.net>
Sat, 6 Jun 2026 08:43:06 +0000 (18:43 +1000)
committerAndrew Tridgell <andrew@tridgell.net>
Sat, 6 Jun 2026 08:56:51 +0000 (18:56 +1000)
The regression test honestly skips when it cannot force the receiver's
output mkstemp() to fail -- as root (root bypasses DAC) and on Cygwin
(chmod 0555 does not deny the owner a write). The ubuntu, ubuntu-22.04,
almalinux and macOS jobs run `make check` as root, and Cygwin can't
enforce the unwritable directory, so the test skips on all of them.
runtests.py fails a run on any skip-set mismatch, so add the test to
those jobs' RSYNC_EXPECT_SKIPPED lists; the BSD/Solaris jobs run as root
too but enforce no expected-skip set, so they need no change.

Also tighten the pass condition. The post-chmod writability probe already
guarantees the receiver discards (mkstemp must fail), so an exit 0 would
mean the file actually transferred and the discard path was never
exercised -- a silent false-pass. Require exactly exit 23 (the forced
discard leaves the file untransferred); 12 remains the pre-fix crash.

.github/workflows/almalinux-8-build.yml
.github/workflows/cygwin-build.yml
.github/workflows/macos-build.yml
.github/workflows/ubuntu-22.04-build.yml
.github/workflows/ubuntu-build.yml
testsuite/recv-discard-nullderef_test.py

index 1a0b0e1579234ef54fa36586b9f3f60e8558a552..f3ba969f443603a9a78ecb81df04e81983092015 100644 (file)
@@ -62,7 +62,7 @@ jobs:
       # crtimes-not-supported skip matches the other Linux jobs;
       # daemon-chroot-acl and proxy-response-line-too-long skip because
       # the default (secure) transport opens no listening socket.
-      run: RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check
+      run: RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check
     - name: check (TCP daemon transport)
       # Second run exercising the real loopback-TCP daemon path.
       run: ./runtests.py --rsync-bin="$PWD/rsync" --use-tcp -j 8
index a63a3f26b2aafacb08a98541c2f1ec5f717afd46..a14e9d0691c21d2f683c7ed15d5277098a9cf300 100644 (file)
@@ -46,7 +46,7 @@ jobs:
       # RESOLVE_BENEATH symlink-race tests.  symlink-dirlink-basis also now
       # RUNS (the #915 non-daemon basis open uses a plain do_open, restoring
       # following an in-tree dir-symlink basis without RESOLVE_BENEATH).
-      run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls-depth,acls,bare-do-open-symlink-race,chdir-symlink-race,chown,daemon-access-ip,daemon-chroot-acl,devices,dir-sgid,open-noatime,protected-regular,proxy-response-line-too-long,sender-flist-symlink-leak,simd-checksum make check'
+      run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls-depth,acls,bare-do-open-symlink-race,chdir-symlink-race,chown,daemon-access-ip,daemon-chroot-acl,devices,dir-sgid,open-noatime,protected-regular,proxy-response-line-too-long,recv-discard-nullderef,sender-flist-symlink-leak,simd-checksum make check'
     - name: check (TCP daemon transport)
       # Second run with daemon tests over a real loopback rsyncd; the default
       # 'make check' above uses the secure stdio-pipe transport.
index 067671ce0da594289452f24f6785c27f9d31ddf7..971389fb61f970e027a5e2f880521eb44e08acbe 100644 (file)
@@ -44,7 +44,7 @@ jobs:
       # chown-fake / devices-fake / xattrs / xattrs-hlink now RUN on macOS
       # (rsyncfns.py drives xattrs via the `xattr` command), verified on a
       # real macOS host, so they're no longer in the skip set.
-      run: sudo RSYNC_EXPECT_SKIPPED=acls-default,acls-depth,chmod-temp-dir,daemon-access-ip,daemon-chroot-acl,dir-sgid,open-noatime,preallocate,protected-regular,proxy-response-line-too-long,simd-checksum,sparse make check
+      run: sudo RSYNC_EXPECT_SKIPPED=acls-default,acls-depth,chmod-temp-dir,daemon-access-ip,daemon-chroot-acl,dir-sgid,open-noatime,preallocate,protected-regular,proxy-response-line-too-long,recv-discard-nullderef,simd-checksum,sparse make check
     - name: check (TCP daemon transport)
       # Second run with daemon tests over a real loopback rsyncd; the default
       # 'make check' above uses the secure stdio-pipe transport.
index 392b5e7385e461b67afd79edc23cf310d2eb5cf3..af14ce4bb2c78e25d1762140a1bacd6adef6944b 100644 (file)
@@ -39,11 +39,11 @@ jobs:
     - name: info
       run: rsync --version
     - name: check
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check
     - name: check30
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check30
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check30
     - name: check29
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check29
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check29
     - name: check (TCP daemon transport)
       # Second run with daemon tests over a real loopback rsyncd; the default
       # 'make check' above uses the secure stdio-pipe transport.
index c142d693f23aead198c7252afda85dfc38bdb041..72f19e3fd3385db2c2cfe9c556dd073fd91a3bba 100644 (file)
@@ -63,11 +63,11 @@ jobs:
     - name: info
       run: rsync --version
     - name: check
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check
     - name: check30
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check30
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check30
     - name: check29
-      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long make check29
+      run: sudo RSYNC_EXPECT_SKIPPED=crtimes,daemon-access-ip,daemon-chroot-acl,proxy-response-line-too-long,recv-discard-nullderef make check29
     - name: check (TCP daemon transport)
       # Second run with daemon tests over a real loopback rsyncd. The default
       # 'make check' above uses the secure stdio-pipe transport (no listening
index a0919578380a968ac1b679c9bb8204938136ee0f..e130203f81094134a6523e9ff0fe2a225fd6c7b1 100755 (executable)
@@ -104,20 +104,23 @@ finally:
 rc = proc.returncode
 
 # A receiver SIGSEGV manifests to the client as a protocol error (the daemon's
-# receiver child crashes mid-stream and the connection drops). Pre-fix this is
-# code 12 (error in rsync protocol data stream); post-fix the receiver drains
-# the delta and reports a benign "could not transfer" (code 23), or succeeds.
+# receiver child crashes mid-stream and the connection drops): exit code 12.
+# With the fix the receiver drains the delta and, because the forced-unwritable
+# destination leaves the file untransferred, the run reports the benign "some
+# files were not transferred" -- exit code 23.
 #
-# rsync's own exit codes are all < 128, so we can't read the receiver's signal
-# directly from the client. The discriminator is the PROTOCOL error: only a
-# crashed (or otherwise vanished) receiver produces code 12 here. A clean
-# discard yields 23 (file not transferred) or 0.
+# 23 is the ONLY non-crash outcome here: the writability probe above guarantees
+# the receiver's mkstemp() fails, so the file is always discarded. An exit 0
+# would mean the file actually transferred -- the discard path was NOT exercised
+# and the run proves nothing -- so require exactly 23 (and call out 12 as the
+# pre-fix crash).
 if rc == 12:
     test_fail(f"receiver crashed on the discard path (rsync exited {rc}: "
               "error in rsync protocol data stream -- the receiver child "
               "SIGSEGV'd in full_fname(NULL))")
-if rc not in (0, 23):
-    test_fail(f"unexpected rsync exit {rc} (expected 0 or 23, a benign "
-              "discard; 12 would be the crash)")
+if rc != 23:
+    test_fail(f"expected rsync exit 23 (the forced discard leaves the file "
+              f"untransferred); got {rc} -- the discard path was not exercised, "
+              "so this run validates nothing (12 would be the pre-fix crash)")
 
 print(f"OK: receiver discarded the delta without crashing (rsync exit {rc})")