diff options
| author | Mattias EngdegÄrd | 2024-05-02 18:05:21 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2025-08-24 10:28:27 +0200 |
| commit | 308e3ab1dbd9633b843541af55d77c82b725df02 (patch) | |
| tree | 7036ce2267ad670d95e1b2702f4554e97395e233 /src/alloc.c | |
| parent | 230ed1f9b6da42515735970c370424c37bda5d59 (diff) | |
| download | emacs-308e3ab1dbd9633b843541af55d77c82b725df02.tar.gz emacs-308e3ab1dbd9633b843541af55d77c82b725df02.zip | |
Disallow string data resizing (bug#79784)
Only allow string mutation that is certain not to require string data to
be resized and reallocated: writing bytes into a unibyte string, and
changing ASCII to ASCII in a multibyte string.
This ensures that mutation will never transform a unibyte string to
multibyte, that the size of a string in bytes never changes, and that
the byte offsets of characters remain the same. Most importantly, it
removes a long-standing obstacle to reform of string representation and
allow for future performance improvements.
* src/data.c (Faset): Disallow resizing string mutation.
* src/fns.c (clear_string_char_byte_cache):
* src/alloc.c (resize_string_data): Remove.
* test/src/data-tests.el (data-aset-string): New test.
* test/lisp/subr-tests.el (subr--subst-char-in-string):
Skip error cases.
* test/src/alloc-tests.el (aset-nbytes-change):
Remove test that is no longer relevant.
* doc/lispref/strings.texi (Modifying Strings):
* doc/lispref/sequences.texi (Array Functions):
* doc/lispref/text.texi (Substitution): Update manual.
* etc/NEWS: Announce.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 50 |
1 files changed, 0 insertions, 50 deletions
diff --git a/src/alloc.c b/src/alloc.c index 07ca8474bf3..9ace6f01856 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -1815,56 +1815,6 @@ allocate_string_data (struct Lisp_String *s, | |||
| 1815 | tally_consing (needed); | 1815 | tally_consing (needed); |
| 1816 | } | 1816 | } |
| 1817 | 1817 | ||
| 1818 | /* Reallocate multibyte STRING data when a single character is replaced. | ||
| 1819 | The character is at byte offset CIDX_BYTE in the string. | ||
| 1820 | The character being replaced is CLEN bytes long, | ||
| 1821 | and the character that will replace it is NEW_CLEN bytes long. | ||
| 1822 | Return the address where the caller should store the new character. */ | ||
| 1823 | |||
| 1824 | unsigned char * | ||
| 1825 | resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte, | ||
| 1826 | int clen, int new_clen) | ||
| 1827 | { | ||
| 1828 | eassume (STRING_MULTIBYTE (string)); | ||
| 1829 | sdata *old_sdata = SDATA_OF_STRING (XSTRING (string)); | ||
| 1830 | ptrdiff_t nchars = SCHARS (string); | ||
| 1831 | ptrdiff_t nbytes = SBYTES (string); | ||
| 1832 | ptrdiff_t new_nbytes = nbytes + (new_clen - clen); | ||
| 1833 | unsigned char *data = SDATA (string); | ||
| 1834 | unsigned char *new_charaddr; | ||
| 1835 | |||
| 1836 | if (sdata_size (nbytes) == sdata_size (new_nbytes)) | ||
| 1837 | { | ||
| 1838 | /* No need to reallocate, as the size change falls within the | ||
| 1839 | alignment slop. */ | ||
| 1840 | XSTRING (string)->u.s.size_byte = new_nbytes; | ||
| 1841 | #ifdef GC_CHECK_STRING_BYTES | ||
| 1842 | SDATA_NBYTES (old_sdata) = new_nbytes; | ||
| 1843 | #endif | ||
| 1844 | new_charaddr = data + cidx_byte; | ||
| 1845 | memmove (new_charaddr + new_clen, new_charaddr + clen, | ||
| 1846 | nbytes - (cidx_byte + (clen - 1))); | ||
| 1847 | } | ||
| 1848 | else | ||
| 1849 | { | ||
| 1850 | allocate_string_data (XSTRING (string), nchars, new_nbytes, false, false); | ||
| 1851 | unsigned char *new_data = SDATA (string); | ||
| 1852 | new_charaddr = new_data + cidx_byte; | ||
| 1853 | memcpy (new_charaddr + new_clen, data + cidx_byte + clen, | ||
| 1854 | nbytes - (cidx_byte + clen)); | ||
| 1855 | memcpy (new_data, data, cidx_byte); | ||
| 1856 | |||
| 1857 | /* Mark old string data as free by setting its string back-pointer | ||
| 1858 | to null, and record the size of the data in it. */ | ||
| 1859 | SDATA_NBYTES (old_sdata) = nbytes; | ||
| 1860 | old_sdata->string = NULL; | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | clear_string_char_byte_cache (); | ||
| 1864 | |||
| 1865 | return new_charaddr; | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | 1818 | ||
| 1869 | /* Sweep and compact strings. */ | 1819 | /* Sweep and compact strings. */ |
| 1870 | 1820 | ||