Skip to content

#5304: mix relative path into Cache.dirSha so a file rename changes the hash#5320

Merged
yegor256 merged 2 commits into
objectionary:masterfrom
morphqdd:5304-cache-dirsha-path-hashing
Jul 8, 2026
Merged

#5304: mix relative path into Cache.dirSha so a file rename changes the hash#5320
yegor256 merged 2 commits into
objectionary:masterfrom
morphqdd:5304-cache-dirsha-path-hashing

Conversation

@morphqdd

@morphqdd morphqdd commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Closes #5304.

Cache.dirSha — the production directory-hashing path used by Linting, Transpiling, and
Parsing to decide whether cached compiled output can be reused — hashed each regular file's
content independently (new Sha(p).toString()), sorted by path only for iteration order, but
never fed the path itself into the digest. Two single-file directories whose one file has
identical content but a different name produced the exact same per-file content hash, so
dirSha(dirA) and dirSha(dirB) came out byte-for-byte identical — even though a file's name is
semantically significant in this toolchain (the compiled output for original-name.eo encodes
that name). Since Cache.apply treats a sha match as "reuse the cached content," a rename that
happens to collide this way could make the cache silently serve compiled output built for a
different file name.

This is the other half of the defect already fixed for Sha.hash's own directory branch in
#5254/#5262 — that fix addressed the delimiter-injection half (concatenating raw file contents
with no boundary), while Cache.dirSha's independent reimplementation sidestepped that half (each
per-file contribution is already a fixed-length Base64 SHA-256 string) but never addressed the
path-omission half at all.

Mixed each file's relative path into the digest alongside its content hash, joined by a NUL byte
(rel_path + "\0" + Sha(file), matching the fix suggested in the issue) — a NUL is safe as a
separator since file paths can't contain one, unlike a printable delimiter such as a space.

Test

Updated the existing generatesCorrectHashForEntireFolderWithSeveralFiles test to expect the new
per-entry format ("file1.txt\0" + hash instead of just hash).

Added generatesDifferentHashesForFoldersWithDifferentlyNamedIdenticalFiles, reproducing the
exact scenario from the issue: two directories, dirA/original-name.eo and
dirB/completely-different-name.eo, both containing the same content, asserting their cached
.sha256 files are no longer identical.

Ran the full CacheTest suite locally — all 10 tests pass.

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🚀 Performance Analysis

All benchmarks are within the acceptable range. No critical degradation detected (threshold is 100%). Please refer to the detailed report for more information.

Click to see the detailed report
Test Base Score PR Score Change % Change Unit Mode
benchmarks.XmirBench.xmirToEO 9780.628 9556.936 -223.692 -2.29% ms/op Average Time

✅ Performance gain: benchmarks.XmirBench.xmirToEO is faster by 223.692 ms/op (2.29%)

@sonarqubecloud

sonarqubecloud Bot commented Jul 4, 2026

Copy link
Copy Markdown

@morphqdd

morphqdd commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

@yegor256, please take a look when you have a moment.

@yegor256
yegor256 merged commit 94fe68b into objectionary:master Jul 8, 2026
25 of 26 checks passed
@0crat

0crat commented Jul 8, 2026

Copy link
Copy Markdown

@morphqdd Thanks for the contribution! You've earned +16 points. Please, keep them coming. Your running score is +588; don't forget to check your Zerocracy account too).

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.

Cache.dirSha reuses cached output after source file renaming due to lack of file path hashing

3 participants