public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
* When/how is global "errno" variable from reent.c to be used?
@ 2020-10-16 15:50 Grant Edwards
  2020-10-16 16:38 ` Richard Damon
  0 siblings, 1 reply; 5+ messages in thread
From: Grant Edwards @ 2020-10-16 15:50 UTC (permalink / raw)
  To: newlib

[Sorry for yet another errno vs. reentrancy thread.]

I've been studying errno, __errno, _impure_ptr et alia, and I think I
understand how that's supposed to work. If you don't define
_REENT_ONLY, then errno is defined as *(__errno()), where __errno()
returns &_REENT->errno, and _REENT is #defined as _impure_ptr, and
thread context switches are supposed to set _impure_ptr to point to a
per-thread struct _reent.

If you define _REENT_ONLY, then there is no 'errno' declared in
errno.h, and you've got to mannually pass a struct _reent pointer to
the _r versions of various lib[cm] functions.

But, in the application source I've been given, the LWIP stack does
not include newlib's errno.h.  Instead it declares "extern int errno"
and then uses errno as usual. That external declaration is satisfied
at link time by the global "errno" exported by libc/reent/reent.c.

That seems to be non-thread-safe and won't interoperate correctly with
newlib's library calls or with application code that includes newlib's
errno.h.

What is that global errno variable for and how is to be used?

Is there a use case for single-threaded applications that I've missed
where newlib's library calls will set/check the global 'int errno'
variable instead of _impure_ptr->errno?

Or is the LWIP configuration broken?

Even if there is a single-threaded use case for newlib where everybody
uses the global 'int errno' variable, the application in question is
multi-threaded, so it's probably still broken. The RTOS in use does
not set _impure_ptr on context switches, so I believe that switching
to using the newlib errno.h which will define errno as *(__errno())
still won't work as it should.

FWIW, the toolchain I'm using is

 gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2

from

 https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads

It contains v3.3.0 newlib and newlib-nano built from

 git://sourceware.org/git/newlib-cygwin.git commit 6d79e0a58866548f435527798fbd4a6849d05bc7

The LWIP application I'm looking at uses newlib-nano.

--
Grant






^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: When/how is global "errno" variable from reent.c to be used?
  2020-10-16 15:50 When/how is global "errno" variable from reent.c to be used? Grant Edwards
@ 2020-10-16 16:38 ` Richard Damon
  2020-10-16 18:10   ` Grant Edwards
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Damon @ 2020-10-16 16:38 UTC (permalink / raw)
  To: newlib

Software the explicitly declares errno as
extern int errno;
is broken, and violates the C standard, and creates explicitly stated
Undefined Behavior.


On 10/16/20 11:50 AM, Grant Edwards via Newlib wrote:
> [Sorry for yet another errno vs. reentrancy thread.]
>
> I've been studying errno, __errno, _impure_ptr et alia, and I think I
> understand how that's supposed to work. If you don't define
> _REENT_ONLY, then errno is defined as *(__errno()), where __errno()
> returns &_REENT->errno, and _REENT is #defined as _impure_ptr, and
> thread context switches are supposed to set _impure_ptr to point to a
> per-thread struct _reent.
>
> If you define _REENT_ONLY, then there is no 'errno' declared in
> errno.h, and you've got to mannually pass a struct _reent pointer to
> the _r versions of various lib[cm] functions.
>
> But, in the application source I've been given, the LWIP stack does
> not include newlib's errno.h.  Instead it declares "extern int errno"
> and then uses errno as usual. That external declaration is satisfied
> at link time by the global "errno" exported by libc/reent/reent.c.
>
> That seems to be non-thread-safe and won't interoperate correctly with
> newlib's library calls or with application code that includes newlib's
> errno.h.
>
> What is that global errno variable for and how is to be used?
>
> Is there a use case for single-threaded applications that I've missed
> where newlib's library calls will set/check the global 'int errno'
> variable instead of _impure_ptr->errno?
>
> Or is the LWIP configuration broken?
>
> Even if there is a single-threaded use case for newlib where everybody
> uses the global 'int errno' variable, the application in question is
> multi-threaded, so it's probably still broken. The RTOS in use does
> not set _impure_ptr on context switches, so I believe that switching
> to using the newlib errno.h which will define errno as *(__errno())
> still won't work as it should.
>
> FWIW, the toolchain I'm using is
>
>  gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2
>
> from
>
>  https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
>
> It contains v3.3.0 newlib and newlib-nano built from
>
>  git://sourceware.org/git/newlib-cygwin.git commit 6d79e0a58866548f435527798fbd4a6849d05bc7
>
> The LWIP application I'm looking at uses newlib-nano.
>
> --
> Grant
>
>
>
>
>

-- 
Richard Damon


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: When/how is global "errno" variable from reent.c to be used?
  2020-10-16 16:38 ` Richard Damon
@ 2020-10-16 18:10   ` Grant Edwards
  2020-10-16 19:06     ` Richard Damon
  0 siblings, 1 reply; 5+ messages in thread
From: Grant Edwards @ 2020-10-16 18:10 UTC (permalink / raw)
  To: newlib

On 2020-10-16, Richard Damon <Richard@Damon-Family.org> wrote:

> Software the explicitly declares errno as
> extern int errno;
> is broken, and violates the C standard, and creates explicitly stated
> Undefined Behavior.

So the LWIP source is just plain wrong.

What is the global 'int errno' exported by reent.c for?

--
Grant



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: When/how is global "errno" variable from reent.c to be used?
  2020-10-16 18:10   ` Grant Edwards
@ 2020-10-16 19:06     ` Richard Damon
  2020-10-16 21:49       ` Grant Edwards
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Damon @ 2020-10-16 19:06 UTC (permalink / raw)
  To: newlib

On 10/16/20 2:10 PM, Grant Edwards via Newlib wrote:
> On 2020-10-16, Richard Damon <Richard@Damon-Family.org> wrote:
>
>> Software the explicitly declares errno as
>> extern int errno;
>> is broken, and violates the C standard, and creates explicitly stated
>> Undefined Behavior.
> So the LWIP source is just plain wrong.
>
> What is the global 'int errno' exported by reent.c for?
>
> --
> Grant
>
>
First, newlib considers itself as part of 'the implementation', as its
purpose is to provide the 'standard library' for an implementation, thus
it can do what it wants here (as long as the net result meets the
specifications).

I would have to dig into the actual implementation details to tell for
sure, but first check if when the statement int errno; is compiled, is
errno currently a macro, and after replacing that macro with its
definition what the statement actually defines, it might be creating the
pointer that is used to access the effective errno.

It could also be creating a global variable just to limit the breakage
that programs that do it wrong incur (though, I might prefer getting the
link error errno not defined rather than code that ends up checking the
wrong errno).

-- 
Richard Damon


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: When/how is global "errno" variable from reent.c to be used?
  2020-10-16 19:06     ` Richard Damon
@ 2020-10-16 21:49       ` Grant Edwards
  0 siblings, 0 replies; 5+ messages in thread
From: Grant Edwards @ 2020-10-16 21:49 UTC (permalink / raw)
  To: newlib

On 2020-10-16, Richard Damon <Richard@Damon-Family.org> wrote:

> First, newlib considers itself as part of 'the implementation', as its
> purpose is to provide the 'standard library' for an implementation, thus
> it can do what it wants here (as long as the net result meets the
> specifications).

Right. I didn't mean to imply that newlib having a globally visible
integer variable named 'errno' was wrong. I was just asking what it
was for.

> I would have to dig into the actual implementation details to tell
> for sure, but first check if when the statement int errno; is
> compiled, is errno currently a macro, and after replacing that macro
> with its definition what the statement actually defines, it might be
> creating the pointer that is used to access the effective errno.

Sorry, I don't really understand that sentence. The file
newlib/libc/reent/reent.c defines a globally visible integer variable
named 'errno'. I was asking what that globally visible 'int errno' was
for. I've done some additional code browsing, and it appears to be
used by other files in newlib/libc/reent/ to provide fake "reentrant"
<whatever>_r() versions of system calls for which there aren't actual
_r() versions.

Except I don't see how those _r() functions could actaully _be_
rentrant, since they all use a single shared, global, errno variable.
The description/comments claiming they are rentrant seems to be
deceptive.  For example from readr.c (edited for time and to fit your
screen):

    /* Reentrant versions of read system call. */
    [...]
    /* We use the errno variable used by the system dependent layer.  */
    #undef errno
    extern int errno;
    /*
    [...]
    DESCRIPTION
    	This is a reentrant version of <<read>>.  It
    	takes a pointer to the global data block, which holds
    	<<errno>>.
    */
    
    _ssize_t _read_r (struct _reent *ptr, int fd, void *buf, size_t cnt)
    {
      _ssize_t ret;
    
      errno = 0;
      if ((ret = (_ssize_t)_read (fd, buf, cnt)) == -1 && errno != 0)
        ptr->_errno = errno;
      return ret;
    }

I just don't see how that function can be called reentrant.

> It could also be creating a global variable just to limit the breakage
> that programs that do it wrong incur

I don't think so. It appears to actually be used when making calls to
the system-dependent layer.

> (though, I might prefer getting the link error errno not defined
> rather than code that ends up checking the wrong errno).

Agreed.





^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-10-16 21:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-16 15:50 When/how is global "errno" variable from reent.c to be used? Grant Edwards
2020-10-16 16:38 ` Richard Damon
2020-10-16 18:10   ` Grant Edwards
2020-10-16 19:06     ` Richard Damon
2020-10-16 21:49       ` Grant Edwards

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).