Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

close

Closed Beginner friendly
#108 6 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
74/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
bash, macos

Research direction

Start with /Library/NullMoth/nullmoth-displaytrace.sh as generated in nullmoth-setup.sh (the issue cites the v1.12.0 and v1.13.0 heredoc locations) and compare its kext check with the wait loop in nullmoth-wsreset.sh. Check the display trace launchd plist for its startup behavior. Done means the tracker creates its directory and starts recording when the kext loads after launchd starts it; verify the boot timing path described in the issue.

Written by the indexing model from the issue text.

Description

What happens

On this machine the display tracker records nothing. /Library/NullMoth/display-trace/ does not exist, so
Send logs uploads no display-trace.txt / display-kernel.txt / display-ws.txt, and the app's
Record the flicker does nothing either — it only appends its == USER: flicker seen now marker when that
directory exists.

This is on both 1.12.0 and 1.13.0, freshly installed and rebooted.

Evidence
$ ls -la /Library/NullMoth/display-trace/
ls: /Library/NullMoth/display-trace/: No such file or directory

$ launchctl print system/com.nullmoth.displaytrace
	state = not running
	runs = 1
	last exit code = 0

The daemon ran exactly once and exited 0 — without creating its own directory. mkdir -p is on line 4, so the
run ended before it.

Why

/Library/NullMoth/nullmoth-displaytrace.sh line 3:

kextstat 2>/dev/null | grep -q com.nullmoth.NVAccel || exit 0

That is the only exit 0 before the mkdir, so the gate is where it stopped: at the moment launchd started it,
kextstat did not yet list com.nullmoth.NVAccel. The plist has RunAtLoad and no KeepAlive, so there is
no second attempt and no retry.

The gate is not wrong — it passes now, which I checked by hand:

$ kextstat 2>/dev/null | grep -c com.nullmoth.NVAccel
1

So it is a race, not a bad test. The neighbouring daemon shows the difference: nullmoth-wsreset.sh waits for its
dependency before using it —

for i in $(seq 1 40); do pgrep -x WindowServer >/dev/null 2>&1 && break; sleep 1; done

— and it does run (/var/run/nullmoth-wsreset.done exists and wsreset.log was written at this boot). The
tracker checks once, immediately, and gives up for the whole boot.

What it costs

Both halves of the display-evidence path are gated on that directory, in nullmoth-setup.sh:

# line 150 — Record the flicker
[ -d /Library/NullMoth/display-trace ] && echo "== USER: flicker seen now $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> /Library/NullMoth/display-trace/trace.txt

# line 261 — Send logs
[ -f "/Library/NullMoth/display-trace/$f" ] && tail -c 3145728 "/Library/NullMoth/display-trace/$f" > "$COLLECT/display-$f"

So the 1.12 release note — "Send logs uploads it, so if your screen went black, restart, then press Send logs; we
can see what happened"
— yields nothing on a machine where the gate lost the race. The open item for black
screens above 60 Hz asks for exactly this data, and a user who follows the instruction will believe they sent it.

Suggested fix

Wait for the kext the way wsreset waits for WindowServer, and keep the gate as the final check:

for i in $(seq 1 60); do kextstat 2>/dev/null | grep -q com.nullmoth.NVAccel && break; sleep 1; done
kextstat 2>/dev/null | grep -q com.nullmoth.NVAccel || exit 0

Or add KeepAlive with a ThrottleInterval, or drop the gate entirely — the two log stream pipelines are
harmless when no NullMoth kext is loaded, and the loop already does nothing useful without the counters.

Workaround for a user who needs the trace now
sudo launchctl kickstart -k system/com.nullmoth.displaytrace

The gate passes once the kexts are up, so the directory appears and the loop starts. It does not survive the next
boot.

Environment

RTX 3080 10 GB (10DE:2206), macOS 15.8.1 (24H32), OpenCore. Driver 1.12.0 then 1.13.0; the gate line is identical
in both (nullmoth-setup.sh heredoc at v1.12.0 L915 and v1.13.0 L1024).


中文版(Chinese version)
发生了什么

本机的 display tracker 什么都没记录。/Library/NullMoth/display-trace/ 不存在,因此 Send logs 不会上传任何
display-trace.txt / display-kernel.txt / display-ws.txt;app 的 Record the flicker 同样什么也不做
—— 它只在那个目录存在时才追加 == USER: flicker seen now 标记。

1.12.0 和 1.13.0 都是如此(全新安装 + 重启)。

证据
$ ls -la /Library/NullMoth/display-trace/
ls: /Library/NullMoth/display-trace/: No such file or directory

$ launchctl print system/com.nullmoth.displaytrace
	state = not running
	runs = 1
	last exit code = 0

daemon 只跑过一次并以 0 退出 —— 而且没有创建自己的目录。mkdir -p 在第 4 行,所以它在到达那一行之前就结束了。

原因

/Library/NullMoth/nullmoth-displaytrace.sh 第 3 行:

kextstat 2>/dev/null | grep -q com.nullmoth.NVAccel || exit 0

这是 mkdir 之前唯一的 exit 0,所以它卡在门槛上:launchd 启动它的那一刻,kextstat 还没有列出
com.nullmoth.NVAccel。plist 是 RunAtLoad 且没有 KeepAlive ⇒ 没有第二次尝试,也没有重试。

门槛本身没错 —— 我手工验证过,现在能通过:

$ kextstat 2>/dev/null | grep -c com.nullmoth.NVAccel
1

所以这是竞态,不是测试写错。相邻的 daemon 正好是对照组:nullmoth-wsreset.sh 会先等它的依赖 ——
for i in $(seq 1 40); do pgrep -x WindowServer >/dev/null 2>&1 && break; sleep 1; done —— 它确实跑起来了
(/var/run/nullmoth-wsreset.done 存在,本次启动也写了 wsreset.log)。tracker 只检查一次,立刻放弃,整次启动
都不再有。

代价

显示证据链的两半都依赖那个目录(nullmoth-setup.sh):

# 第 150 行 —— Record the flicker
[ -d /Library/NullMoth/display-trace ] && echo "== USER: flicker seen now ..." >> /Library/NullMoth/display-trace/trace.txt

# 第 261 行 —— Send logs
[ -f "/Library/NullMoth/display-trace/$f" ] && tail -c 3145728 "/Library/NullMoth/display-trace/$f" > "$COLLECT/display-$f"

因此 1.12 的 release note ——「Send logs 会上传它,所以如果屏幕黑了,重启后按 Send logs,我们就能看到发生了什么」
—— 在门槛输掉竞态的机器上什么也拿不到。而「>60 Hz 黑屏」这个 open 项要的正是这份数据,照做的用户会以为
自己发出去了。

建议修法

像 wsreset 等 WindowServer 那样等 kext,并把门槛留作最后一道检查:

for i in $(seq 1 60); do kextstat 2>/dev/null | grep -q com.nullmoth.NVAccel && break; sleep 1; done
kextstat 2>/dev/null | grep -q com.nullmoth.NVAccel || exit 0

或者加 KeepAlive + ThrottleInterval,或者干脆去掉门槛 —— 没有 NullMoth kext 时那两条 log stream 无害,
而没有计数器时主循环本来也做不了有用的事。

需要立刻拿到 trace 的用户的临时办法
sudo launchctl kickstart -k system/com.nullmoth.displaytrace

kext 加载后门槛就能过,目录会出现、循环会开始。但它熬不过下一次重启。

环境

RTX 3080 10GB(10DE:2206),macOS 15.8.1 (24H32),OpenCore。驱动 1.12.0 → 1.13.0;两版的门槛行完全相同
(nullmoth-setup.sh 的 heredoc:v1.12.0 L915、v1.13.0 L1024)。

Dominant language
Rust
Stars
2.5k
Forks
233
Avg merge
1h 37m
Merged PRs (30d)
1

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from nullmoth/nvidia-macos-driver

All issues in nullmoth/nvidia-macos-driver

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.