Very short summary: cat "$file" | patch produces a Bad file descriptor-error, but patch < "$file" works, when libtrash is preloaded with LD_PRELOAD, and only on bigger projects.

Description: For this example, I work on the vanilla linux-3.18.21 kernel sources as downloaded from [1] (and extracted the archive, of course).

I want to patch it with TuxOnIce as downloaded von [2], and extracted.

In this example I show some big project, since with just small files everything works okay.

I work within the top level linux source directory, and from there the patch is located at ../patches/tuxonice-for-linux-3.18.21-2015-09-08.patch. No symlinks involved, everything on the same filesystem.

The following happens:

$ cat ../patches/tuxonice-for-linux-3.18.21-2015-09-08.patch | patch -p1 --dry-run
patch: **** can't open file Documentation/kernel-parameters.txt : Bad file descriptor

(exitcode: 2)


$ patch -p1 --dry-run < ../patches/tuxonice-for-linux-3.18.21-2015-09-08.patch 
checking file Documentation/kernel-parameters.txt
checking file Documentation/power/tuxonice-internals.txt

(runs successfully).

The problem has something to do with libtrash.so loaded via the LD_PRELOAD environment variable:

  • By default, I have export LD_PRELOAD=/usr/lib/libtrash.so. [3]
  • If I export LD_PRELOAD='' or unset LD_PRELOAD, it works fine.
  • If I just switch off the functioning of libtrash (but keep it preloaded), by export TRASH_OFF=YES, which is the way provided by libtrash, the problems persist.
  • It definitely has to do with libtrash and not with LD_PRELOAD itself, since when I export LD_PRELOAD='/usr/lib/libgtk3-nocsd.so.0' (the file exists) the patching with cat $file | patch works.

In fact, I expect cat "$file" | "$programme" to result in the same as "$programme" < "$file", but it doesn't.

It's a practical nuisance, since in practice instead of using cat, I would use things like xzcat or bzcat on the compressed patch files so that I don't need to decompress them in an extra step first.

I use bash, but that doesn't matter (within zsh the same). patch is GNU patch version 2.7.5, glib-config --version shows 1.2.10, I use an arch linux distribution and this problem did persist already for at least several months, including updates. Kernel 3.18.21.

Here are two outputs with strace, once strace-ing cat, once strace-ing patch, with export LD_PRELOAD=/usr/lib/libtrash.so and export TRASH_OFF=YES:


$ strace cat ../patches/tuxonice-for-linux-3.18.21-2015-09-08.patch | patch -p1 --dry-run




$ cat ../patches/tuxonice-for-linux-3.18.21-2015-09-08.patch | strace patch -p1 --dry-run



(Sorry for linking it, if I would put it directly stackexchange won't accept my post without telling me why).

I am not familiar with dynamic linking, strace and so on.

Does anyone know what goes on? If that is a bug somewhere, where would it be? (patch, libc, libtrash, dynamic linker, ..., ..., ?)

xzcat /usr/src/linux-3.18.21.tar.xz | tar -xv works (but xzcat some.patch.xz | patch does not), so it has at least some specificity with patch.

[1] linux kernel: https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.18.21.tar.xz

[2] TuxOnIce: http://tuxonice.nigelcunningham.com.au/downloads/all/tuxonice-for-linux-3.18.21-2015-09-08.patch.bz2

[3] libtrash: http://pages.stern.nyu.edu/~marriaga/software/libtrash/

  • whats inside ../patches/pf/patch-4.4-pf3 – 123 Feb 8 '16 at 13:34
  • Some linux kernel patches, See pf.natalenko.name (in fact it is the extracted pf.natalenko.name/sources/4.4/patch-4.4-pf3.xz). But it does not matter, since this behaviour is also when using other patches. In fact, cat $file | $programme should be the same as $programme < $file, but it isn't. – Golar Ramblar Feb 8 '16 at 13:47
  • I'd strace it to see what it does. There's a couple of things that can be done with a file set to stdin via < that can't be done on an input pipe (like reopening or seeking). I guess patch is trying to do one of those things. – PSkocik Feb 8 '16 at 14:02
  • I found out that it has to do something with the environment variable LD_PRELOAD. I have set it up to provide libtrash. When I provide an empty LD_PRELOAD to the cat ... | patch-command, it still fails, but when I unset it, patch works. Though, this is not a satisfying solution yet, since it fails also when I disable libtrash with TRASH_OFF=YES but still having the LD_PRELOAD set. I don't really understand what is going on -- will provide some more details and add them to my original question. – Golar Ramblar Feb 8 '16 at 14:55
  • Completely rewrote the question. – Golar Ramblar Feb 8 '16 at 16:41

libtrash is broken:

For example, in helpers.c:

char* make_absolute_path_from_dirfd_relpath(int dirfd, const char *arg_pathname)
   char *abs_path = NULL;

   if (arg_pathname == NULL)
    return NULL;
   else if (arg_pathname[0] == '/' || dirfd == AT_FDCWD)
    return arg_pathname;
   else if (dirfd <= 0)
    errno = EBADF;
    return NULL;

A value of 0 for a file descriptor is perfectly legitimate. Since you're using redirection, you're reading from stdin, which is file descriptor 0. I suspect that's what's breaking somewhere in libtrash.

| improve this answer | |
  • Thanks. Not a C-hacker and not knowing shared library stuff: If I change if (dirfd <= 0) to if (dirfd < 0), would that be also OK, or do you expect that it breaks other things? – Golar Ramblar Feb 9 '16 at 22:28
  • I wrote the author of libtrash. – Golar Ramblar Feb 9 '16 at 22:58
  • 1
    @GolarRamblar - If you make that change, it shouldn't hurt anything, but without going through the entire code base there's no way I can guarantee you anything. I can say that trying to use LD_PRELOAD to successfully interpose on IO calls of any type is extremely difficult to do correctly even when one is completely familiar with how basic Unix-type file descriptors behave. I encountered numerous bugs in IBM's use of LD_PRELOAD interposing when I supported a customer using IBM SANergy. And if IBM can't do it without bugs... – Andrew Henle Feb 9 '16 at 23:39
  • Seems libtrash is broken, yes: Recently issues appeared with files getting wrong permissions (240 instead of 644, 000) with libtrash: github.com/termih/libtrash/issues/3, github.com/termih/libtrash/issues/2. Maybe also related with updates in libc which libtrash is lacking behind? – Golar Ramblar Mar 11 '18 at 14:49
  • @GolarRamblar thank you for having written to me about this. Unfortunately the email didn't make it to my inbox so I only learned about this problem a few weeks ago when I was notified about a different problem and a link to this page popped up in Google. :) – arriaga Mar 25 '18 at 19:48

As Andrew Henle pointed out, this was due to a bug in libtrash. I have just released a new version that should fix this behavior.

| improve this answer | |
  • "This was a bug, but it's fixed now" seems like a fine answer to me. I moved the other half to a comment – Michael Mrozek Mar 26 '18 at 1:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.