Clean up dubious code in contrib/seg.

The restore() function assumed that the result of sprintf() with %e format
would necessarily contain an 'e', which is false: what if the supplied
number is an infinity or NaN?  If that did happen, we'd get a
null-pointer-dereference core dump.  The case appears impossible currently,
because seg_in() does not accept such values, and there are no seg-creating
functions that would create one.  But it seems unwise to rely on it never
happening in future.

Quite aside from that, the code was pretty ugly: it relied on modifying a
static format string when it could use a "*" precision argument, and it
used strtok() entirely gratuitously, and it stripped off trailing spaces
by hand instead of just not asking for them to begin with.

Coverity noticed the potential null pointer dereference (though I wonder
why it didn't complain years ago, since this code is ancient).

Since this is just code cleanup and forestalling a hypothetical future
bug, there seems no need for back-patching.
This commit is contained in:
Tom Lane 2016-04-03 17:36:53 -04:00
parent 8f75fd1f40
commit a75a418d07
1 changed files with 19 additions and 19 deletions

View File

@ -833,15 +833,18 @@ seg_different(SEG *a, SEG *b)
* Auxiliary functions
*****************************************************************************/
/* The purpose of this routine is to print the floating point
* value with exact number of significant digits. Its behaviour
/*
* The purpose of this routine is to print the given floating point
* value with exactly n significant digits. Its behaviour
* is similar to %.ng except it prints 8.00 where %.ng would
* print 8
* print 8. Returns the length of the string written at "result".
*
* Caller must provide a sufficiently large result buffer; 16 bytes
* should be enough for all known float implementations.
*/
static int
restore(char *result, float val, int n)
{
static char efmt[8] = {'%', '-', '1', '5', '.', '#', 'e', 0};
char buf[25] = {
'0', '0', '0', '0', '0',
'0', '0', '0', '0', '0',
@ -856,32 +859,29 @@ restore(char *result, float val, int n)
sign;
/*
* put a cap on the number of siugnificant digits to avoid nonsense in the
* output
* Put a cap on the number of significant digits to avoid garbage in the
* output and ensure we don't overrun the result buffer.
*/
n = Min(n, FLT_DIG);
/* remember the sign */
sign = (val < 0 ? 1 : 0);
efmt[5] = '0' + (n - 1) % 10; /* makes %-15.(n-1)e -- this format
* guarantees that the exponent is
* always present */
/* print, in %e style to start with */
sprintf(result, "%.*e", n - 1, val);
sprintf(result, efmt, val);
/* find the exponent */
p = strchr(result, 'e');
/* trim the spaces left by the %e */
for (p = result; *p != ' '; p++);
*p = '\0';
/* get the exponent */
strtok(pstrdup(result), "e");
exp = atoi(strtok(NULL, "e"));
/* punt if we have 'inf' or similar */
if (p == NULL)
return strlen(result);
exp = atoi(p + 1);
if (exp == 0)
{
/* use the supplied mantyssa with sign */
strcpy((char *) strchr(result, 'e'), "");
/* just truncate off the 'e+00' */
*p = '\0';
}
else
{