This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Difficulties with tzset() and setenv()


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]