Bug#916562: libc6: fputs(), fputc(), and fwrite() do not fail on write error

2018-12-15 Thread Asher Gordon
On Saturday, December 15, 2018 7:02 PM, Samuel Thibault  
wrote:

> Hello,
>
> Asher Gordon, le sam. 15 déc. 2018 18:51:19 -0500, a ecrit:
>
> > If I use fputs(3), fputc(3), or fwrite(3) to write to a file that can
> > be opened for writing but cannot be written to (e.g /dev/full), the
> > functions return 1 rather than the expected EOF (or 0 in the case of
> > fread()).
>
> Well, that is not surprising since these functions are buffered. You
> need to call fflush() to make sure that no error happened on the actual
> underlying write.
>
> Samuel

You're right. I tried it with fflush() and it gave expected results. I guess we 
can close this bug now.



Bug#916562: libc6: fputs(), fputc(), and fwrite() do not fail on write error

2018-12-15 Thread Samuel Thibault
Hello,

Asher Gordon, le sam. 15 déc. 2018 18:51:19 -0500, a ecrit:
> If I use fputs(3), fputc(3), or fwrite(3) to write to a file that can
> be opened for writing but cannot be written to (e.g /dev/full), the
> functions return 1 rather than the expected EOF (or 0 in the case of
> fread()).

Well, that is not surprising since these functions are buffered. You
need to call fflush() to make sure that no error happened on the actual
underlying write.

Samuel



Bug#916562: libc6: fputs(), fputc(), and fwrite() do not fail on write error

2018-12-15 Thread Asher Gordon
Package: libc6
Version: 2.27-8
Severity: normal
Tags: upstream

Dear Maintainer,

If I use fputs(3), fputc(3), or fwrite(3) to write to a file that can
be opened for writing but cannot be written to (e.g /dev/full), the
functions return 1 rather than the expected EOF (or 0 in the case of
fread()). On the other hand, write(2) returns -1 and sets errno to
ENOSPC an expected.

Expected results:
The functions fputs() and fputc() should return EOF and fwrite()
should return 0. All the functions should set errno to ENOSPC (for
/dev/full).

Actual results:
The functions return 1 (an indication of success) and leave errno
unchanged.

Steps to reproduce:
Compile the attached program (the compiler flag `-fno-builtin' does
not change anything, nor does -O0):
$ gcc -o write write.c

Run the program with /dev/full as the output file:
$ ./write hello /dev/full
fputs() returned 1 and errno is 0 (Success).
fputc() returned 104 (h) and errno is 0 (Success).
fwrite() returned 5 (the length of "hello" is 5) and errno is 0 (Success).
write() returned -1 (the length of "hello" is 5) and errno is 28 (No space left 
on device).

The expected output is:
fputs() returned EOF (-1) and errno is 28 (No space left on device).
fputc() returned EOF (-1) and errno is 28 (No space left on device).
fwrite() returned 0 (the length of "hello" is 5) and errno is 28 (No space left 
on device).
write() returned -1 (the length of "hello" is 5) and errno is 28 (No space left 
on device).


-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 4.18.0-2-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages libc6 depends on:
ii  libgcc1  1:8.2.0-9

libc6 recommends no packages.

Versions of packages libc6 suggests:
ii  debconf [debconf-2.0]  1.5.69
pn  glibc-doc  
ii  libc-l10n  2.27-8
ii  locales2.27-8

-- debconf information:
* glibc/restart-services: cups cron
  glibc/kernel-too-old:
  glibc/kernel-not-supported:
  glibc/restart-failed:
  glibc/upgrade: true
  glibc/disable-screensaver:
* libraries/restart-without-asking: false
#include 
#include 
#include 
#include 

int main(int argc, char **argv) {
  int ret;
  size_t string_len;
  FILE *output_file;
  
  if (argc != 3) {
fprintf(stderr, "Usage: %s STRING FILE\nWrite STRING to FILE.\n", argv[0]);
return 1;
  }

  /* Open the file */
  if (!(output_file = fopen(argv[2], "w"))) {
fprintf(stderr, "%s: could not open %s: %m\n", argv[0], argv[2]);
return 1;
  }

  /* Now try to write to the file using fputs() */
  errno = 0;
  ret = fputs(argv[1], output_file);
  /* `ret' should be EOF if an error occured (see fputs(3)) */
  printf ("fputs() returned ");
  if (ret == EOF)
printf("EOF (%d)", ret);
  else
printf("%d", ret);
  printf(" and errno is %d (%m).\n", errno);

  /* This happens with fputc() too */
  errno = 0;
  ret = fputc(argv[1][0], output_file);
  printf("fputc() returned ");
  if (ret == EOF)
printf("EOF (%d)", ret);
  else
printf("%d (%c)", ret, (char)ret);
  printf(" and errno is %d (%m).\n", errno);

  string_len = strlen(argv[1]);

  /* This happens with fwrite() too */
  errno = 0;
  printf("fwrite() returned %lu (the length of \"%s\" is %lu) ",
 fwrite(argv[1], 1, string_len, output_file), argv[1], string_len);
  printf("and errno is %d (%m).\n", errno);

  /* write() gives us expected results */
  errno = 0;
  printf("write() returned %ld (the length of \"%s\" is %lu) ",
 write(fileno(output_file), argv[1], string_len), argv[1], string_len);
  printf("and errno is %d (%m).\n", errno);

  return 0;
}