You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
timeshift --create hangs indefinitely at exit in infinite read() = 0 loop on aarch64 (Fedora 44 / Kernel 7.2.x) #570
Describe the bug
When running scheduled or scripted backups via timeshift --create, the underlying rsync execution script completes cleanly with an exit code of 0. However, the parent timeshift process hangs indefinitely, consuming 100% of an ARM core thread. It never writes info.json, leaving the snapshot unregistered and vulnerable to automated purging on subsequent runs.
Running an strace on the stuck parent process PID reveals an unhandled infinite spin loop querying a closed pipe descriptor at End-of-File (EOF):
Root Cause Analysis:
The issue seems to lie in src/Core/AsyncTask.vala. When AsyncTask sets up asynchronous standard output/error monitoring streams (GIOChannel) to track rsync progress metrics, it handles stream boundaries interactively.
Apparently, under the newer Kernel 7.2 task scheduler and GLib 2.88 on weakly ordered memory architectures (aarch64), the child execution process terminates and its pipe write-end closes rapidly. This immediate closure forces the kernel to yield 0 bytes on the read end instantly. Because the Vala-compiled async loop lacks a hard escape/break condition specifically checking for bytes_read <= 0 or missing the G_SOURCE_REMOVE return callback signal when an empty read hits a non-blocking stream, the application loops infinitely on the same descriptor without ever reaching the downstream finalization sequences (such as writing info.json or unmounting temporary targets).
This issue appears to be heavily architecture/timing dependent, as an identical deployment of timeshift 25.12.14 on an x86_64 architecture running Fedora 44 / Kernel 7.2 executes cleanly without encountering the race condition.
Suggested Code Location for Patching:
The infinite loop occurs within src/Core/AsyncTask.vala inside the asynchronous IOChannel/DataStream channel read callback routines. The stream watch needs an explicit break statement or should return false (G_SOURCE_REMOVE) whenever bytes_read <= 0 or an EOF status condition is encountered, preventing GLib from continuously refiring the empty read event on aarch64.
I reproduced the same post-rsync ARM64 hang on Ubuntu 26.04 with Timeshift 25.12.4-1, RSYNC mode (headless CLI; no display server). There is a deterministic EOF bug in file_line_count() in src/Utility/TeeJee.FileSystem.vala, independent of async callback timing. This also looks relevant to #523. I have not tested the Fedora package, so this does not establish that every reported hang has the same cause.
Root cause and affected source
BufferedInputStream.read_byte() returns an integer, with -1 for EOF. The function narrows it to char before comparing with -1. On the native AArch64 compiler used here, plain char is unsigned (__CHAR_UNSIGNED__ 1), so EOF becomes 255 and the loop never exits. The generated C confirms the narrowing to gchar; retaining gint fixes it.
The faulty function is identical in Ubuntu's 25.12.4 source and upstream 26.09.0/master at e7e54ab7b96f0ca79774662544ccd93e58059b48. Master was rechecked before posting.
This preserves newline counting, buffering, stream closure and error handling. Keeping the integer also avoids treating a real byte 0xff as EOF on signed-char targets (that case was not executed on a signed-char target here).
Focused reproduction without taking a system snapshot
On native Ubuntu 26.04 AArch64, with Vala 0.56.18, GCC 15.2 and GLib 2.88, extract the original function from the source checkout at the revision above:
perl -0777 -ne 'm/(\tpublic int64\? file_line_count .*?\n\t\})/s or die "function not found"; print "$1\n"' \
src/Utility/TeeJee.FileSystem.vala > old-function.vala
Save this minimal caller as direct-call.vala:
constint64MiB=1024*1024;
void log_error (string message) { stderr.printf ("%s\n", message); }
int main (string[] args) {
int64? count = file_line_count (args[1]);
if (count ==null) return1;
stdout.printf ("%s\n", count.to_string ());
return0;
}
Compile and call the verbatim function, not a rewritten model of its loop:
Apply the two-line patch to the source, repeat the same extraction into fixed-function.vala, then compile with that file and -o fixed and run the same three inputs.
Observed native results (each invocation bounded by timeout 2):
Input
Original
Patched
Empty file
timeout, exit 124
count 0, exit 0
one\ntwo\n
timeout, exit 124
count 2, exit 0
byte 0xff followed by newline
timeout, exit 124
count 1, exit 0
The focused calls and package builds ran in a native ARM64 build container; full Timeshift snapshot validation ran on the Ubuntu guest itself, not inside the container. A locally rebuilt Ubuntu package with only this upstream source change built successfully, and rebuilding the retained corrected source produced a byte-identical binary package. After installing it, real RSYNC snapshots completed, wrote info.json, appeared in native listings and contained the system/dpkg payload. A subsequent snapshot-protected package update also completed successfully. No destructive restore or reboot validation is claimed.
Posting the diagnosis, direct reproduction and minimal patch here rather than opening a duplicate issue or a fork/PR.
Oops, i think i introduced this bug. I think i did some testing on this function before submitting the PR. Maybe we should add some pipeline tests, so i could have commited the tests and they can also be reviewed...
I will provide a fix PR this weekend.
Activity
michaelkory commentedon Oct 10, 2026
I reproduced the same post-rsync ARM64 hang on Ubuntu 26.04 with Timeshift 25.12.4-1, RSYNC mode (headless CLI; no display server). There is a deterministic EOF bug in
file_line_count()insrc/Utility/TeeJee.FileSystem.vala, independent of async callback timing. This also looks relevant to #523. I have not tested the Fedora package, so this does not establish that every reported hang has the same cause.Root cause and affected source
BufferedInputStream.read_byte()returns an integer, with -1 for EOF. The function narrows it tocharbefore comparing with -1. On the native AArch64 compiler used here, plain char is unsigned (__CHAR_UNSIGNED__ 1), so EOF becomes 255 and the loop never exits. The generated C confirms the narrowing togchar; retaininggintfixes it.The faulty function is identical in Ubuntu's 25.12.4 source and upstream 26.09.0/master at e7e54ab7b96f0ca79774662544ccd93e58059b48. Master was rechecked before posting.
Minimal patch
This preserves newline counting, buffering, stream closure and error handling. Keeping the integer also avoids treating a real byte 0xff as EOF on signed-char targets (that case was not executed on a signed-char target here).
Focused reproduction without taking a system snapshot
On native Ubuntu 26.04 AArch64, with Vala 0.56.18, GCC 15.2 and GLib 2.88, extract the original function from the source checkout at the revision above:
Save this minimal caller as
direct-call.vala:Compile and call the verbatim function, not a rewritten model of its loop:
Apply the two-line patch to the source, repeat the same extraction into
fixed-function.vala, then compile with that file and-o fixedand run the same three inputs.Observed native results (each invocation bounded by
timeout 2):one\ntwo\nThe focused calls and package builds ran in a native ARM64 build container; full Timeshift snapshot validation ran on the Ubuntu guest itself, not inside the container. A locally rebuilt Ubuntu package with only this upstream source change built successfully, and rebuilding the retained corrected source produced a byte-identical binary package. After installing it, real RSYNC snapshots completed, wrote
info.json, appeared in native listings and contained the system/dpkg payload. A subsequent snapshot-protected package update also completed successfully. No destructive restore or reboot validation is claimed.Posting the diagnosis, direct reproduction and minimal patch here rather than opening a duplicate issue or a fork/PR.
ygerlach commentedon Oct 10, 2026
Oops, i think i introduced this bug. I think i did some testing on this function before submitting the PR. Maybe we should add some pipeline tests, so i could have commited the tests and they can also be reviewed...
I will provide a fix PR this weekend.
fredcwells commentedon Oct 29, 2026
Looks like it's merge-blocked. Not clear why.
fredcwells commentedon Nov 1, 2026
Is this a clue to the merge block?
Check failure on line R70
Check failure:
FileTest ==> file test
Build / build / build (mint22, linuxmintd/mint22.3-amd64, Mint 22, true) / Mint 22
fredcwells commentedon Nov 1, 2026
So, I applied the @michaelkory minimal patch, successfully rebuilt & tested full snapshot locally on my Fedora 44.
Sadly, no fix. :(
CORRECTION: The patch actually did fix the problem - once I actually applied it correctly.
srebrovvilen01 commentedon Nov 8, 2026
I had the same problem with Armbian Resolute on my Rock 5 ITX. Applying the patch solved it.