Skip to content

fix: reject non-finite ranks when importing - #1280

Open
pcruz1905 wants to merge 1 commit into
ajeetdsouza:mainfrom
pcruz1905:fix-non-finite-rank
Open

fix: reject non-finite ranks when importing#1280
pcruz1905 wants to merge 1 commit into
ajeetdsouza:mainfrom
pcruz1905:fix-non-finite-rank

Conversation

@pcruz1905

Copy link
Copy Markdown

Importing a data file whose rank is inf, nan, or just larger than an
f64 can hold throws away the rest of the database:

$ cat ~/.z
/aaa|5|1000000000
/bbb|inf|1000000000
/ccc|3|1000000000
/ddd|10|1000000000

$ zoxide import z; echo "exit $?"
exit 0

$ zoxide query --list --score --all
   NaN /bbb

Three directories are gone and the command reports success.

Database::age scales every rank by 0.9 * max_age / total. One non-finite
rank makes total infinite, so the factor is 0.0: every other directory is
multiplied down to 0.0, drops below the 1.0 threshold and is removed,
while the entry responsible survives, because NaN < 1.0 is false like every
other comparison against it.

It does not stop there. The NaN keeps the total NaN, so total_age > max_age
is never true again and the database stops ageing permanently — 20 dirs at
rank 600 stay at a total of 12000 instead of being scaled back to 9000.

last_accessed is already validated, in that parse::<u64>() rejects
anything unreasonable and reports it with a line number. Doing the same for
the rank keeps the bad line out and leaves the rest of the file alone:

$ zoxide import z
/home/user/.z:2: invalid entry: /bbb|inf|1000000000

$ zoxide query --list --score --all
   1.2 /aaa
   0.8 /ccc

age drops non-finite ranks too, so a database that has already been hit by
this recovers on the next run rather than staying stuck.

This covers z, fasd, z.lua and zsh-z, which share the parser.
autojump passes its rank through a sigmoid and was never affected.

Testing

cargo test (26 tests), cargo +nightly fmt --check and
cargo clippy --all-targets -- -D warnings are clean.

Added a parametrised parser test covering inf, -inf, nan and 1e400
alongside the ranks that must keep working, including a path containing |,
and two age tests: one that the finite entries survive a poisoned database,
one that ageing still brings the total back under max_age. Reverting either
half of the fix on its own fails its tests and leaves the valid cases green.

Importing a z, fasd, z.lua or zsh-z data file whose rank is `inf`, `nan`,
or simply larger than f64 can hold silently wipes the rest of the database.

Ageing scales every rank by `0.9 * max_age / total`. One non-finite rank
makes the total infinite, so the factor is zero: every other directory is
multiplied down to 0.0, falls under the 1.0 threshold and is dropped, while
the offending entry survives as NaN because none of the comparisons against
it hold. Importing four directories where one has an `inf` rank leaves a
single NaN entry behind, and the command still exits 0.

The NaN then keeps the total NaN, `total_age > max_age` is never true again,
and the database stops ageing for good.

The last_accessed field is already validated by virtue of parsing as u64, so
do the same for the rank and reject it with the usual line-numbered error.
Ageing also drops non-finite ranks now, so a database that was already hit
by this recovers instead of staying stuck.
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.

1 participant