分享一个git diff在mac上bug
git diff 在 mac 上有个奇怪现象,有时候我修改了文件,但 git diff 认为它没变;稍作研究后,发现是 mac 和 linux 的 mmap 表现不一致,也不好说是 bug 还是 feature。水一篇文章记录一下。
一、最初的表现
环境:macos 10.15,任意版本的 git 命令。 平时逆向时候会涉及到 section headers 的修复,自己用 C 写代码来修,但发现我修复后的文件无法被 commit,但文件的 hash 确实发生了变化,而且内容也是修改后的内容。
二、测试样例
先使用 c 编写一个简单的使用 mmap 修改文件内容的可执行文件。
1 |
|
然后使用下列命令进行测试
1 | git init |
在 macos 上运行,发现 git diff 输出为空;在 linux 上运行,发现 git diff 认为1.bin 被修改了
三、初步结论
偶然使用 ls -la 发现,mac 使用这种方式,文件的修改日期时间戳是不会被刷新的,但 linux 使用这种方式,修改日期时间戳会被刷新。 使用 touch -t 刷新文件的修改日期,就可以让 git diff 感知到文件被修改了。 稍加阅读 git 的代码,大概有类似的行为。因此,初步结论是mac 的锅,mmap 不刷新时间戳,导致 git 抽风。
四、可能性猜测
linux mmap man page 有这句话
The st_ctime and st_mtime field for a file mapped with PROT_WRITE and MAP_SHARED will be updated after a write to the mapped region, and before a subsequent msync(2) with the MS_SYNC or MS_ASYNC flag, if one occurs.
但 mac 没有明确说自己会刷时间,因此这可能是个 feature,也可能是个 bug。 希望有生之年能够看看内核代码实现上有什么区别,以及希望 Lan学弟 能不能帮我破个案。