Package: bash
Version: 5.2.37-2+b10
Severity: minor
File: /usr/bin/bash
I think this is NotABugTM, but I was so surprised I had to write it down/up.
I think the appropriate response is "don't do that, then" and
maybe add a comment in the manpage e.g.
HISTFILE should point to a regular file, not a symlink
Initially I noticed that every interactive bash process was 85MB RSS.
My ~/.bash_history was 24MB; moving it away fixed bash to be only 6MB RSS.
I increase HISTFILESIZE, but not THAT much.
Its oldest entry was from 2022, when my host was first built.
My ~/.bash_history is a symlink, and
I speculated bash was measuring the length of the symlink and
concluding "it's small enough, nothing to truncate".
i.e. stat vs lstat.
Attached is a test transcript showing truncation is silently skipped
when ~/.bash_history is a symlink to ~/.local/share/bash/history.
Digging through the code, I can't see anything in here:
https://sources.debian.org/src/bash/5.3-4/bashhist.c
I think the underlying issue is in readline:
https://sources.debian.org/src/readline/8.3-4/histfile.c#L572-L581
I think if HISTFILE points to a symlink, readline skips truncation entirely.
However I can't see where bashhist.c ever calls history_truncate_file, so
that may be entirely the wrong function.
-- System Information:
Debian Release: 13.7
APT prefers stable-updates
APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500,
'proposed-updates'), (500, 'stable')
Architecture: amd64 (x86_64)
Kernel: Linux 6.12.107+deb13-amd64 (SMP w/8 CPU threads; PREEMPT)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE,
TAINT_UNSIGNED_MODULE
Locale: LANG=en_AU.UTF-8, LC_CTYPE=en_AU.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
Versions of packages bash depends on:
ii base-files 13.8+deb13u7
ii debianutils 5.23.2
ii libc6 2.41-12+deb13u4
ii libtinfo6 6.5+20250216-2
Versions of packages bash recommends:
ii bash-completion 1:2.16.0-7
Versions of packages bash suggests:
pn bash-doc <none>
-- no debconf information
# First create a completely clean environment, so none of my personal config
can cause weirdness.
bash5$ mmdebstrap forky /dev/null --customize-hook='env -i TERM=dumb
PATH=/bin:/sbin chroot $1 bash'
I: automatically chosen mode: unshare
I: chroot architecture amd64 is equal to the host's architecture
I: finding correct signed-by value...
done
I: automatically chosen format: null
I: using /tmp/mmdebstrap.tTpw9nfJXg as tempdir
I: running apt-get update...
done
I: downloading packages with apt...
done
I: extracting archives...
done
I: installing essential packages...
done
I: installing remaining packages inside the chroot...
done
done
I: running --customize-hook in shell: sh -c 'env -i TERM=dumb PATH=/bin:/sbin
chroot $1 bash' exec /tmp/mmdebstrap.tTpw9nfJXg
root@hera:/# echo echo file was read >> ~/.bashrc
root@hera:/# echo shopt -s histappend >> ~/.bashrc
root@hera:/# echo HISTSIZE=3 HISTFILESIZE=5 >> ~/.bashrc
root@hera:/# bash
file was read
root@hera:/# :a
bash: :a: command not found
root@hera:/# : a
root@hera:/# : b
root@hera:/# : c
root@hera:/# : d
root@hera:/# : e
root@hera:/# : f
root@hera:/# exit
exit
root@hera:/# wc -l ~/.bash_history
5 /root/.bash_history
root@hera:/# bash
file was read
root@hera:/# : g
root@hera:/# : h
root@hera:/# exit
root@hera:/# wc -l ~/.bash_history
5 /root/.bash_history
root@hera:/# fmt < ~/.bash_history
: e : f exit : g : h
root@hera:/# mkdir -p ~/.local/share/bash
root@hera:/# mv ~/.bash_history ~/.local/share/bash/history
root@hera:/# ln -s .local/share/bash/history ~/.bash_history
root@hera:/# bash
file was read
root@hera:/# : i
root@hera:/# : j
root@hera:/# : k
root@hera:/# : l
root@hera:/# : m
root@hera:/# exit
exit
root@hera:/# fmt < ~/.bash_history
: e : f exit : g : h : l : m exit
root@hera:/# wc -l ~/.bash_history
8 /root/.bash_history
root@hera:/# # if ~/.bash_history is a symlink, it fails to truncate the file
root@hera:/# mv -b ~/.local/share/bash/history ~/.bash_history
root@hera:/# ls -l ~/.bash_history
-rw------- 1 root root 34 Oct 8 05:05 /root/.bash_history
root@hera:/# bash
file was read
root@hera:/# exit
exit
root@hera:/# ls -l ~/.bash_history
-rw------- 1 root root 22 Oct 8 05:10 /root/.bash_history
root@hera:/# # You can see that going back to a regular file, it gets truncated
correctly
root@hera:/#