Tcl Source Code

View Ticket
Login
Ticket UUID: 7b4a819535231639cccf59d197ed59ded4375119
Title: Sometimes, on macOS, 15/20 minutes are not enough to run all testcases
Type: Bug Created on: 2026-09-11 15:05:30
Submitter: sebres Assigned to: jan.nijtmans
Subsystem: 16. Commands A-H Severity: Minor
Priority: 5 Medium Last modified: 2026-09-15 11:19:31
Status: Closed Closed by: sebres
Resolution: Fixed Closed on: 2026-09-15 11:19:31
Version: any
Description:

Attempts to fix (like [34db3351f1d7faf1]) would not help at all, because it is not slowness but hang:

2026-09-11T11:58:45.9965230Z unixFCmd.test
2026-09-11T11:58:46.0526710Z ---- unixFCmd-1.1 start
2026-09-11T11:58:46.0538050Z ++++ unixFCmd-1.1 took 1 ms
...
2026-09-11T11:58:46.0595970Z ---- unixFCmd-2.3 start
2026-09-11T11:58:46.0596640Z ++++ unixFCmd-2.3 took 0 ms
2026-09-11T11:58:46.0599030Z ---- unixFCmd-2.4 start
2026-09-11T12:23:14.7589210Z ##[error]The action 'Run Tests' has timed out after 30 minutes.

Something seems to be wrong in unixFCmd-2.4 (or rather with file copy) - looks like a race condition to me.

Also the AIs are in agreement here: On macOS, opening a FIFO for reading (without the O_NONBLOCK flag) blocks until another process opens the same FIFO for writing. This behavior is documented in the open(2) man page and is specific to the BSD-based kernel that macOS uses. On Linux, the same operation returns immediately, which is why the test may pass on other Unix-like systems but hangs on macOS.

The check for S_IFIFO in DoCopyFile whether the source is fifo seems to be not enough there (or there is some bypass somewhere for MACOS and it fallsback to copy), or [e4d3a903de130788] misses something yet specific for macos.
I could try to fix it, but I don't have macos to hand and debugging and fixing sporadic heisenbug on GH is thankless task.

User Comments:
sebres added on 2026-09-11 15:10:33:

Therefore, the test for macOS is being disabled in [b7d236402fcec914] for 8.6+ for now, until the issue is resolved.


jan.nijtmans added on 2026-09-11 18:18:18:

Thank you for having a look at this. I already figured, it was some kind of a hang, more complicated than a simple timeout.

So, fully agreed! +1


jan.nijtmans added on 2026-09-14 07:58:40:

Still hanging :-(


sebres added on 2026-09-14 11:19:05:

Hmm, looks like it were different now for all 3 builds (xcode & 2 clang):

2026-09-14T10:59:24.2315740Z tcltest.test
...
2026-09-14T10:59:24.2316790Z ---- tcltest-4.1 start
2026-09-14T11:08:53.1772100Z ##[error]The action 'Run Tests' has timed out after 15 minutes.
-------------------------
2026-09-14T10:58:07.3118320Z tcltest.test
...
2026-09-14T10:58:07.3143360Z ---- tcltest-21.5 start
2026-09-14T11:13:16.6458290Z ##[error]The operation was canceled.
2026-09-14T11:13:16.6658760Z Post job cleanup.
-------------------------
2026-09-14T11:00:21.4613910Z tailcall.test
...
2026-09-14T11:00:21.4617130Z ---- tailcall-7 start
2026-09-14T11:13:04.2408000Z ##[error]The action 'Run Tests' has timed out after 20 minutes.

Something is completely wrong on macos side. Do we have people with mac to hand?


sebres added on 2026-09-14 11:29:29:

Huh, and test tcltest-4.1 has a constraint {unixOrWin}, how the test can trigger run for it on macos? Weird.


sebres added on 2026-09-14 13:10:20:

OK, looks like it doesn't detect mac at all, because tcl_platform(platform) is recognized as "unix".

See runs/34846833228/job/103984729723#step:5:14 :

**** osVersion 24.6.0 pointerSize 8 byteOrder littleEndian machine arm64 platform unix pathSeparator : os Darwin engine Tcl user runner wordSize 8 ****
**** unix ****
**** unixOrWin: 1, unix: 1, win: 0. mac: 0 ****


anonymous added on 2026-09-14 13:36:52:
Hi, 
I've a macOS and i can do some tests if you want

nicolas

sebres added on 2026-09-14 14:07:37:

I don't know how it ever working properly, because $::tcl_platform(platform) is basically never "macintosh" (I didn't search for the revision yet, but even 8.5/8.6 seem to miss it (it is either dos, unix or windows, nothing else).

The fix (repairing tcltest) may look like this - GH/tcl/956856ba192179526fc12241f1bcb4ee1a540924:

    ConstraintInitializer unixOnly \
-	    {string equal $::tcl_platform(platform) unix}
+	    {expr {$::tcl_platform(platform) eq "unix" && $::tcl_platform(os) ne "Darwin"}}
    ConstraintInitializer macOnly \
-	    {string equal $::tcl_platform(platform) macintosh}
+	    {expr {$::tcl_platform(platform) eq "unix" && $::tcl_platform(os) eq "Darwin"}}
    ConstraintInitializer pcOnly \
	    {string equal $::tcl_platform(platform) windows}
    ConstraintInitializer winOnly \
As you can see - runs/34849913792 - it fixed the hang, but...

An alternative fix may move this logic to TclpSetVariables(), and restore $::tcl_platform(platform) "macintosh" back. However it looks as too grave change to my taste.

I'm not really familiar with macos, so I'd like to delegate this decision to someone else. I'd firstly repair macos in tcltest only, but there are more places in source code checking for "macintosh".


sl1200mk2 added on 2026-09-14 14:41:54:

here's what AI is saying about it:

here (macOS 26.6.2, Apple M4 Pro). No platform decision is needed: the hang comes from file copy itself, fix below.

mac never matches on macOS, by design. macintosh was Mac OS Classic, removed in 2004 [b6330dbac7]. Mac OS X has always been unix for Tcl, so the mac* constraints of tcltest are leftovers and tempNotMac is always 1 there. Returning "macintosh" again would break every script that relies on unix.

956856b only hides the hang. It turns unix off on macOS: a full make test then runs 334 fewer tests (61966 instead of 62300), unixFCmd-2.4 among them, and Tk or extensions using tcltest would lose their unix tests too.

Cause. unixFCmd-2.4 hangs every time here, on 8.6 and 9.0:

DoCopyFile → CopyFileAtts → TclMacOSXCopyFileAttributes → copyfile → copyfile_set_dst_permissions → open

After mkfifo, copyfile(3) opens the new fifo in blocking mode and waits forever for a writer. copyfile only handles regular files, directories and links (ENOTSUP otherwise), so skipping it loses nothing. file copy of a directory containing a named pipe hangs the same way. The hangs reported in tailcall-7, tcltest-4.1 and tcltest-21.5 come from | grep buffering: with that pipeline, the log here stops at trace-16.8 while the process is stuck in unixFCmd-2.4.

Fix for 8.6, 9.0 and trunk: skip copyfile() for other file types, and remove tempNotMac. unixFCmd-2.4 passes on 8.6 and 9.0; on 9.0 the full make test with the CI settings gives 68144 tests, 0 failures, in 3 minutes.

Index: macosx/tclMacOSXFCmd.c
==================================================================
--- macosx/tclMacOSXFCmd.c
+++ macosx/tclMacOSXFCmd.c
@@ -395,10 +395,21 @@
     const char *src,		/* Path name of source file (native). */
     const char *dst,		/* Path name of target file (native). */
     const Tcl_StatBuf *statBufPtr)
 				/* Stat info for source file */
 {
+    /*
+     * copyfile() only handles regular files, directories and links (ENOTSUP
+     * otherwise), but recent macOS versions first open() dst, which never
+     * returns if dst is a fifo. [7b4a819535]
+     */
+
+    if (!S_ISREG(statBufPtr->st_mode) && !S_ISDIR(statBufPtr->st_mode)
+	    && !S_ISLNK(statBufPtr->st_mode)) {
+	return TCL_OK;
+    }
+
     if (MayUseCopyFile()) {
 #ifdef HAVE_COPYFILE
 	if (0 == copyfile(src, dst, NULL, (S_ISLNK(statBufPtr->st_mode)
 		? COPYFILE_XATTR | COPYFILE_NOFOLLOW_SRC
 		: COPYFILE_XATTR | COPYFILE_ACL))) {

Index: tests/unixFCmd.test
==================================================================
--- tests/unixFCmd.test
+++ tests/unixFCmd.test
@@ -210,11 +210,11 @@
     }
     # file copy $null tf1
 } -result {}
 test unixFCmd-2.4 {TclpCopyFile: src is fifo} -setup {
     cleanup
-} -constraints {unix notRoot execMknod tempNotMac} -body { # tempNotMac -- see bug [7b4a819535231639]
+} -constraints {unix notRoot execMknod} -body {
     exec mknod tf1 p
     file copy tf1 tf2
     list [file type tf1] [file type tf2]
 } -cleanup {
     cleanup

sebres added on 2026-09-14 15:55:27:

> No platform decision is needed

Sure, as I wrote below it is temporary constraint to ignore test, till it is fixed properly.

> unixFCmd-2.4 passes on 8.6 and 9.0; on 9.0 the full `make test` with the CI settings gives 68144 tests, 0 failures, in 3 minutes.

Thx, I'll check it.

But as you can see on GH, more tests failing here and there (it is not unixFCmd-2.4 only), and they all are sporadic. The basic issue was a wrong constraints detection, repaired in [001fa14844a641c6] now. But you can try to fix another issues too.


jan.nijtmans added on 2026-09-14 19:01:27:

Let's [f44aa91653bea8e8|try] sl1200mk2's proposed solution.

I agree with Don that changing existing constraints in tcltest is not a good idea: Any testcase which was written for the old Macintosh will - after this change - suddenly start failing when run under MacOS. Therefore, in the above commit, I reverted the changes to tcltest.tcl. Also, because we now know that macintosh is not supported any more, let's just remove the tempNotMac restrictions (since this is always 1) and change macOrUnix to unixOnly.

Tomorrow we will see if this works.


sebres added on 2026-09-14 20:09:49:

As already said (see below), it failed sporadically here and there, and some of the tests where it was hanging have nothing to do with fifo-detection fix at all.

I also committed the fix directly in GH (without changing the constraints back), but a bit simpler variant:

+    /*
+     * FIFOs do not have attributes, moreover calling copyfile() 
+     * could cause a blocking deadlock in the macOS VFS layer,
+     * see [7b4a819535231639].
+     */
+    if (S_ISFIFO(statBufPtr->st_mode)) {
+        return TCL_OK;
+    }

Looks good now - GH/runs/34888741662. Thus I'd add it to 8.6/9.0 (just to see who wins tomorrow ;)...
Let see if your branch would hang somewhere else.

Regarding the constraints - partially agree, but as already said it'd be rather task for someone with macos. Anyway, we can revert them if your branch passes the tests (and remain stable in few days).


jan.nijtmans added on 2026-09-15 07:04:20:

So, what should happen with S_ISCHR/S_ISBLK/S_ISSOCK? Do they have attributes?

Your S_ISFIFO solution is the 'least change in functionality' solution, which is safest, so let's go for that (whether it actually fixes _this_ hang or not).


sebres added on 2026-09-15 11:19:31:

I don't think S_ISCHR, S_ISBLK, or S_ISSOCK will ever hang on Darwin's copyfile() function in the same way S_ISFIFO does. However they are also special file types, their underlying VFS structures handle read/write stream initialization differently. Also AIs seem to confirm that.

Although I wonder about another tests that was hanging previously... I don't believe there were a copy of PIPE attrs somewhere (stdout?). But lets see whether it'd hang later.

Closed now.