[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#481543: libc6: low-memory snprintf provokes internal segfault



Petr Salinger <Petr.Salinger@seznam.cz> wrote:
> could you test what are exactly condition of segfault ?
>
> For me (glibc 2.7-15, x86_64)
>   strace zsh -c 'ulimit -v 10000; strace ./a.out %$[5*2**25]d'
> segfaults, but
>   strace zsh -c 'ulimit -v 10000; ./a.out %$[5*2**25]d'
> does not.
>
> Similarly with  "ulimit -v 5000", it looks like strace
> with low-memory provokes segfault.

The bug/failure is unrelated to strace.
But since running a.out under strace increases its virtual memory
utilization, you have to use a larger limit -- or else the
binary won't even run.  If the limit is too low, things will fail
while trying to load shared libraries, or zsh itself will fail.

There are a couple of additional variables that can influence things
and that may cause it to fail for me but not for you.  The size of your
environment and start-up code run by zsh can change the threshold.
To eliminate those differences, run it with an empty environment and
with zsh's -f option.  Since it's good to watch dmesg output to
see whether it's zsh or a.out that's failing, use this slightly
different program.

cat <<EOF > k.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
  char buf[200];
  char *fmt = argv[1];
  if (argc < 2)
    abort ();
  int n = snprintf (buf, sizeof buf, fmt, 1);
  return 0;
}
EOF

And might as well eliminate the shared-libraries,
so compile with -static:

    gcc -static k.c

Then run it like this:

    env -u -- zsh -f -c 'ulimit -v 5000; ./a.out %$[5*2**20]d' || dmesg|tail -1

This demonstrates that it is indeed a.out/libc that provokes
the segfault.  Here's the output I get:

    [2331489.137491] zsh[21289]: segfault at 0 ip 7f1126c824f4 sp \
      7fff2fa49778 error 6 in libc-2.7.so[7f1126c06000+14a000]

Do the same thing with true, and there's no problem:

    $ env -u -- zsh -f -c 'ulimit -v 5000; /bin/true' || dmesg|tail -1

But if you use a command that calls printf or other stream output
functions, it'll fail because glibc's stream output initialization code
tries to allocate space and fails, and then segfaults.



Reply to: