Bug 101773 - errors when writing to .gcda file are not checked
Summary: errors when writing to .gcda file are not checked
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: gcov-profile (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-08-04 10:20 UTC by Vincent Lefèvre
Modified: 2021-08-04 15:28 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-04 00:00:00


Attachments
added missing error check on fclose in gcc/gcov-io.c (181 bytes, patch)
2021-08-04 14:35 UTC, Vincent Lefèvre
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2021-08-04 10:20:31 UTC
When I run a program compiled with -fprofile-generate, this program creates a .gcda file, but write/close errors are not checked. With GCC 12.0.0 20210729 built from master and an almost full file system for the .gcda file:

$ gcc-test -O -fprofile-generate=dir tst.c
$ strace ./a.out
[...]
openat(AT_FDCWD, "dir/#home#vlefevre#a-tst.gcda", O_RDWR|O_CREAT, 0666) = 3
fcntl(3, F_SETLKW, {l_type=F_WRLCK, l_whence=SEEK_SET, l_start=0, l_len=0}) = 0
fcntl(3, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
read(3, "", 1024)                       = 0
lseek(3, 0, SEEK_SET)                   = 0
write(3, "adcg 02B\21\20\217\20\0\0\0\241\10\0\0\0\1\0\0\0\1\0\0\0\0\0\0\1"..., 84) = -1 ENOSPC (No space left on device)
close(3)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

Note that with gcc (Debian 10.2.1-6) 10.2.1 20210110, I get an error message:

$ ./a.out
libgcov profiling error:dir/#home#vlefevre#tst.gcda:Error writing

but the exit status is also 0, so that the error cannot be detected in scripts.
Comment 1 Richard Biener 2021-08-04 10:35:44 UTC
The question is what to do, exit() or alternatively simply stop attempting to write to the file?  (or even remove it)
Comment 2 Vincent Lefèvre 2021-08-04 11:39:54 UTC
An immediate exit() might yield other files, the terminal, etc. in a bad state. IMHO, the best thing to do is to stop attempting to write to the file (possibly attempt to remove it, but this might fail), and at the end, exit() with a nonzero exit status.
Comment 3 Martin Liška 2021-08-04 12:39:46 UTC
Note we have a env variable that can achieve an immediate exit (GCOV_EXIT_AT_ERROR):
https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Gcov-and-Optimization.html

in that case, 1 is the exit code.
Comment 4 Vincent Lefèvre 2021-08-04 12:50:08 UTC
GCOV_EXIT_AT_ERROR is not documented in the man page.

Anyway, it doesn't seem to work:

$ export GCOV_EXIT_AT_ERROR=1
$ printenv GCOV_EXIT_AT_ERROR
1
$ gcc-test -O -fprofile-generate=dir tst.c
$ ./a.out
$ echo $?
0
$ ls -l dir/*.gcda
-rw-r--r-- 1 vlefevre vlefevre 0 2021-08-04 14:48:01 dir/#home#vlefevre#a-tst.gcda
Comment 5 Martin Liška 2021-08-04 14:09:25 UTC
(In reply to Vincent Lefèvre from comment #4)
> GCOV_EXIT_AT_ERROR is not documented in the man page.

But we document that in GCC user manual.

> 
> Anyway, it doesn't seem to work:
> 
> $ export GCOV_EXIT_AT_ERROR=1
> $ printenv GCOV_EXIT_AT_ERROR
> 1
> $ gcc-test -O -fprofile-generate=dir tst.c
> $ ./a.out
> $ echo $?
> 0
> $ ls -l dir/*.gcda
> -rw-r--r-- 1 vlefevre vlefevre 0 2021-08-04 14:48:01
> dir/#home#vlefevre#a-tst.gcda

It works for me:

$ gcc --version
gcc (GCC) 12.0.0 20210804 (experimental)

$ df -h /tmp/ramdisk
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           4.0K  4.0K     0 100% /tmp/ramdisk

$ g++ ~/Programming/tramp3d/tramp3d-v4.ii -fprofile-generate=/tmp/ramdisk
$ GCOV_EXIT_AT_ERROR=1 ./a.out -n 0
...
libgcov profiling error:/tmp/ramdisk/#home#marxin#Programming#testcases#a-tramp3d-v4.gcda:Error writing
profiling:exiting after an error
$ echo $?
1

$ ./a.out -n 0
...
libgcov profiling error:/tmp/ramdisk/#home#marxin#Programming#testcases#a-tramp3d-v4.gcda:Error writing
echo $?
0
Comment 6 Vincent Lefèvre 2021-08-04 14:35:54 UTC
Created attachment 51259 [details]
added missing error check on fclose in gcc/gcov-io.c

Well, not all errors are detected. There is a missing test in gcc/gcov-io.c for fclose (which does a write system call to flush the buffers):

--- a/gcc/gcov-io.c
+++ b/gcc/gcov-io.c
@@ -199,7 +199,8 @@ gcov_close (void)
 {
   if (gcov_var.file)
     {
-      fclose (gcov_var.file);
+      if (fclose (gcov_var.file))
+       gcov_var.error = 1;
       gcov_var.file = 0;
     }
   gcov_var.mode = 0;

(also in attachment). I've tested this patch, and it solves my problem:

openat(AT_FDCWD, "dir/#home#vlefevre#a-tst.gcda", O_RDWR|O_CREAT, 0666) = 3
fcntl(3, F_SETLKW, {l_type=F_WRLCK, l_whence=SEEK_SET, l_start=0, l_len=0}) = 0
fcntl(3, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
read(3, "", 1024)                       = 0
lseek(3, 0, SEEK_SET)                   = 0
write(3, "adcg 02B\233\10\222\21\0\0\0\241\10\0\0\0\1\0\0\0\1\0\0\0\0\0\0\1"..., 84) = -1 ENOSPC (No space left on device)
close(3)                                = 0
write(2, "libgcov profiling error:dir/#hom"..., 68libgcov profiling error:dir/#home#vlefevre#a-tst.gcda:Error writing
) = 68
write(2, "profiling:exiting after an error"..., 33profiling:exiting after an error
) = 33
exit_group(1)                           = ?
+++ exited with 1 +++
Comment 7 Martin Liška 2021-08-04 15:12:00 UTC
(In reply to Vincent Lefèvre from comment #6)
> Created attachment 51259 [details]
> added missing error check on fclose in gcc/gcov-io.c
> 
> Well, not all errors are detected. There is a missing test in gcc/gcov-io.c
> for fclose (which does a write system call to flush the buffers):
> 
> --- a/gcc/gcov-io.c
> +++ b/gcc/gcov-io.c
> @@ -199,7 +199,8 @@ gcov_close (void)
>  {
>    if (gcov_var.file)
>      {
> -      fclose (gcov_var.file);
> +      if (fclose (gcov_var.file))
> +       gcov_var.error = 1;
>        gcov_var.file = 0;
>      }
>    gcov_var.mode = 0;
> 
> (also in attachment). I've tested this patch, and it solves my problem:

Great job! I was aware of the fclose, but didn't realize it fails during flushing.
May I please install the patch on your behalf?
Comment 8 Vincent Lefèvre 2021-08-04 15:15:38 UTC
(In reply to Martin Liška from comment #7)
> May I please install the patch on your behalf?

Yes. Thanks.
Comment 9 GCC Commits 2021-08-04 15:27:45 UTC
The master branch has been updated by Martin Liska <marxin@gcc.gnu.org>:

https://gcc.gnu.org/g:929f2cf4105ccf12d0684c6d5838f58f0ee5e7c7

commit r12-2736-g929f2cf4105ccf12d0684c6d5838f58f0ee5e7c7
Author: Vincent Lefèvre <vincent-gcc@vinc17.net>
Date:   Wed Aug 4 17:25:52 2021 +0200

    gcov: check return code of a fclose
    
    gcc/ChangeLog:
    
            PR gcov-profile/101773
            * gcov-io.c (gcov_close): Check return code of a fclose.
Comment 10 Martin Liška 2021-08-04 15:28:02 UTC
Thanks for your cooperation, fixed on master.