Why does dirname() inside nftw() callback cause abort?

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue Aug 8 23:35:00 GMT 2017



On 08/08/2017 14:59, john smith wrote:
> The following code doesn't work as expected:
> 
> #define _XOPEN_SOURCE 500
> #include <ftw.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <libgen.h>
> #include <unistd.h>
> #include <errno.h>
> 
> static int display_info(const char *fpath, const struct stat *sb,
> 	     int tflag, struct FTW *ftwbuf)
> {
>   (void)sb;
>   (void)tflag;
>   (void)ftwbuf;
> 
>   char *dir = dirname((char *) fpath);
>   return 0;		/* To tell nftw() to continue */
> }

Because you are tampering with a buffer which is not supposed to be
changed by the callback (the necessity to cast to char * should have
hinted you about it).  To use dirname you will need to actually make
a copy of the input argument:

 [...]
 char *path = strdup (fpath);
 char *dir = dirname (path);
 /* Do something with dir.  */
 free (path);
 [...]

> 
> int usb_device_list_get(void)
> {
>   int flags = 0;
> 
>   if (nftw("/sys/bus/usb/devices", display_info, 20, flags)
>       == -1) {
>     perror("Traversing /sys/bus/usb/devices failed");
>     return errno;
>   }
> 
>   return 0;
> }
> 
> int main(void)
> {
>   usb_device_list_get();
>   return EXIT_SUCCESS;
> }
> 
> $ ./usb
> usb: ../sysdeps/wordsize-64/../../io/ftw.c:536: ftw_dir: Assertion
> `startp != data->dirbuf' failed.
> Aborted
> $ echo $?
> 134
> 
> It's just an example, it is a part of a bigger project when dirname()
> output is actually used.
> 
> It only crashes on x64 system, it works well on x32. Man nftw
> mentions:

It is working on x32 just by chance in your system, on mine (ubuntu 16)
it fails on all x86 abis (x86_64, x86_64-x32, and i686).

> 
> "POSIX.1-2008 notes that the results are unspecified if fn does not
> preserve the current working directory."
> 
> IIUC, it refers to the working directory that can be checked with
> getcwd() - I checked that dirname() does not change it.
> 
> glibc version:
> 
> GNU C Library (GNU libc) stable release version 2.26, by Roland McGrath et al.
> Copyright (C) 2017 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.
> There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
> PARTICULAR PURPOSE.
> Compiled by GNU CC version 7.1.0.
> Available extensions:
>         crypt add-on version 2.1 by Michael Glad and others
>         GNU Libidn by Simon Josefsson
>         Native POSIX Threads Library by Ulrich Drepper et al
>         BIND-8.2.3-T5B
> libc ABIs: UNIQUE IFUNC
> 
> OS:
> 
> Slackware Linux -current x64
> 



More information about the Libc-help mailing list