onetrueawk / awk

One true awk
Other
1.96k stars 156 forks source link

delete ARGV #229

Closed riscygeek closed 2 months ago

riscygeek commented 2 months ago

Example

$ awk 'BEGIN { delete ARGV; } { print; }' a b c
Segmentation fault (core dumped)

Environment

OS: OpenBSD/amd64 7.5 Version: both the current git and the one in base

sookach commented 2 months ago

I can take a look at this over the weekend.

millert commented 2 months ago

This is a basic use-after-free bug, easy to reproduce under valgrind. The ARGV symbol table is freed by awkdelete() but the ARGVtab global still has the old (now freed) value. I would expect ENVIRON to have a similar issue. Adding checks for ARGVtab and ENVtab in awkdelete() would work around the issue but maybe there is a more elegant solution.

Actually, ENVtab is not an issue as it is only used in envinit() and doesn't actually need to be global.

plan9 commented 2 months ago

thanks @riscygeek for the report. I'm amazed we never spotted this before.

millert commented 2 months ago

Keeping a pointer to the Cell containing ARGV instead of the table itself avoids the problem.

riscygeek commented 2 months ago

thanks @riscygeek for the report. I'm amazed we never spotted this before.

I found this while trying to create something like this:

#!/bin/sh
# Can't do "#!/usr/bin/env awk -f", because POSIX doesn't specify what happens,
# if I have more than one argument in the shebang \
exec awk -f "$0" "$@"

BEGIN {
    for (i = 1; i < ARGC; ++i)
        print ARGV[i];
    delete ARGV;
}

Just out of curiosity, do you know if POSIX specifies what happens, if you delete ARGV? GNU Awk just assumes, that no arguments were given.

plan9 commented 2 months ago

todd's changes were pulled.