Commit
54cd4f045 added some kluges to work around an old glibc bug,
namely that %.*s could misbehave if glibc thought any characters in
the supplied string were incorrectly encoded. Now that we use our
own snprintf.c implementation, we need not worry about that bug (even
if it still exists in the wild). Revert a couple of particularly
ugly hacks, and remove or improve assorted comments.
Note that there can still be encoding-related hazards here: blindly
clipping at a fixed length risks producing wrongly-encoded output
if the clip splits a multibyte character. However, code that's
doing correct multibyte-aware clipping doesn't really need a comment
about that, while code that isn't needs an explanation why not,
rather than a red-herring comment about an obsolete bug.
Discussion: https://postgr.es/m/279428.
1593373684@sss.pgh.pa.us
/*
* Make sure we don't print an unreasonable amount of COPY data in a message.
*
- * It would seem a lot easier to just use the sprintf "precision" limit to
- * truncate the string. However, some versions of glibc have a bug/misfeature
- * that vsnprintf will always fail (return -1) if it is asked to truncate
- * a string that contains invalid byte sequences for the current encoding.
- * So, do our own truncation. We return a pstrdup'd copy of the input.
+ * Returns a pstrdup'd copy of the input.
*/
static char *
limit_printout_length(const char *str)
{
len = pg_mbcliplen(ident, len, NAMEDATALEN - 1);
if (warn)
- {
- /*
- * We avoid using %.*s here because it can misbehave if the data
- * is not valid in what libc thinks is the prevailing encoding.
- */
- char buf[NAMEDATALEN];
-
- memcpy(buf, ident, len);
- buf[len] = '\0';
ereport(NOTICE,
(errcode(ERRCODE_NAME_TOO_LONG),
- errmsg("identifier \"%s\" will be truncated to \"%s\"",
- ident, buf)));
- }
+ errmsg("identifier \"%s\" will be truncated to \"%.*s\"",
+ ident, len, ident)));
ident[len] = '\0';
}
}
prs->state->state = TPS_Base;
#ifdef WPARSER_TRACE
-
- /*
- * Use of %.*s here is a bit risky since it can misbehave if the data is
- * not in what libc thinks is the prevailing encoding. However, since
- * this is just a debugging aid, we choose to live with that.
- */
fprintf(stderr, "parsing \"%.*s\"\n", len, str);
#endif
prs->state->state = TPS_Base;
#ifdef WPARSER_TRACE
- /* See note above about %.*s */
fprintf(stderr, "parsing copy of \"%.*s\"\n", prs->lenstr, prs->str);
#endif
/*
* Note: the uses of %.*s in this function would be risky if the
- * timezone names ever contain non-ASCII characters. However, all
+ * timezone names ever contain non-ASCII characters, since we are
+ * not being careful to do encoding-aware clipping. However, all
* TZ abbreviations in the IANA database are plain ASCII.
*/
if (print_tz)
hentry->counter++;
for (;;)
{
- /*
- * We avoid using %.*s here because it can misbehave
- * if the data is not valid in what libc thinks is the
- * prevailing encoding.
- */
memcpy(modname, refname, refnamelen);
sprintf(modname + refnamelen, "_%d", hentry->counter);
if (strlen(modname) < NAMEDATALEN)
i++;
for (;;)
{
- /*
- * We avoid using %.*s here because it can misbehave if the
- * data is not valid in what libc thinks is the prevailing
- * encoding.
- */
memcpy(modname, colname, colnamelen);
sprintf(modname + colnamelen, "_%d", i);
if (strlen(modname) < NAMEDATALEN)
}
-/*
- * fputnbytes: print exactly N bytes to a file
- *
- * We avoid using %.*s here because it can misbehave if the data
- * is not valid in what libc thinks is the prevailing encoding.
- */
-static void
-fputnbytes(FILE *f, const char *str, size_t n)
-{
- while (n-- > 0)
- fputc(*str++, f);
-}
-
-
static void
print_separator(struct separator sep, FILE *fout)
{
{
/* spaces first */
fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
- fputnbytes(fout,
- (char *) (this_line->ptr + bytes_output[j]),
- bytes_to_output);
+ fwrite((char *) (this_line->ptr + bytes_output[j]),
+ 1, bytes_to_output, fout);
}
else /* Left aligned cell */
{
/* spaces second */
- fputnbytes(fout,
- (char *) (this_line->ptr + bytes_output[j]),
- bytes_to_output);
+ fwrite((char *) (this_line->ptr + bytes_output[j]),
+ 1, bytes_to_output, fout);
}
bytes_output[j] += bytes_to_output;
*/
bytes_to_output = strlen_max_width(dlineptr[dline].ptr + offset,
&target_width, encoding);
- fputnbytes(fout, (char *) (dlineptr[dline].ptr + offset),
- bytes_to_output);
+ fwrite((char *) (dlineptr[dline].ptr + offset),
+ 1, bytes_to_output, fout);
chars_to_output -= target_width;
offset += bytes_to_output;
else
sqlca->sqlcode = ECPG_PGSQL;
- /* %.*s is safe here as long as sqlstate is all-ASCII */
ecpg_log("raising sqlstate %.*s (sqlcode %ld): %s\n",
(int) sizeof(sqlca->sqlstate), sqlca->sqlstate, sqlca->sqlcode, sqlca->sqlerrm.sqlerrmc);
/*
* Note: the uses of %.*s in this function would be risky if the
- * timezone names ever contain non-ASCII characters. However, all
+ * timezone names ever contain non-ASCII characters, since we are
+ * not being careful to do encoding-aware clipping. However, all
* TZ abbreviations in the IANA database are plain ASCII.
*/
return PG_VERSION_NUM;
}
-/*
- * fputnbytes: print exactly N bytes to a file
- *
- * We avoid using %.*s here because it can misbehave if the data
- * is not valid in what libc thinks is the prevailing encoding.
- */
-static void
-fputnbytes(FILE *f, const char *str, size_t n)
-{
- while (n-- > 0)
- fputc(*str++, f);
-}
-
/*
* pqGetc: get 1 character from the connection
if (conn->Pfdebug)
{
fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
- fputnbytes(conn->Pfdebug, s, len);
+ fwrite(s, 1, len, conn->Pfdebug);
fprintf(conn->Pfdebug, "\n");
}
if (conn->Pfdebug)
{
fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
- fputnbytes(conn->Pfdebug, conn->inBuffer + conn->inCursor, len);
+ fwrite(conn->inBuffer + conn->inCursor, 1, len, conn->Pfdebug);
fprintf(conn->Pfdebug, "\n");
}
if (conn->Pfdebug)
{
fprintf(conn->Pfdebug, "To backend> ");
- fputnbytes(conn->Pfdebug, s, len);
+ fwrite(s, 1, len, conn->Pfdebug);
fprintf(conn->Pfdebug, "\n");
}