Re: [PATCH] setbuf.3: fix the error in section BUGS

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

 



Hi Zhiheng,

On Thu, Apr 15, 2021 at 2:01 PM Zhiheng Li <phoenix_lzh@xxxxxxxx> wrote:
>
> Hello Alex,
>
> Section BUGS in setbuf.3 says the space that buf points must be exist at
> program termination. And it says that the example is invalid. It wants
> to express that the example cannot print "Hello, world!". Because the
> stack space that buf points to is released when the program terminates
> by return.
> But the example prints "Hello, world!". So i say there is something
> wrong with this example.
> The original author should have made two mistakes:
> 1. The typo of 'stdout';
> 2. The return is used. The original author did not know that the return
> would close all file streams before terminating the program. Because
> this program uses setbuf(3), the "Hello, world!" printed by printf(3)
> will be saved in the buffer first. When the file stream is closed, buf
> is exist, and the buffer is flushed, so the "Hello, world!" in the
> buffer is printed(This knowledge comes from APUE 7.3).

I've tried a slightly modified example on my Ubuntu 20.04 x86-64 VM
(with just the stdout change but without _exit):

#include <stdio.h>

int main()
{
    char buf[100];
    setbuf(stdout, buf);
    printf("Hello, world\n!");
    return 0;
}

I've built it with '-Wall -g'. I get garbage in the output:

stefan@spuiu-vm:~/src/test/man_pages$ ./setbuf
���Ystefan@spuiu-vm:~/src/test/man_pages$

So I would say the buffer flushing happens outside of main(). If I
remove the setbuf(), I see "Hello, world" printed as expected.
I've also tried building with -O2 - it simply prints a different kind
of garbage:
stefan@spuiu-vm:~/src/test/man_pages$ ./setbuf
ȿ
 Qstefan@spuiu-vm:~/src/test/man_pages$

So I would say the code is invalid as is (if stdout is used instead of stdin).

Just my 2 cents,
Stefan.

> And returning an integer value from the main function is equivalent to
> calling exit(3) with the same value(This knowledge also comes from APUE
> 7.3). So return and exit(3) cannot be used.
> _exit(3) and _Exit(3) terminate the program immediately, and they don't
> close the file stream(This knowledge also comes from APUE 7.3), So using
> _exit(3) and _Exit(3) does not print "Hello, world".
> I'm using Thunderbird to send this email. It's very easy to use. Thank you.
>
> This is what I was going to send. When I was about to press the send
> button, I thought again that it would be inappropriate to use _exit(2).
> When using _exit(2), the file stream will not be flushed, but buf still
> exists when the program terminates (the program terminates at the end of
> main function, and buf exists at this time, which is in line with the
> author's requirements, but the author wants to give a counter example).
> So is the following example more appropriate?
> #include <stdio.h>
> void setmybuf(FILE *fp)
> {
>         char buf[BUFSIZ];
>         setbuf(fp, buf);
> }
> int main(void)
> {
>         setmybuf(stdout);
>         printf("Hello, world!\n");
>         return 0;
> }
> When the setmybuf returns, the buf stack space is released. When the
> program close the file stream by return, buf does not exist for the main
> function, which is in line with the author's original intention(This is
> a invalid example).
> Although the above program can still print "Hello, world!" in my
> environment(ubuntu18.04, gcc5.5.0, glibc2.27), that's because the
> address pointing to buf can still be used illegally(dangling pointer).
> You can add some code to the source code to make the program produce
> exceptions, like this:
> #include <stdio.h>
> void setmybuf(FILE *fp)
> {
>         char buf[BUFSIZ];
>         setbuf(fp, buf);
> }
> int test(int i)
> {
>         if (i > 0) {
>                 i--;
>                 test(i);
>         } else {
>                 printf("zzzzz\n");
>                 return 0;
>         }
> }
> int main(void)
> {
>         setmybuf(stdout);
>         printf("Hello, world!\n");
>         test(1000);
>         return 0;
> }
> Recursively called functions test use the stack space of buf in
> setmybuf, which can cause segmentation fault in my evironment.
>
>
> Sincerely,
> Zhiheng Li
>
>
>
> On 4/12/21 5:22 PM, Alejandro Colomar (man-pages) wrote:
> > On 4/12/21 9:44 AM, Zhiheng Li wrote:
> >> ---
> >>   man3/setbuf.3 | 5 +++--
> >>   1 file changed, 3 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/man3/setbuf.3 b/man3/setbuf.3
> >> index 5e5d57f89..e6d41b2a9 100644
> >> --- a/man3/setbuf.3
> >> +++ b/man3/setbuf.3
> >> @@ -224,14 +224,15 @@ For example, the following is invalid:
> >>   .PP
> >>   .EX
> >>   #include <stdio.h>
> >> +#include <unistd.h>
> >>   int
> >>   main(void)
> >>   {
> >>       char buf[BUFSIZ];
> >> -    setbuf(stdin, buf);
> >> +    setbuf(stdout, buf);
> >>       printf("Hello, world!\en");
> >> -    return 0;
> >> +    _exit(0);
> >>   }
> >>   .EE
> >>   .SH SEE ALSO
> >>
> >
> > Hello Zhiheng Li,
> >
> > I never used setbuf(3), so I don't know much about this example and why
> > it is "invalid", and therefore also don't know why it is wrong in being
> > invalid.
> >
> > As far as I can see, 'stdin' just seems to be a typo because it's not
> > being used, and probably 'stdout' was meant instead, as you point out.
> >
> > What about _exit(0)?  Why _exit(2) and not return (or equivalently
> > exit(3))?  Could you explain that a bit more?
> >
> > BTW, Could you please use a mailer that allows you to write plain text
> > emails?  Mozilla Thunderbird may be easy to use for you, and it comes
> > with most Linux distros.
> >
> > Thanks,
> >
> > Alex
> >




[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux