Red Hat Bugzilla – Bug 6944
6.1 libtermcap tgetstr() has a bad incompatability problem
Last modified: 2008-05-01 11:37:52 EDT
tgetstr() is documented as taking as one of its arguments a
buffer area where it will place the extracted string entry
(it also returns a pointer to this area as its return value).
In 6.1, tgetstr() does NOT use this area; it appears to
make up its own area and return that instead. This BREAKS
code of the form:
char buf, *bufp = buf;
if (tgetstr(capability, &bufp) != NULL)
tputstr(buf, 1, myputchar);
which is perfectly valid code that is found in some of the
programs we use here.
Worse yet, not even the minor library version has changed.
Worse still, if this area is dynamically allocated (the
info file suggests by implication that it may be), any
programs using tgetstr() repeatedly, even if they work,
are leaking memory -- since they don't expect to need to
free the result, and indeed freeing the result is an error
with the old library.
As a followup note: I have an (obvious) test program to demonstrate
this problem, and to show how it makes valid code print really whacky
garbage. The same test program -- even the same BINARY -- works fine
with the 6.0 libtermcap library. If you want a copy I will attach it
to this bug report.
Which documentation states tgetstr() should accept this? (The man page in
ncurses definitely doesn't).
The changelog of the libtermcap package actually documents the change as a
bugfix, so I believe your code is relying on some other-OS specific function.
"Fixing" it is a matter of removing one patch, so if you can convince me that
it's the right thing to do, it can be done quickly.
See 'info --file=/usr/info/termcap.info.gz' and search for tgetstr().
This is also the historical behavior, as documented in the manpages on
other systems. In fact, this is the behavior specified in the Single
Unix Specification; see the URL:
which says specifically 'If area is not a null pointer and does not point
to a null pointer, tgetstr() copies the string entry into the buffer
pointed to by *area [...]'.
Using this buffer causes problems. The amount that the terminal library
would write is a somewhat undocumented custom; if this ever changes (for
example, if termcap entries get longer), you run the risks of exploding any
program that uses tgetstr, some of which might be running setuid/setgid.
Hence, termcap was changed to ignore the buffer parameter, much as
There are two major problems with the argument that this is better.
First: this change contradicts both the libtermcap documentation for
tgetstr() and its Single Unix Standard specification. Indeed both sets of
documentation tell how to achieve this safety. I don't consider gratuitous
deviations from a standard in the interests of nominal application safety
to be a particularly good thing; what's next, making gets() not work? After
all, it's unsafe too.
Second, and more severe: THIS IS AN INCOMPATABLE ABI CHANGE. The Redhat
6.1 libtermcap.so library does not implement the same ABI that the 6.0
libtermcap.so implements, and does so without even a MINOR version number
change, much less the proper major version number change. This change can,
will, and DOES break applications, such as some we have. No matter how
improved the library is, if it does not have the same ABI it should not
have the same major and minor revision number as the 6.0 libtermcap,
because applications that worked perfectly under 6.0, and were written
in accordance with the available documentation, *BREAK UNDER THE CHANGE*.
If Redhat is going to change the ABI, it should change the major version
number of the library, and it should change the documentation so that people
know what changed.
In the abscence of this, I strongly believe that Redhat has an obligation
to honor the existing ABI: ie, reverse the change and issue an updated shared
library that has the 6.0 ABI.
We've just had another internal discussion about it, and come to the conclusion
that the new behavior is correct and MUCH better security-wise.