diff options
| author | Dmitry Antipov | 2013-01-18 10:32:12 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2013-01-18 10:32:12 +0400 |
| commit | e07469fa51b2955391255f54917ffb34efd66f1f (patch) | |
| tree | c1d5d48ed06bb7c11b5ad1fc06229e92d1e50ada /src | |
| parent | 6772211202c57f0dc96e5725f882a2fa4ee98d2d (diff) | |
| download | emacs-e07469fa51b2955391255f54917ffb34efd66f1f.tar.gz emacs-e07469fa51b2955391255f54917ffb34efd66f1f.zip | |
Fix crash when inserting data from non-regular files. See
http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00406.html
for the error description produced by valgrind.
* fileio.c (read_non_regular): Rename to read_contents.
Free Lisp_Save_Value object used to pass parameters.
(read_non_regular_quit): Rename to read_contents_quit.
(Finsert_file_contents): Redesign internal file reading loop to adjust
gap and end positions after each read and so help make_gap to work
properly. Do not signal an I/O error too early and so do not leave
not yet decoded characters in a buffer, which was the reason of
redisplay crash. Use list2 to build return value. Adjust comments.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 14 | ||||
| -rw-r--r-- | src/fileio.c | 174 |
2 files changed, 86 insertions, 102 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index f53b9a70e97..a7b8ab7855b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,17 @@ | |||
| 1 | 2013-01-18 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | Fix crash when inserting data from non-regular files. See | ||
| 4 | http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00406.html | ||
| 5 | for the error description produced by valgrind. | ||
| 6 | * fileio.c (read_non_regular): Rename to read_contents. | ||
| 7 | Free Lisp_Save_Value object used to pass parameters. | ||
| 8 | (read_non_regular_quit): Rename to read_contents_quit. | ||
| 9 | (Finsert_file_contents): Redesign internal file reading loop to adjust | ||
| 10 | gap and end positions after each read and so help make_gap to work | ||
| 11 | properly. Do not signal an I/O error too early and so do not leave | ||
| 12 | not yet decoded characters in a buffer, which was the reason of | ||
| 13 | redisplay crash. Use list2 to build return value. Adjust comments. | ||
| 14 | |||
| 1 | 2013-01-17 Paul Eggert <eggert@cs.ucla.edu> | 15 | 2013-01-17 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 16 | ||
| 3 | Close a race when statting and reading files (Bug#13149). | 17 | Close a race when statting and reading files (Bug#13149). |
diff --git a/src/fileio.c b/src/fileio.c index 41b8ae388d1..4c54fd822ae 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -3408,13 +3408,13 @@ decide_coding_unwind (Lisp_Object unwind_data) | |||
| 3408 | return Qnil; | 3408 | return Qnil; |
| 3409 | } | 3409 | } |
| 3410 | 3410 | ||
| 3411 | /* Read from a non-regular file. STATE is a Lisp_Save_Value | 3411 | /* Check quit and read from the file. STATE is a Lisp_Save_Value |
| 3412 | object where slot 0 is the file descriptor, slot 1 specifies | 3412 | object where slot 0 is the file descriptor, slot 1 specifies |
| 3413 | an offset to put the read bytes, and slot 2 is the maximum | 3413 | an offset to put the read bytes, and slot 2 is the maximum |
| 3414 | amount of bytes to read. Value is the number of bytes read. */ | 3414 | amount of bytes to read. Value is the number of bytes read. */ |
| 3415 | 3415 | ||
| 3416 | static Lisp_Object | 3416 | static Lisp_Object |
| 3417 | read_non_regular (Lisp_Object state) | 3417 | read_contents (Lisp_Object state) |
| 3418 | { | 3418 | { |
| 3419 | int nbytes; | 3419 | int nbytes; |
| 3420 | 3420 | ||
| @@ -3425,15 +3425,15 @@ read_non_regular (Lisp_Object state) | |||
| 3425 | + XSAVE_INTEGER (state, 1)), | 3425 | + XSAVE_INTEGER (state, 1)), |
| 3426 | XSAVE_INTEGER (state, 2)); | 3426 | XSAVE_INTEGER (state, 2)); |
| 3427 | immediate_quit = 0; | 3427 | immediate_quit = 0; |
| 3428 | /* Fast recycle this object for the likely next call. */ | ||
| 3429 | free_misc (state); | ||
| 3428 | return make_number (nbytes); | 3430 | return make_number (nbytes); |
| 3429 | } | 3431 | } |
| 3430 | 3432 | ||
| 3431 | 3433 | /* Condition-case handler used when reading files in insert-file-contents. */ | |
| 3432 | /* Condition-case handler used when reading from non-regular files | ||
| 3433 | in insert-file-contents. */ | ||
| 3434 | 3434 | ||
| 3435 | static Lisp_Object | 3435 | static Lisp_Object |
| 3436 | read_non_regular_quit (Lisp_Object ignore) | 3436 | read_contents_quit (Lisp_Object ignore) |
| 3437 | { | 3437 | { |
| 3438 | return Qnil; | 3438 | return Qnil; |
| 3439 | } | 3439 | } |
| @@ -3505,7 +3505,7 @@ by calling `format-decode', which see. */) | |||
| 3505 | Lisp_Object p; | 3505 | Lisp_Object p; |
| 3506 | ptrdiff_t total = 0; | 3506 | ptrdiff_t total = 0; |
| 3507 | bool not_regular = 0; | 3507 | bool not_regular = 0; |
| 3508 | int save_errno = 0; | 3508 | int save_errno = 0, read_errno = 0; |
| 3509 | char read_buf[READ_BUF_SIZE]; | 3509 | char read_buf[READ_BUF_SIZE]; |
| 3510 | struct coding_system coding; | 3510 | struct coding_system coding; |
| 3511 | char buffer[1 << 14]; | 3511 | char buffer[1 << 14]; |
| @@ -4195,88 +4195,72 @@ by calling `format-decode', which see. */) | |||
| 4195 | Fcons (orig_filename, Qnil)); | 4195 | Fcons (orig_filename, Qnil)); |
| 4196 | } | 4196 | } |
| 4197 | 4197 | ||
| 4198 | /* In the following loop, HOW_MUCH contains the total bytes read so | 4198 | /* In the following loop, HOW_MUCH contains the total bytes read |
| 4199 | far for a regular file, and not changed for a special file. But, | 4199 | so far for a regular file, and not changed for a special file. */ |
| 4200 | before exiting the loop, it is set to a negative value if I/O | ||
| 4201 | error occurs. */ | ||
| 4202 | how_much = 0; | 4200 | how_much = 0; |
| 4203 | 4201 | ||
| 4204 | /* Total bytes inserted. */ | 4202 | /* Total bytes inserted. */ |
| 4205 | inserted = 0; | 4203 | inserted = 0; |
| 4206 | 4204 | ||
| 4207 | /* Here, we don't do code conversion in the loop. It is done by | 4205 | /* Here we don't do code conversion in the loop. It is done by |
| 4208 | decode_coding_gap after all data are read into the buffer. */ | 4206 | decode_coding_gap after all data are read into the buffer, or |
| 4209 | { | 4207 | reading loop is interrupted with quit or due to I/O error. */ |
| 4210 | ptrdiff_t gap_size = GAP_SIZE; | ||
| 4211 | |||
| 4212 | while (how_much < total) | ||
| 4213 | { | ||
| 4214 | /* try is reserved in some compilers (Microsoft C) */ | ||
| 4215 | ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); | ||
| 4216 | ptrdiff_t this; | ||
| 4217 | |||
| 4218 | if (not_regular) | ||
| 4219 | { | ||
| 4220 | Lisp_Object nbytes; | ||
| 4221 | |||
| 4222 | /* Maybe make more room. */ | ||
| 4223 | if (gap_size < trytry) | ||
| 4224 | { | ||
| 4225 | make_gap (total - gap_size); | ||
| 4226 | gap_size = GAP_SIZE; | ||
| 4227 | } | ||
| 4228 | |||
| 4229 | /* Read from the file, capturing `quit'. When an | ||
| 4230 | error occurs, end the loop, and arrange for a quit | ||
| 4231 | to be signaled after decoding the text we read. */ | ||
| 4232 | nbytes = internal_condition_case_1 | ||
| 4233 | (read_non_regular, | ||
| 4234 | make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), | ||
| 4235 | Qerror, read_non_regular_quit); | ||
| 4236 | |||
| 4237 | if (NILP (nbytes)) | ||
| 4238 | { | ||
| 4239 | read_quit = 1; | ||
| 4240 | break; | ||
| 4241 | } | ||
| 4242 | |||
| 4243 | this = XINT (nbytes); | ||
| 4244 | } | ||
| 4245 | else | ||
| 4246 | { | ||
| 4247 | /* Allow quitting out of the actual I/O. We don't make text | ||
| 4248 | part of the buffer until all the reading is done, so a C-g | ||
| 4249 | here doesn't do any harm. */ | ||
| 4250 | immediate_quit = 1; | ||
| 4251 | QUIT; | ||
| 4252 | this = emacs_read (fd, | ||
| 4253 | ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE | ||
| 4254 | + inserted), | ||
| 4255 | trytry); | ||
| 4256 | immediate_quit = 0; | ||
| 4257 | } | ||
| 4258 | |||
| 4259 | if (this <= 0) | ||
| 4260 | { | ||
| 4261 | how_much = this; | ||
| 4262 | break; | ||
| 4263 | } | ||
| 4264 | 4208 | ||
| 4265 | gap_size -= this; | 4209 | while (how_much < total) |
| 4210 | { | ||
| 4211 | ptrdiff_t nread, maxread = min (total - how_much, READ_BUF_SIZE); | ||
| 4212 | Lisp_Object result; | ||
| 4213 | |||
| 4214 | /* For a special file, gap is enlarged as we read, | ||
| 4215 | so GAP_SIZE should be checked every time. */ | ||
| 4216 | if (not_regular && (GAP_SIZE < maxread)) | ||
| 4217 | make_gap (maxread - GAP_SIZE); | ||
| 4218 | |||
| 4219 | /* Read from the file, capturing `quit'. */ | ||
| 4220 | result = internal_condition_case_1 | ||
| 4221 | (read_contents, | ||
| 4222 | make_save_value ("iii", (ptrdiff_t) fd, inserted, maxread), | ||
| 4223 | Qerror, read_contents_quit); | ||
| 4224 | if (NILP (result)) | ||
| 4225 | { | ||
| 4226 | /* Quit is signaled. End the loop and arrange | ||
| 4227 | real quit after decoding the text we read. */ | ||
| 4228 | read_quit = 1; | ||
| 4229 | break; | ||
| 4230 | } | ||
| 4231 | nread = XINT (result); | ||
| 4232 | if (nread <= 0) | ||
| 4233 | { | ||
| 4234 | /* End of file or I/O error. End the loop and | ||
| 4235 | save error code in case of I/O error. */ | ||
| 4236 | if (nread < 0) | ||
| 4237 | read_errno = errno; | ||
| 4238 | break; | ||
| 4239 | } | ||
| 4266 | 4240 | ||
| 4267 | /* For a regular file, where TOTAL is the real size, | 4241 | /* Adjust gap and end positions. */ |
| 4268 | count HOW_MUCH to compare with it. | 4242 | GAP_SIZE -= nread; |
| 4269 | For a special file, where TOTAL is just a buffer size, | 4243 | GPT += nread; |
| 4270 | so don't bother counting in HOW_MUCH. | 4244 | ZV += nread; |
| 4271 | (INSERTED is where we count the number of characters inserted.) */ | 4245 | Z += nread; |
| 4272 | if (! not_regular) | 4246 | GPT_BYTE += nread; |
| 4273 | how_much += this; | 4247 | ZV_BYTE += nread; |
| 4274 | inserted += this; | 4248 | Z_BYTE += nread; |
| 4275 | } | 4249 | if (GAP_SIZE > 0) |
| 4276 | } | 4250 | *(GPT_ADDR) = 0; |
| 4251 | |||
| 4252 | /* For a regular file, where TOTAL is the real size, count HOW_MUCH to | ||
| 4253 | compare with it. For a special file, where TOTAL is just a buffer | ||
| 4254 | size, don't bother counting in HOW_MUCH, but always accumulate the | ||
| 4255 | number of bytes read in INSERTED. */ | ||
| 4256 | if (!not_regular) | ||
| 4257 | how_much += nread; | ||
| 4258 | inserted += nread; | ||
| 4259 | } | ||
| 4277 | 4260 | ||
| 4278 | /* Now we have read all the file data into the gap. | 4261 | /* Now we have either read all the file data into the gap, |
| 4279 | If it was empty, undo marking the buffer modified. */ | 4262 | or stop reading on I/O error or quit. If nothing was |
| 4263 | read, undo marking the buffer modified. */ | ||
| 4280 | 4264 | ||
| 4281 | if (inserted == 0) | 4265 | if (inserted == 0) |
| 4282 | { | 4266 | { |
| @@ -4289,28 +4273,11 @@ by calling `format-decode', which see. */) | |||
| 4289 | else | 4273 | else |
| 4290 | Vdeactivate_mark = Qt; | 4274 | Vdeactivate_mark = Qt; |
| 4291 | 4275 | ||
| 4292 | /* Make the text read part of the buffer. */ | ||
| 4293 | GAP_SIZE -= inserted; | ||
| 4294 | GPT += inserted; | ||
| 4295 | GPT_BYTE += inserted; | ||
| 4296 | ZV += inserted; | ||
| 4297 | ZV_BYTE += inserted; | ||
| 4298 | Z += inserted; | ||
| 4299 | Z_BYTE += inserted; | ||
| 4300 | |||
| 4301 | if (GAP_SIZE > 0) | ||
| 4302 | /* Put an anchor to ensure multi-byte form ends at gap. */ | ||
| 4303 | *GPT_ADDR = 0; | ||
| 4304 | |||
| 4305 | emacs_close (fd); | 4276 | emacs_close (fd); |
| 4306 | 4277 | ||
| 4307 | /* Discard the unwind protect for closing the file. */ | 4278 | /* Discard the unwind protect for closing the file. */ |
| 4308 | specpdl_ptr--; | 4279 | specpdl_ptr--; |
| 4309 | 4280 | ||
| 4310 | if (how_much < 0) | ||
| 4311 | error ("IO error reading %s: %s", | ||
| 4312 | SDATA (orig_filename), emacs_strerror (errno)); | ||
| 4313 | |||
| 4314 | notfound: | 4281 | notfound: |
| 4315 | 4282 | ||
| 4316 | if (NILP (coding_system)) | 4283 | if (NILP (coding_system)) |
| @@ -4599,14 +4566,17 @@ by calling `format-decode', which see. */) | |||
| 4599 | report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); | 4566 | report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); |
| 4600 | } | 4567 | } |
| 4601 | 4568 | ||
| 4569 | /* There was an error reading file. */ | ||
| 4570 | if (read_errno) | ||
| 4571 | error ("IO error reading %s: %s", | ||
| 4572 | SDATA (orig_filename), emacs_strerror (read_errno)); | ||
| 4573 | |||
| 4574 | /* Quit was signaled. */ | ||
| 4602 | if (read_quit) | 4575 | if (read_quit) |
| 4603 | Fsignal (Qquit, Qnil); | 4576 | Fsignal (Qquit, Qnil); |
| 4604 | 4577 | ||
| 4605 | /* ??? Retval needs to be dealt with in all cases consistently. */ | ||
| 4606 | if (NILP (val)) | 4578 | if (NILP (val)) |
| 4607 | val = Fcons (orig_filename, | 4579 | val = list2 (orig_filename, make_number (inserted)); |
| 4608 | Fcons (make_number (inserted), | ||
| 4609 | Qnil)); | ||
| 4610 | 4580 | ||
| 4611 | RETURN_UNGCPRO (unbind_to (count, val)); | 4581 | RETURN_UNGCPRO (unbind_to (count, val)); |
| 4612 | } | 4582 | } |