aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJoakim Verona2013-01-19 00:03:30 +0100
committerJoakim Verona2013-01-19 00:03:30 +0100
commit19ea867b2ed4dca4e460d1f347a4ff39d31705f1 (patch)
treefbc1bfd2714bd7fff8d3cb5d0d2295f6f8902c9d /src
parent9206508b76f73ceeb87c72496d1c40cec83dac21 (diff)
parentb117094709e34befa5a9486584f870d3e84d8f38 (diff)
downloademacs-19ea867b2ed4dca4e460d1f347a4ff39d31705f1.tar.gz
emacs-19ea867b2ed4dca4e460d1f347a4ff39d31705f1.zip
auto upstream
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog22
-rw-r--r--src/fileio.c218
2 files changed, 107 insertions, 133 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index c85e0a789ea..a7b8ab7855b 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,25 @@
12013-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
152013-01-17 Paul Eggert <eggert@cs.ucla.edu>
16
17 Close a race when statting and reading files (Bug#13149).
18 * fileio.c (Finsert_file_contents): Use open+fstat, not stat+open.
19 This avoids a race if the file is renamed between stat and open.
20 This race is not the problem originally noted in Bug#13149;
21 see <http://bugs.gnu.org/13149#73> and later messages in the thread.
22
12013-01-17 Dmitry Antipov <dmantipov@yandex.ru> 232013-01-17 Dmitry Antipov <dmantipov@yandex.ru>
2 24
3 * lisp.h (toplevel): Add comment about using Lisp_Save_Value 25 * lisp.h (toplevel): Add comment about using Lisp_Save_Value
diff --git a/src/fileio.c b/src/fileio.c
index 8d711e8e6bf..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
3416static Lisp_Object 3416static Lisp_Object
3417read_non_regular (Lisp_Object state) 3417read_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
3435static Lisp_Object 3435static Lisp_Object
3436read_non_regular_quit (Lisp_Object ignore) 3436read_contents_quit (Lisp_Object ignore)
3437{ 3437{
3438 return Qnil; 3438 return Qnil;
3439} 3439}
@@ -3492,7 +3492,6 @@ by calling `format-decode', which see. */)
3492 (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace) 3492 (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, Lisp_Object replace)
3493{ 3493{
3494 struct stat st; 3494 struct stat st;
3495 int file_status;
3496 EMACS_TIME mtime; 3495 EMACS_TIME mtime;
3497 int fd; 3496 int fd;
3498 ptrdiff_t inserted = 0; 3497 ptrdiff_t inserted = 0;
@@ -3506,7 +3505,7 @@ by calling `format-decode', which see. */)
3506 Lisp_Object p; 3505 Lisp_Object p;
3507 ptrdiff_t total = 0; 3506 ptrdiff_t total = 0;
3508 bool not_regular = 0; 3507 bool not_regular = 0;
3509 int save_errno = 0; 3508 int save_errno = 0, read_errno = 0;
3510 char read_buf[READ_BUF_SIZE]; 3509 char read_buf[READ_BUF_SIZE];
3511 struct coding_system coding; 3510 struct coding_system coding;
3512 char buffer[1 << 14]; 3511 char buffer[1 << 14];
@@ -3554,26 +3553,9 @@ by calling `format-decode', which see. */)
3554 orig_filename = filename; 3553 orig_filename = filename;
3555 filename = ENCODE_FILE (filename); 3554 filename = ENCODE_FILE (filename);
3556 3555
3557 fd = -1; 3556 fd = emacs_open (SSDATA (filename), O_RDONLY, 0);
3558 3557 if (fd < 0)
3559#ifdef WINDOWSNT
3560 {
3561 Lisp_Object tem = Vw32_get_true_file_attributes;
3562
3563 /* Tell stat to use expensive method to get accurate info. */
3564 Vw32_get_true_file_attributes = Qt;
3565 file_status = stat (SSDATA (filename), &st);
3566 Vw32_get_true_file_attributes = tem;
3567 }
3568#else
3569 file_status = stat (SSDATA (filename), &st);
3570#endif /* WINDOWSNT */
3571
3572 if (file_status == 0)
3573 mtime = get_stat_mtime (&st);
3574 else
3575 { 3558 {
3576 badopen:
3577 save_errno = errno; 3559 save_errno = errno;
3578 if (NILP (visit)) 3560 if (NILP (visit))
3579 report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); 3561 report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
@@ -3585,6 +3567,17 @@ by calling `format-decode', which see. */)
3585 goto notfound; 3567 goto notfound;
3586 } 3568 }
3587 3569
3570 /* Replacement should preserve point as it preserves markers. */
3571 if (!NILP (replace))
3572 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
3573
3574 record_unwind_protect (close_file_unwind, make_number (fd));
3575
3576 if (fstat (fd, &st) != 0)
3577 report_file_error ("Getting input file status",
3578 Fcons (orig_filename, Qnil));
3579 mtime = get_stat_mtime (&st);
3580
3588 /* This code will need to be changed in order to work on named 3581 /* This code will need to be changed in order to work on named
3589 pipes, and it's probably just not worth it. So we should at 3582 pipes, and it's probably just not worth it. So we should at
3590 least signal an error. */ 3583 least signal an error. */
@@ -3600,17 +3593,6 @@ by calling `format-decode', which see. */)
3600 build_string ("not a regular file"), orig_filename); 3593 build_string ("not a regular file"), orig_filename);
3601 } 3594 }
3602 3595
3603 if (fd < 0)
3604 if ((fd = emacs_open (SSDATA (filename), O_RDONLY, 0)) < 0)
3605 goto badopen;
3606
3607 /* Replacement should preserve point as it preserves markers. */
3608 if (!NILP (replace))
3609 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
3610
3611 record_unwind_protect (close_file_unwind, make_number (fd));
3612
3613
3614 if (!NILP (visit)) 3596 if (!NILP (visit))
3615 { 3597 {
3616 if (!NILP (beg) || !NILP (end)) 3598 if (!NILP (beg) || !NILP (end))
@@ -4213,88 +4195,72 @@ by calling `format-decode', which see. */)
4213 Fcons (orig_filename, Qnil)); 4195 Fcons (orig_filename, Qnil));
4214 } 4196 }
4215 4197
4216 /* In the following loop, HOW_MUCH contains the total bytes read so 4198 /* In the following loop, HOW_MUCH contains the total bytes read
4217 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. */
4218 before exiting the loop, it is set to a negative value if I/O
4219 error occurs. */
4220 how_much = 0; 4200 how_much = 0;
4221 4201
4222 /* Total bytes inserted. */ 4202 /* Total bytes inserted. */
4223 inserted = 0; 4203 inserted = 0;
4224 4204
4225 /* 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
4226 decode_coding_gap after all data are read into the buffer. */ 4206 decode_coding_gap after all data are read into the buffer, or
4227 { 4207 reading loop is interrupted with quit or due to I/O error. */
4228 ptrdiff_t gap_size = GAP_SIZE;
4229
4230 while (how_much < total)
4231 {
4232 /* try is reserved in some compilers (Microsoft C) */
4233 ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE);
4234 ptrdiff_t this;
4235
4236 if (not_regular)
4237 {
4238 Lisp_Object nbytes;
4239
4240 /* Maybe make more room. */
4241 if (gap_size < trytry)
4242 {
4243 make_gap (total - gap_size);
4244 gap_size = GAP_SIZE;
4245 }
4246
4247 /* Read from the file, capturing `quit'. When an
4248 error occurs, end the loop, and arrange for a quit
4249 to be signaled after decoding the text we read. */
4250 nbytes = internal_condition_case_1
4251 (read_non_regular,
4252 make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry),
4253 Qerror, read_non_regular_quit);
4254
4255 if (NILP (nbytes))
4256 {
4257 read_quit = 1;
4258 break;
4259 }
4260
4261 this = XINT (nbytes);
4262 }
4263 else
4264 {
4265 /* Allow quitting out of the actual I/O. We don't make text
4266 part of the buffer until all the reading is done, so a C-g
4267 here doesn't do any harm. */
4268 immediate_quit = 1;
4269 QUIT;
4270 this = emacs_read (fd,
4271 ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
4272 + inserted),
4273 trytry);
4274 immediate_quit = 0;
4275 }
4276 4208
4277 if (this <= 0) 4209 while (how_much < total)
4278 { 4210 {
4279 how_much = this; 4211 ptrdiff_t nread, maxread = min (total - how_much, READ_BUF_SIZE);
4280 break; 4212 Lisp_Object result;
4281 } 4213
4282 4214 /* For a special file, gap is enlarged as we read,
4283 gap_size -= this; 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 }
4284 4240
4285 /* For a regular file, where TOTAL is the real size, 4241 /* Adjust gap and end positions. */
4286 count HOW_MUCH to compare with it. 4242 GAP_SIZE -= nread;
4287 For a special file, where TOTAL is just a buffer size, 4243 GPT += nread;
4288 so don't bother counting in HOW_MUCH. 4244 ZV += nread;
4289 (INSERTED is where we count the number of characters inserted.) */ 4245 Z += nread;
4290 if (! not_regular) 4246 GPT_BYTE += nread;
4291 how_much += this; 4247 ZV_BYTE += nread;
4292 inserted += this; 4248 Z_BYTE += nread;
4293 } 4249 if (GAP_SIZE > 0)
4294 } 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 }
4295 4260
4296 /* Now we have read all the file data into the gap. 4261 /* Now we have either read all the file data into the gap,
4297 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. */
4298 4264
4299 if (inserted == 0) 4265 if (inserted == 0)
4300 { 4266 {
@@ -4307,28 +4273,11 @@ by calling `format-decode', which see. */)
4307 else 4273 else
4308 Vdeactivate_mark = Qt; 4274 Vdeactivate_mark = Qt;
4309 4275
4310 /* Make the text read part of the buffer. */
4311 GAP_SIZE -= inserted;
4312 GPT += inserted;
4313 GPT_BYTE += inserted;
4314 ZV += inserted;
4315 ZV_BYTE += inserted;
4316 Z += inserted;
4317 Z_BYTE += inserted;
4318
4319 if (GAP_SIZE > 0)
4320 /* Put an anchor to ensure multi-byte form ends at gap. */
4321 *GPT_ADDR = 0;
4322
4323 emacs_close (fd); 4276 emacs_close (fd);
4324 4277
4325 /* Discard the unwind protect for closing the file. */ 4278 /* Discard the unwind protect for closing the file. */
4326 specpdl_ptr--; 4279 specpdl_ptr--;
4327 4280
4328 if (how_much < 0)
4329 error ("IO error reading %s: %s",
4330 SDATA (orig_filename), emacs_strerror (errno));
4331
4332 notfound: 4281 notfound:
4333 4282
4334 if (NILP (coding_system)) 4283 if (NILP (coding_system))
@@ -4617,14 +4566,17 @@ by calling `format-decode', which see. */)
4617 report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); 4566 report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
4618 } 4567 }
4619 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. */
4620 if (read_quit) 4575 if (read_quit)
4621 Fsignal (Qquit, Qnil); 4576 Fsignal (Qquit, Qnil);
4622 4577
4623 /* ??? Retval needs to be dealt with in all cases consistently. */
4624 if (NILP (val)) 4578 if (NILP (val))
4625 val = Fcons (orig_filename, 4579 val = list2 (orig_filename, make_number (inserted));
4626 Fcons (make_number (inserted),
4627 Qnil));
4628 4580
4629 RETURN_UNGCPRO (unbind_to (count, val)); 4581 RETURN_UNGCPRO (unbind_to (count, val));
4630} 4582}