Fix GC bug causing incorrect 'format' output (Bug#75754)
This fixes the correctness bug discovered in bug#75754, but not the performance issue or excessive stack usage. * src/editfns.c (styled_format): Split 'info' array into two arrays, one of them allocated via SAFE_ALLOCA_LISP for GC protection.
This commit is contained in:
parent
990b0811ad
commit
ed5067e689
1 changed files with 13 additions and 12 deletions
|
@ -3431,10 +3431,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
/* Information recorded for each format spec. */
|
||||
struct info
|
||||
{
|
||||
/* The corresponding argument, converted to string if conversion
|
||||
was needed. */
|
||||
Lisp_Object argument;
|
||||
|
||||
/* The start and end bytepos in the output string. */
|
||||
ptrdiff_t start, end;
|
||||
|
||||
|
@ -3461,6 +3457,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
|| SIZE_MAX < alloca_size)
|
||||
memory_full (SIZE_MAX);
|
||||
info = SAFE_ALLOCA (alloca_size);
|
||||
/* One argument belonging to each spec; but needs to be allocated
|
||||
separately so GC doesn't free the strings (bug#75754). */
|
||||
Lisp_Object *spec_arguments;
|
||||
SAFE_ALLOCA_LISP (spec_arguments, nspec_bound);
|
||||
/* discarded[I] is 1 if byte I of the format
|
||||
string was not copied into the output.
|
||||
It is 2 if byte I was not the first byte of its character. */
|
||||
|
@ -3610,14 +3610,15 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
if (! (n < nargs))
|
||||
error ("Not enough arguments for format string");
|
||||
|
||||
struct info *spec = &info[ispec++];
|
||||
ptrdiff_t spec_index = ispec++;
|
||||
struct info *spec = &info[spec_index];
|
||||
if (nspec < ispec)
|
||||
{
|
||||
spec->argument = args[n];
|
||||
spec_arguments[spec_index] = args[n];
|
||||
spec->intervals = false;
|
||||
nspec = ispec;
|
||||
}
|
||||
Lisp_Object arg = spec->argument;
|
||||
Lisp_Object arg = spec_arguments[spec_index];
|
||||
|
||||
/* For 'S', prin1 the argument, and then treat like 's'.
|
||||
For 's', princ any argument that is not a string or
|
||||
|
@ -3630,7 +3631,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
if (EQ (arg, args[n]))
|
||||
{
|
||||
Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
|
||||
spec->argument = arg = Fprin1_to_string (arg, noescape, Qnil);
|
||||
spec_arguments[spec_index] = arg = Fprin1_to_string (arg, noescape, Qnil);
|
||||
if (STRING_MULTIBYTE (arg) && ! multibyte)
|
||||
{
|
||||
multibyte = true;
|
||||
|
@ -3648,7 +3649,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
multibyte = true;
|
||||
goto retry;
|
||||
}
|
||||
spec->argument = arg = Fchar_to_string (arg);
|
||||
spec_arguments[spec_index] = arg = Fchar_to_string (arg);
|
||||
}
|
||||
|
||||
if (!EQ (arg, args[n]))
|
||||
|
@ -3658,7 +3659,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
|
||||
if (SYMBOLP (arg))
|
||||
{
|
||||
spec->argument = arg = SYMBOL_NAME (arg);
|
||||
spec_arguments[spec_index] = arg = SYMBOL_NAME (arg);
|
||||
if (STRING_MULTIBYTE (arg) && ! multibyte)
|
||||
{
|
||||
multibyte = true;
|
||||
|
@ -4303,9 +4304,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
|
|||
for (ptrdiff_t i = 0; i < nspec; i++)
|
||||
if (info[i].intervals)
|
||||
{
|
||||
len = make_fixnum (SCHARS (info[i].argument));
|
||||
len = make_fixnum (SCHARS (spec_arguments[i]));
|
||||
Lisp_Object new_len = make_fixnum (info[i].end - info[i].start);
|
||||
props = text_property_list (info[i].argument,
|
||||
props = text_property_list (spec_arguments[i],
|
||||
make_fixnum (0), len, Qnil);
|
||||
props = extend_property_ranges (props, len, new_len);
|
||||
/* If successive arguments have properties, be sure that
|
||||
|
|
Loading…
Add table
Reference in a new issue