This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Re: Difficulties with tzset() and setenv()
- From: Craig Howland <howland at LGSInnovations dot com>
- To: "R. Diez" <rdiezmail-newlib at yahoo dot de>, "newlib at sourceware dot org" <newlib at sourceware dot org>
- Date: Mon, 31 Jul 2017 11:56:39 -0400
- Subject: Re: Difficulties with tzset() and setenv()
- Authentication-results: sourceware.org; auth=none
- References: <1022512790.3544807.1501484481626.ref@mail.yahoo.com> <1022512790.3544807.1501484481626@mail.yahoo.com>
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