diff options
| author | Paul Eggert | 2016-12-08 11:32:48 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-12-08 13:00:32 -0800 |
| commit | f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1 (patch) | |
| tree | d4d752498b6da8154e6d3cf8dfed94643ae67614 /src | |
| parent | 162ba405ac144c2a0cb6854f791ff7d3203b0e2f (diff) | |
| download | emacs-f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1.tar.gz emacs-f0a1e9ec3fba3d5bea5bd62f525dba3fb005d1b1.zip | |
Make read1 more reentrant
This is needed if ‘read’ is called soon after startup, before the
Unicode tables have been set up, and it reads a \N escape and
needs to look up a value the Unicode tables, a lookup that in turn
calls read1 recursively. Although this change doesn’t make ‘read’
fully reentrant, it’s good enough to handle this case.
* src/lread.c (read_buffer_size, read_buffer): Remove static vars.
(grow_read_buffer): Revamp to use locals, not statics, and to
record memory allocation un the specpdl. All callers changed.
(read1): Start with a stack-based buffer, and use the heap
only if the stack buffer is too small. Use unbind_to to
free any heap buffer allocated. Use bool for boolean.
Redo symbol loop so that only one call to grow_read_buffer
is needed.
(init_obarray): Remove no-longer-needed initialization.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lread.c | 203 |
1 files changed, 106 insertions, 97 deletions
diff --git a/src/lread.c b/src/lread.c index 1335ccfea78..157a392a158 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -2144,16 +2144,28 @@ read0 (Lisp_Object readcharfun) | |||
| 2144 | Fmake_string (make_number (1), make_number (c))); | 2144 | Fmake_string (make_number (1), make_number (c))); |
| 2145 | } | 2145 | } |
| 2146 | 2146 | ||
| 2147 | static ptrdiff_t read_buffer_size; | 2147 | /* Grow a read buffer BUF that contains OFFSET useful bytes of data, |
| 2148 | static char *read_buffer; | 2148 | by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and |
| 2149 | 2149 | *BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is | |
| 2150 | /* Grow the read buffer by at least MAX_MULTIBYTE_LENGTH bytes. */ | 2150 | initially null, BUF is on the stack: copy its data to the new heap |
| 2151 | 2151 | buffer. Otherwise, BUF must equal *BUF_ADDR and can simply be | |
| 2152 | static void | 2152 | reallocated. Either way, remember the heap allocation (which is at |
| 2153 | grow_read_buffer (void) | 2153 | pdl slot COUNT) so that it can be freed when unwinding the stack.*/ |
| 2154 | |||
| 2155 | static char * | ||
| 2156 | grow_read_buffer (char *buf, ptrdiff_t offset, | ||
| 2157 | char **buf_addr, ptrdiff_t *buf_size, ptrdiff_t count) | ||
| 2154 | { | 2158 | { |
| 2155 | read_buffer = xpalloc (read_buffer, &read_buffer_size, | 2159 | char *p = xpalloc (*buf_addr, buf_size, MAX_MULTIBYTE_LENGTH, -1, 1); |
| 2156 | MAX_MULTIBYTE_LENGTH, -1, 1); | 2160 | if (!*buf_addr) |
| 2161 | { | ||
| 2162 | memcpy (p, buf, offset); | ||
| 2163 | record_unwind_protect_ptr (xfree, p); | ||
| 2164 | } | ||
| 2165 | else | ||
| 2166 | set_unwind_protect_ptr (count, xfree, p); | ||
| 2167 | *buf_addr = p; | ||
| 2168 | return p; | ||
| 2157 | } | 2169 | } |
| 2158 | 2170 | ||
| 2159 | /* Return the scalar value that has the Unicode character name NAME. | 2171 | /* Return the scalar value that has the Unicode character name NAME. |
| @@ -2432,6 +2444,9 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2432 | if (length == 0) | 2444 | if (length == 0) |
| 2433 | invalid_syntax ("Empty character name"); | 2445 | invalid_syntax ("Empty character name"); |
| 2434 | name[length] = '\0'; | 2446 | name[length] = '\0'; |
| 2447 | |||
| 2448 | /* character_name_to_code can invoke read1, recursively. | ||
| 2449 | This is why read1's buffer is not static. */ | ||
| 2435 | return character_name_to_code (name, length); | 2450 | return character_name_to_code (name, length); |
| 2436 | } | 2451 | } |
| 2437 | 2452 | ||
| @@ -2541,8 +2556,9 @@ static Lisp_Object | |||
| 2541 | read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | 2556 | read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) |
| 2542 | { | 2557 | { |
| 2543 | int c; | 2558 | int c; |
| 2544 | bool uninterned_symbol = 0; | 2559 | bool uninterned_symbol = false; |
| 2545 | bool multibyte; | 2560 | bool multibyte; |
| 2561 | char stackbuf[MAX_ALLOCA]; | ||
| 2546 | 2562 | ||
| 2547 | *pch = 0; | 2563 | *pch = 0; |
| 2548 | 2564 | ||
| @@ -2873,7 +2889,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2873 | /* #:foo is the uninterned symbol named foo. */ | 2889 | /* #:foo is the uninterned symbol named foo. */ |
| 2874 | if (c == ':') | 2890 | if (c == ':') |
| 2875 | { | 2891 | { |
| 2876 | uninterned_symbol = 1; | 2892 | uninterned_symbol = true; |
| 2877 | c = READCHAR; | 2893 | c = READCHAR; |
| 2878 | if (!(c > 040 | 2894 | if (!(c > 040 |
| 2879 | && c != NO_BREAK_SPACE | 2895 | && c != NO_BREAK_SPACE |
| @@ -3084,16 +3100,20 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3084 | 3100 | ||
| 3085 | case '"': | 3101 | case '"': |
| 3086 | { | 3102 | { |
| 3103 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 3104 | char *read_buffer = stackbuf; | ||
| 3105 | ptrdiff_t read_buffer_size = sizeof stackbuf; | ||
| 3106 | char *heapbuf = NULL; | ||
| 3087 | char *p = read_buffer; | 3107 | char *p = read_buffer; |
| 3088 | char *end = read_buffer + read_buffer_size; | 3108 | char *end = read_buffer + read_buffer_size; |
| 3089 | int ch; | 3109 | int ch; |
| 3090 | /* True if we saw an escape sequence specifying | 3110 | /* True if we saw an escape sequence specifying |
| 3091 | a multibyte character. */ | 3111 | a multibyte character. */ |
| 3092 | bool force_multibyte = 0; | 3112 | bool force_multibyte = false; |
| 3093 | /* True if we saw an escape sequence specifying | 3113 | /* True if we saw an escape sequence specifying |
| 3094 | a single-byte character. */ | 3114 | a single-byte character. */ |
| 3095 | bool force_singlebyte = 0; | 3115 | bool force_singlebyte = false; |
| 3096 | bool cancel = 0; | 3116 | bool cancel = false; |
| 3097 | ptrdiff_t nchars = 0; | 3117 | ptrdiff_t nchars = 0; |
| 3098 | 3118 | ||
| 3099 | while ((ch = READCHAR) >= 0 | 3119 | while ((ch = READCHAR) >= 0 |
| @@ -3102,7 +3122,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3102 | if (end - p < MAX_MULTIBYTE_LENGTH) | 3122 | if (end - p < MAX_MULTIBYTE_LENGTH) |
| 3103 | { | 3123 | { |
| 3104 | ptrdiff_t offset = p - read_buffer; | 3124 | ptrdiff_t offset = p - read_buffer; |
| 3105 | grow_read_buffer (); | 3125 | read_buffer = grow_read_buffer (read_buffer, offset, |
| 3126 | &heapbuf, &read_buffer_size, | ||
| 3127 | count); | ||
| 3106 | p = read_buffer + offset; | 3128 | p = read_buffer + offset; |
| 3107 | end = read_buffer + read_buffer_size; | 3129 | end = read_buffer + read_buffer_size; |
| 3108 | } | 3130 | } |
| @@ -3117,7 +3139,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3117 | if (ch == -1) | 3139 | if (ch == -1) |
| 3118 | { | 3140 | { |
| 3119 | if (p == read_buffer) | 3141 | if (p == read_buffer) |
| 3120 | cancel = 1; | 3142 | cancel = true; |
| 3121 | continue; | 3143 | continue; |
| 3122 | } | 3144 | } |
| 3123 | 3145 | ||
| @@ -3125,9 +3147,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3125 | ch = ch & ~CHAR_MODIFIER_MASK; | 3147 | ch = ch & ~CHAR_MODIFIER_MASK; |
| 3126 | 3148 | ||
| 3127 | if (CHAR_BYTE8_P (ch)) | 3149 | if (CHAR_BYTE8_P (ch)) |
| 3128 | force_singlebyte = 1; | 3150 | force_singlebyte = true; |
| 3129 | else if (! ASCII_CHAR_P (ch)) | 3151 | else if (! ASCII_CHAR_P (ch)) |
| 3130 | force_multibyte = 1; | 3152 | force_multibyte = true; |
| 3131 | else /* I.e. ASCII_CHAR_P (ch). */ | 3153 | else /* I.e. ASCII_CHAR_P (ch). */ |
| 3132 | { | 3154 | { |
| 3133 | /* Allow `\C- ' and `\C-?'. */ | 3155 | /* Allow `\C- ' and `\C-?'. */ |
| @@ -3153,7 +3175,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3153 | string. */ | 3175 | string. */ |
| 3154 | modifiers &= ~CHAR_META; | 3176 | modifiers &= ~CHAR_META; |
| 3155 | ch = BYTE8_TO_CHAR (ch | 0x80); | 3177 | ch = BYTE8_TO_CHAR (ch | 0x80); |
| 3156 | force_singlebyte = 1; | 3178 | force_singlebyte = true; |
| 3157 | } | 3179 | } |
| 3158 | } | 3180 | } |
| 3159 | 3181 | ||
| @@ -3166,9 +3188,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3166 | { | 3188 | { |
| 3167 | p += CHAR_STRING (ch, (unsigned char *) p); | 3189 | p += CHAR_STRING (ch, (unsigned char *) p); |
| 3168 | if (CHAR_BYTE8_P (ch)) | 3190 | if (CHAR_BYTE8_P (ch)) |
| 3169 | force_singlebyte = 1; | 3191 | force_singlebyte = true; |
| 3170 | else if (! ASCII_CHAR_P (ch)) | 3192 | else if (! ASCII_CHAR_P (ch)) |
| 3171 | force_multibyte = 1; | 3193 | force_multibyte = true; |
| 3172 | } | 3194 | } |
| 3173 | nchars++; | 3195 | nchars++; |
| 3174 | } | 3196 | } |
| @@ -3180,7 +3202,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3180 | return zero instead. This is for doc strings | 3202 | return zero instead. This is for doc strings |
| 3181 | that we are really going to find in etc/DOC.nn.nn. */ | 3203 | that we are really going to find in etc/DOC.nn.nn. */ |
| 3182 | if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel) | 3204 | if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel) |
| 3183 | return make_number (0); | 3205 | return unbind_to (count, make_number (0)); |
| 3184 | 3206 | ||
| 3185 | if (! force_multibyte && force_singlebyte) | 3207 | if (! force_multibyte && force_singlebyte) |
| 3186 | { | 3208 | { |
| @@ -3191,9 +3213,11 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3191 | p = read_buffer + nchars; | 3213 | p = read_buffer + nchars; |
| 3192 | } | 3214 | } |
| 3193 | 3215 | ||
| 3194 | return make_specified_string (read_buffer, nchars, p - read_buffer, | 3216 | Lisp_Object result |
| 3195 | (force_multibyte | 3217 | = make_specified_string (read_buffer, nchars, p - read_buffer, |
| 3196 | || (p - read_buffer != nchars))); | 3218 | (force_multibyte |
| 3219 | || (p - read_buffer != nchars))); | ||
| 3220 | return unbind_to (count, result); | ||
| 3197 | } | 3221 | } |
| 3198 | 3222 | ||
| 3199 | case '.': | 3223 | case '.': |
| @@ -3221,81 +3245,74 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3221 | 3245 | ||
| 3222 | read_symbol: | 3246 | read_symbol: |
| 3223 | { | 3247 | { |
| 3248 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 3249 | char *read_buffer = stackbuf; | ||
| 3250 | ptrdiff_t read_buffer_size = sizeof stackbuf; | ||
| 3251 | char *heapbuf = NULL; | ||
| 3224 | char *p = read_buffer; | 3252 | char *p = read_buffer; |
| 3225 | bool quoted = 0; | 3253 | char *end = read_buffer + read_buffer_size; |
| 3254 | bool quoted = false; | ||
| 3226 | EMACS_INT start_position = readchar_count - 1; | 3255 | EMACS_INT start_position = readchar_count - 1; |
| 3227 | 3256 | ||
| 3228 | { | 3257 | do |
| 3229 | char *end = read_buffer + read_buffer_size; | 3258 | { |
| 3230 | 3259 | if (end - p < MAX_MULTIBYTE_LENGTH + 1) | |
| 3231 | do | 3260 | { |
| 3232 | { | 3261 | ptrdiff_t offset = p - read_buffer; |
| 3233 | if (end - p < MAX_MULTIBYTE_LENGTH) | 3262 | read_buffer = grow_read_buffer (read_buffer, offset, |
| 3234 | { | 3263 | &heapbuf, &read_buffer_size, |
| 3235 | ptrdiff_t offset = p - read_buffer; | 3264 | count); |
| 3236 | grow_read_buffer (); | 3265 | p = read_buffer + offset; |
| 3237 | p = read_buffer + offset; | 3266 | end = read_buffer + read_buffer_size; |
| 3238 | end = read_buffer + read_buffer_size; | 3267 | } |
| 3239 | } | ||
| 3240 | 3268 | ||
| 3241 | if (c == '\\') | 3269 | if (c == '\\') |
| 3242 | { | 3270 | { |
| 3243 | c = READCHAR; | 3271 | c = READCHAR; |
| 3244 | if (c == -1) | 3272 | if (c == -1) |
| 3245 | end_of_file_error (); | 3273 | end_of_file_error (); |
| 3246 | quoted = 1; | 3274 | quoted = true; |
| 3247 | } | 3275 | } |
| 3248 | 3276 | ||
| 3249 | if (multibyte) | 3277 | if (multibyte) |
| 3250 | p += CHAR_STRING (c, (unsigned char *) p); | 3278 | p += CHAR_STRING (c, (unsigned char *) p); |
| 3251 | else | 3279 | else |
| 3252 | *p++ = c; | 3280 | *p++ = c; |
| 3253 | c = READCHAR; | 3281 | c = READCHAR; |
| 3254 | } | 3282 | } |
| 3255 | while (c > 040 | 3283 | while (c > 040 |
| 3256 | && c != NO_BREAK_SPACE | 3284 | && c != NO_BREAK_SPACE |
| 3257 | && (c >= 0200 | 3285 | && (c >= 0200 |
| 3258 | || strchr ("\"';()[]#`,", c) == NULL)); | 3286 | || strchr ("\"';()[]#`,", c) == NULL)); |
| 3259 | 3287 | ||
| 3260 | if (p == end) | 3288 | *p = 0; |
| 3261 | { | 3289 | UNREAD (c); |
| 3262 | ptrdiff_t offset = p - read_buffer; | ||
| 3263 | grow_read_buffer (); | ||
| 3264 | p = read_buffer + offset; | ||
| 3265 | end = read_buffer + read_buffer_size; | ||
| 3266 | } | ||
| 3267 | *p = 0; | ||
| 3268 | UNREAD (c); | ||
| 3269 | } | ||
| 3270 | 3290 | ||
| 3271 | if (!quoted && !uninterned_symbol) | 3291 | if (!quoted && !uninterned_symbol) |
| 3272 | { | 3292 | { |
| 3273 | Lisp_Object result = string_to_number (read_buffer, 10, 0); | 3293 | Lisp_Object result = string_to_number (read_buffer, 10, 0); |
| 3274 | if (! NILP (result)) | 3294 | if (! NILP (result)) |
| 3275 | return result; | 3295 | return unbind_to (count, result); |
| 3276 | } | 3296 | } |
| 3277 | { | 3297 | |
| 3278 | Lisp_Object name, result; | 3298 | ptrdiff_t nbytes = p - read_buffer; |
| 3279 | ptrdiff_t nbytes = p - read_buffer; | 3299 | ptrdiff_t nchars |
| 3280 | ptrdiff_t nchars | 3300 | = (multibyte |
| 3281 | = (multibyte | 3301 | ? multibyte_chars_in_text ((unsigned char *) read_buffer, |
| 3282 | ? multibyte_chars_in_text ((unsigned char *) read_buffer, | 3302 | nbytes) |
| 3283 | nbytes) | 3303 | : nbytes); |
| 3284 | : nbytes); | 3304 | Lisp_Object name = ((uninterned_symbol && ! NILP (Vpurify_flag) |
| 3285 | 3305 | ? make_pure_string : make_specified_string) | |
| 3286 | name = ((uninterned_symbol && ! NILP (Vpurify_flag) | 3306 | (read_buffer, nchars, nbytes, multibyte)); |
| 3287 | ? make_pure_string : make_specified_string) | 3307 | Lisp_Object result = (uninterned_symbol ? Fmake_symbol (name) |
| 3288 | (read_buffer, nchars, nbytes, multibyte)); | 3308 | : Fintern (name, Qnil)); |
| 3289 | result = (uninterned_symbol ? Fmake_symbol (name) | 3309 | |
| 3290 | : Fintern (name, Qnil)); | 3310 | if (EQ (Vread_with_symbol_positions, Qt) |
| 3291 | 3311 | || EQ (Vread_with_symbol_positions, readcharfun)) | |
| 3292 | if (EQ (Vread_with_symbol_positions, Qt) | 3312 | Vread_symbol_positions_list |
| 3293 | || EQ (Vread_with_symbol_positions, readcharfun)) | 3313 | = Fcons (Fcons (result, make_number (start_position)), |
| 3294 | Vread_symbol_positions_list | 3314 | Vread_symbol_positions_list); |
| 3295 | = Fcons (Fcons (result, make_number (start_position)), | 3315 | return unbind_to (count, result); |
| 3296 | Vread_symbol_positions_list); | ||
| 3297 | return result; | ||
| 3298 | } | ||
| 3299 | } | 3316 | } |
| 3300 | } | 3317 | } |
| 3301 | } | 3318 | } |
| @@ -4104,12 +4121,7 @@ OBARRAY defaults to the value of `obarray'. */) | |||
| 4104 | void | 4121 | void |
| 4105 | init_obarray (void) | 4122 | init_obarray (void) |
| 4106 | { | 4123 | { |
| 4107 | Lisp_Object oblength; | 4124 | Vobarray = Fmake_vector (make_number (OBARRAY_SIZE), make_number (0)); |
| 4108 | ptrdiff_t size = 100 + MAX_MULTIBYTE_LENGTH; | ||
| 4109 | |||
| 4110 | XSETFASTINT (oblength, OBARRAY_SIZE); | ||
| 4111 | |||
| 4112 | Vobarray = Fmake_vector (oblength, make_number (0)); | ||
| 4113 | initial_obarray = Vobarray; | 4125 | initial_obarray = Vobarray; |
| 4114 | staticpro (&initial_obarray); | 4126 | staticpro (&initial_obarray); |
| 4115 | 4127 | ||
| @@ -4132,9 +4144,6 @@ init_obarray (void) | |||
| 4132 | Vpurify_flag = Qt; | 4144 | Vpurify_flag = Qt; |
| 4133 | 4145 | ||
| 4134 | DEFSYM (Qvariable_documentation, "variable-documentation"); | 4146 | DEFSYM (Qvariable_documentation, "variable-documentation"); |
| 4135 | |||
| 4136 | read_buffer = xmalloc (size); | ||
| 4137 | read_buffer_size = size; | ||
| 4138 | } | 4147 | } |
| 4139 | 4148 | ||
| 4140 | void | 4149 | void |