public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
* Difficulties with tzset() and setenv()
       [not found] <1022512790.3544807.1501484481626.ref@mail.yahoo.com>
@ 2017-07-31  7:01 ` R. Diez via newlib
  2017-07-31 15:56   ` Craig Howland
  0 siblings, 1 reply; 3+ messages in thread
From: R. Diez via newlib @ 2017-07-31  7:01 UTC (permalink / raw)
  To: newlib

Hallo all:

I am writing embedded software that has to deal with time zones. The internal clock is UTC, as delivered over SNTP or received from an external GPS device.  The user can enter any timezone in POSIX format, which is a string like "CET-1CEST,M3.5.0,M10.5.0/3" (this example is the usual one for European Central Time).

I am finding it difficult to implement this with Newlib. For starters, tzset() does not return an error code if the time zone string that the user entered is syntactically wrong (cannot be parsed properly), so I am resorting to the work-around of setting an invalid time zone, then the new one, and checking whether the new one has changed tzname, which means that it has been accepted.

Furthermore, using setenv() to set the required environment variable TZ results in a memory leak. There is no easy work-around I know of for Newlib.  I undertand that the POSIX standard around setenv() is flawed and leads to this kind of trouble, but that is no real excuse to provide an alternative, leak-free API in Newlib.

In my particular case, the best thing to do would be to publish a variant of tzset() that takes the time zone string directly, instead of reading it from TZ. My embedded firmware does not really need an environment, and tzset() keeps a private copy of TZ anyway.

Furthermore, I am not sure that _setenv_r() is implemented correctly. Things I have noticed are:

1) "alloced = 1;" is set before checking whether _malloc_r() fails.
2) The memory allocated for an environment variable never shrinks, which can lead to great memory waste.

3) I am not sure whether the behaviour is correct if _realloc_r() fails. The code is hard to understand.


Please copy me on any answers, as I am not subscribed to this mailing list.

Best regards,
  rdiez

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

* Re: Difficulties with tzset() and setenv()
  2017-07-31  7:01 ` Difficulties with tzset() and setenv() R. Diez via newlib
@ 2017-07-31 15:56   ` Craig Howland
  2017-08-01  6:57     ` R. Diez via newlib
  0 siblings, 1 reply; 3+ messages in thread
From: Craig Howland @ 2017-07-31 15:56 UTC (permalink / raw)
  To: R. Diez, newlib

On 07/31/2017 03:01 AM, R. Diez via newlib wrote:
> Hallo all:
>
> I am writing embedded software that has to deal with time zones. The internal clock is UTC, as delivered over SNTP or received from an external GPS device.  The user can enter any timezone in POSIX format, which is a string like "CET-1CEST,M3.5.0,M10.5.0/3" (this example is the usual one for European Central Time).
>
> I am finding it difficult to implement this with Newlib. For starters, tzset() does not return an error code if the time zone string that the user entered is syntactically wrong (cannot be parsed properly), so I am resorting to the work-around of setting an invalid time zone, then the new one, and checking whether the new one has changed tzname, which means that it has been accepted.
Since POSIX defines tzset() as void, you're pretty much stuck with an approach 
like this.
> Furthermore, using setenv() to set the required environment variable TZ results in a memory leak. There is no easy work-around I know of for Newlib.  I undertand that the POSIX standard around setenv() is flawed and leads to this kind of trouble, but that is no real excuse to provide an alternative, leak-free API in Newlib.
You could try this as a workaround:  set TZ to something "long," a value that 
you know will not be exceeded by any string you want to try.  Instead of calling 
setenv() to change your value, simply overwrite the value at the pointer 
returned by getenv().  (Certainly improper practice in general, but since you 
have seen the library internals, a valid workaround for the Newlib 
implementation that gets you going now without needing to wait for #2 to be 
addressed.)
> In my particular case, the best thing to do would be to publish a variant of tzset() that takes the time zone string directly, instead of reading it from TZ. My embedded firmware does not really need an environment, and tzset() keeps a private copy of TZ anyway.
>
> Furthermore, I am not sure that _setenv_r() is implemented correctly. Things I have noticed are:
>
> 1) "alloced = 1;" is set before checking whether _malloc_r() fails.
That does seem to be an error, and it should be moved.
> 2) The memory allocated for an environment variable never shrinks, which can lead to great memory waste.
To be more precise, the memory allocated only increases if the variable becomes 
longer.
> 3) I am not sure whether the behaviour is correct if _realloc_r() fails. The code is hard to understand.
It is correct.  (The realloc is only called when a new variable needs to be 
added an existing list.  If adding the name fails, failure is indicated with no 
change having taken place.)
>
> Please copy me on any answers, as I am not subscribed to this mailing list.
>
> Best regards,
>    rdiez

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

* Re: Difficulties with tzset() and setenv()
  2017-07-31 15:56   ` Craig Howland
@ 2017-08-01  6:57     ` R. Diez via newlib
  0 siblings, 0 replies; 3+ messages in thread
From: R. Diez via newlib @ 2017-08-01  6:57 UTC (permalink / raw)
  To: Craig Howland, newlib



> You could try this as a workaround:  set TZ to something
> "long," a value that you know will not be exceeded by
> any string you want to try.  Instead of calling 

> setenv() to change your value, simply overwrite the value
> at the pointer returned by getenv().
> (Certainly improper practice in general, but since
> you have seen the library internals, a valid workaround
> for the Newlib implementation that gets you going
> now without needing to wait for #2 to be addressed.)

It is an interesting work-around, thanks. I am still hoping for a "proper" solution though. 8-)



There is something else I wanted to mention in this mailing list.


Routine _tzset_unlocked_r() does not check whether sscanf() fails at this point:

if (*tzenv == '/')
  sscanf (tzenv, "/%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n);

Other calls to sscanf() in the same routine do check whether sscanf() has failed.

The %hu values captured are checked sometimes, but not in at least 2 sscanf() calls. I wonder if the end-user could trigger in this way an arithmetic overflow and then cause other problems later on. Date/time calculations do not usually involve buffers, so I hope that this lack of bounds checking does not create any security risks down the line.


Unfortunately, I do not have the time to address these issues myself at the moment.


Please copy me on any answers, as I am not subscribed to this mailing list.

Best regards,
  rdiez

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

end of thread, other threads:[~2017-08-01  6:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1022512790.3544807.1501484481626.ref@mail.yahoo.com>
2017-07-31  7:01 ` Difficulties with tzset() and setenv() R. Diez via newlib
2017-07-31 15:56   ` Craig Howland
2017-08-01  6:57     ` R. Diez via newlib

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).