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:/# 

Reply via email to