Skip to content

Prefer fstatat + dirfd to cf_strlcat and then stat - #5517

Open
AZero13 wants to merge 1 commit into
swiftlang:mainfrom
AZero13:stat
Open

Prefer fstatat + dirfd to cf_strlcat and then stat#5517
AZero13 wants to merge 1 commit into
swiftlang:mainfrom
AZero13:stat

Conversation

@AZero13

@AZero13 AZero13 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Motivation:
When checking if a filesystem entry is a directory (handling DT_UNKNOWN or similar), the existing code relied on copying and concatenating strings into a fixed-size CFMaxPathLength buffer using cf_strlcpy and cf_strlcat. If the combined length of the directory path and filename exceeded the buffer size, cf_strlcat would silently truncate the path. This resulted in passing a corrupted path to stat(), causing it to fail and silently misclassify deeply nested directories as standard files. Furthermore, absolute path construction is generally less efficient and more vulnerable to Time-of-Check to Time-of-Use (TOCTOU) race conditions.

Modifications:
Replaced the manual absolute path construction and stat() call with fstatat() and dirfd() on supported platforms. This allows the kernel to resolve the path relative to the already-open directory descriptor, bypassing buffer limits entirely.

For platforms that lack dirfd/fstatat (like WASI), wrapped the legacy stat() fallback in an explicit bounds check (if (pathLength + 1 + namelen < CFMaxPathLength)) to prevent the silent string truncation bug.

Fixed a pointer arithmetic bug in the file extension matching logic where strchr and wcschr failed to advance past the current dot, causing an infinite loop.

Prefer fstatat + dirfd to cf_strlcat and then stat
@AZero13
AZero13 requested a review from a team as a code owner July 17, 2026 15:59

@jmschonfeld jmschonfeld left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a unit test that verifies this functionality to prevent regressions?

cf_strlcat(subdirPath, dp->d_name, sizeof(subdirPath));
if (stat(subdirPath, &statBuf) == 0) {
#if TARGET_OS_WASI
// WASI doesn't support dirfd/fstatat, fall back to stat

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaxDesiatov just confirming - is this correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants