aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2013-07-17 10:24:54 -0700
committerPaul Eggert2013-07-17 10:24:54 -0700
commita0931322f6c257bb4a4a678f62dcb4ae3b253221 (patch)
tree2c597df44098b26fb66026354ef17738ee922635 /src
parent5dc8a629877b040a5dd5904815ed885949614948 (diff)
downloademacs-a0931322f6c257bb4a4a678f62dcb4ae3b253221.tar.gz
emacs-a0931322f6c257bb4a4a678f62dcb4ae3b253221.zip
* lread.c: Fix file descriptor leaks and errno issues.
(Fload): Close some races that leaked fds or streams when 'load' was interrupted. (Fload, openp): Report error number of last nontrivial failure to open. ENOENT counts as trivial. * eval.c (do_nothing, clear_unwind_protect, set_unwind_protect_ptr): New functions. * fileio.c (close_file_unwind): No need to test whether FD is nonnegative, now that the function is always called with a nonnegative arg. * lisp.h (set_unwind_protect_ptr, set_unwind_protect_int): Remove. All uses replaced with ... (clear_unwind_protect, set_unwind_protect_ptr): New decls.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog13
-rw-r--r--src/editfns.c2
-rw-r--r--src/eval.c21
-rw-r--r--src/fileio.c7
-rw-r--r--src/lisp.h14
-rw-r--r--src/lread.c111
6 files changed, 103 insertions, 65 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 23334449ef3..189a353bde6 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,18 @@
12013-07-17 Paul Eggert <eggert@cs.ucla.edu> 12013-07-17 Paul Eggert <eggert@cs.ucla.edu>
2 2
3 * lread.c: Fix file descriptor leaks and errno issues.
4 (Fload): Close some races that leaked fds or streams when 'load'
5 was interrupted.
6 (Fload, openp): Report error number of last nontrivial failure to open.
7 ENOENT counts as trivial.
8 * eval.c (do_nothing, clear_unwind_protect, set_unwind_protect_ptr):
9 New functions.
10 * fileio.c (close_file_unwind): No need to test whether FD is nonnegative,
11 now that the function is always called with a nonnegative arg.
12 * lisp.h (set_unwind_protect_ptr, set_unwind_protect_int): Remove.
13 All uses replaced with ...
14 (clear_unwind_protect, set_unwind_protect_ptr): New decls.
15
3 A few more minor file errno-reporting bugs. 16 A few more minor file errno-reporting bugs.
4 * callproc.c (Fcall_process): 17 * callproc.c (Fcall_process):
5 * doc.c (Fsnarf_documentation): 18 * doc.c (Fsnarf_documentation):
diff --git a/src/editfns.c b/src/editfns.c
index b8fce7c1935..a4dea203a22 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4238,7 +4238,7 @@ usage: (format STRING &rest OBJECTS) */)
4238 else 4238 else
4239 { 4239 {
4240 buf = xrealloc (buf, bufsize); 4240 buf = xrealloc (buf, bufsize);
4241 set_unwind_protect_ptr (buf_save_value_index, buf); 4241 set_unwind_protect_ptr (buf_save_value_index, xfree, buf);
4242 } 4242 }
4243 4243
4244 p = buf + used; 4244 p = buf + used;
diff --git a/src/eval.c b/src/eval.c
index 6632084146f..a4f94ee1415 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3225,6 +3225,27 @@ record_unwind_protect_void (void (*function) (void))
3225 grow_specpdl (); 3225 grow_specpdl ();
3226} 3226}
3227 3227
3228static void
3229do_nothing (void)
3230{}
3231
3232void
3233clear_unwind_protect (ptrdiff_t count)
3234{
3235 union specbinding *p = specpdl + count;
3236 p->unwind_void.kind = SPECPDL_UNWIND_VOID;
3237 p->unwind_void.func = do_nothing;
3238}
3239
3240void
3241set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg)
3242{
3243 union specbinding *p = specpdl + count;
3244 p->unwind_ptr.kind = SPECPDL_UNWIND_PTR;
3245 p->unwind_ptr.func = func;
3246 p->unwind_ptr.arg = arg;
3247}
3248
3228Lisp_Object 3249Lisp_Object
3229unbind_to (ptrdiff_t count, Lisp_Object value) 3250unbind_to (ptrdiff_t count, Lisp_Object value)
3230{ 3251{
diff --git a/src/fileio.c b/src/fileio.c
index 06a0db2316f..28b2dc84726 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -217,8 +217,7 @@ report_file_error (char const *string, Lisp_Object name)
217void 217void
218close_file_unwind (int fd) 218close_file_unwind (int fd)
219{ 219{
220 if (0 <= fd) 220 emacs_close (fd);
221 emacs_close (fd);
222} 221}
223 222
224/* Restore point, having saved it as a marker. */ 223/* Restore point, having saved it as a marker. */
@@ -4029,7 +4028,7 @@ by calling `format-decode', which see. */)
4029 if (this < 0) 4028 if (this < 0)
4030 report_file_error ("Read error", orig_filename); 4029 report_file_error ("Read error", orig_filename);
4031 emacs_close (fd); 4030 emacs_close (fd);
4032 set_unwind_protect_int (fd_index, -1); 4031 clear_unwind_protect (fd_index);
4033 4032
4034 if (unprocessed > 0) 4033 if (unprocessed > 0)
4035 { 4034 {
@@ -4270,7 +4269,7 @@ by calling `format-decode', which see. */)
4270 Vdeactivate_mark = Qt; 4269 Vdeactivate_mark = Qt;
4271 4270
4272 emacs_close (fd); 4271 emacs_close (fd);
4273 set_unwind_protect_int (fd_index, -1); 4272 clear_unwind_protect (fd_index);
4274 4273
4275 if (how_much < 0) 4274 if (how_much < 0)
4276 report_file_error ("Read error", orig_filename); 4275 report_file_error ("Read error", orig_filename);
diff --git a/src/lisp.h b/src/lisp.h
index 26e9e18ec9a..231dbee2d21 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2744,18 +2744,6 @@ SPECPDL_INDEX (void)
2744 return specpdl_ptr - specpdl; 2744 return specpdl_ptr - specpdl;
2745} 2745}
2746 2746
2747LISP_INLINE void
2748set_unwind_protect_ptr (ptrdiff_t count, void *arg)
2749{
2750 specpdl[count].unwind_ptr.arg = arg;
2751}
2752
2753LISP_INLINE void
2754set_unwind_protect_int (ptrdiff_t count, int arg)
2755{
2756 specpdl[count].unwind_int.arg = arg;
2757}
2758
2759/* Everything needed to describe an active condition case. 2747/* Everything needed to describe an active condition case.
2760 2748
2761 Members are volatile if their values need to survive _longjmp when 2749 Members are volatile if their values need to survive _longjmp when
@@ -3755,6 +3743,8 @@ extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object);
3755extern void record_unwind_protect_int (void (*) (int), int); 3743extern void record_unwind_protect_int (void (*) (int), int);
3756extern void record_unwind_protect_ptr (void (*) (void *), void *); 3744extern void record_unwind_protect_ptr (void (*) (void *), void *);
3757extern void record_unwind_protect_void (void (*) (void)); 3745extern void record_unwind_protect_void (void (*) (void));
3746extern void clear_unwind_protect (ptrdiff_t);
3747extern void set_unwind_protect_ptr (ptrdiff_t, void (*) (void *), void *);
3758extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); 3748extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object);
3759extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); 3749extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
3760extern _Noreturn void verror (const char *, va_list) 3750extern _Noreturn void verror (const char *, va_list)
diff --git a/src/lread.c b/src/lread.c
index c4bc6fda812..ee387b832c5 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1040,10 +1040,12 @@ While the file is in the process of being loaded, the variable
1040is bound to the file's name. 1040is bound to the file's name.
1041 1041
1042Return t if the file exists and loads successfully. */) 1042Return t if the file exists and loads successfully. */)
1043 (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage, Lisp_Object nosuffix, Lisp_Object must_suffix) 1043 (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage,
1044 Lisp_Object nosuffix, Lisp_Object must_suffix)
1044{ 1045{
1045 register FILE *stream; 1046 FILE *stream;
1046 register int fd = -1; 1047 int fd;
1048 int fd_index;
1047 ptrdiff_t count = SPECPDL_INDEX (); 1049 ptrdiff_t count = SPECPDL_INDEX ();
1048 struct gcpro gcpro1, gcpro2, gcpro3; 1050 struct gcpro gcpro1, gcpro2, gcpro3;
1049 Lisp_Object found, efound, hist_file_name; 1051 Lisp_Object found, efound, hist_file_name;
@@ -1054,7 +1056,6 @@ Return t if the file exists and loads successfully. */)
1054 Lisp_Object handler; 1056 Lisp_Object handler;
1055 bool safe_p = 1; 1057 bool safe_p = 1;
1056 const char *fmode = "r"; 1058 const char *fmode = "r";
1057 Lisp_Object tmp[2];
1058 int version; 1059 int version;
1059 1060
1060#ifdef DOS_NT 1061#ifdef DOS_NT
@@ -1087,19 +1088,23 @@ Return t if the file exists and loads successfully. */)
1087 else 1088 else
1088 file = Fsubstitute_in_file_name (file); 1089 file = Fsubstitute_in_file_name (file);
1089 1090
1090
1091 /* Avoid weird lossage with null string as arg, 1091 /* Avoid weird lossage with null string as arg,
1092 since it would try to load a directory as a Lisp file. */ 1092 since it would try to load a directory as a Lisp file. */
1093 if (SBYTES (file) > 0) 1093 if (SCHARS (file) == 0)
1094 { 1094 {
1095 ptrdiff_t size = SBYTES (file); 1095 fd = -1;
1096 1096 errno = ENOENT;
1097 }
1098 else
1099 {
1100 Lisp_Object suffixes;
1097 found = Qnil; 1101 found = Qnil;
1098 GCPRO2 (file, found); 1102 GCPRO2 (file, found);
1099 1103
1100 if (! NILP (must_suffix)) 1104 if (! NILP (must_suffix))
1101 { 1105 {
1102 /* Don't insist on adding a suffix if FILE already ends with one. */ 1106 /* Don't insist on adding a suffix if FILE already ends with one. */
1107 ptrdiff_t size = SBYTES (file);
1103 if (size > 3 1108 if (size > 3
1104 && !strcmp (SSDATA (file) + size - 3, ".el")) 1109 && !strcmp (SSDATA (file) + size - 3, ".el"))
1105 must_suffix = Qnil; 1110 must_suffix = Qnil;
@@ -1112,20 +1117,28 @@ Return t if the file exists and loads successfully. */)
1112 must_suffix = Qnil; 1117 must_suffix = Qnil;
1113 } 1118 }
1114 1119
1115 fd = openp (Vload_path, file, 1120 if (!NILP (nosuffix))
1116 (!NILP (nosuffix) ? Qnil 1121 suffixes = Qnil;
1117 : !NILP (must_suffix) ? Fget_load_suffixes () 1122 else
1118 : Fappend (2, (tmp[0] = Fget_load_suffixes (), 1123 {
1119 tmp[1] = Vload_file_rep_suffixes, 1124 suffixes = Fget_load_suffixes ();
1120 tmp))), 1125 if (NILP (must_suffix))
1121 &found, Qnil); 1126 {
1127 Lisp_Object arg[2];
1128 arg[0] = suffixes;
1129 arg[1] = Vload_file_rep_suffixes;
1130 suffixes = Fappend (2, arg);
1131 }
1132 }
1133
1134 fd = openp (Vload_path, file, suffixes, &found, Qnil);
1122 UNGCPRO; 1135 UNGCPRO;
1123 } 1136 }
1124 1137
1125 if (fd == -1) 1138 if (fd == -1)
1126 { 1139 {
1127 if (NILP (noerror)) 1140 if (NILP (noerror))
1128 xsignal2 (Qfile_error, build_string ("Cannot open load file"), file); 1141 report_file_error ("Cannot open load file", file);
1129 return Qnil; 1142 return Qnil;
1130 } 1143 }
1131 1144
@@ -1163,6 +1176,12 @@ Return t if the file exists and loads successfully. */)
1163#endif 1176#endif
1164 } 1177 }
1165 1178
1179 if (0 <= fd)
1180 {
1181 fd_index = SPECPDL_INDEX ();
1182 record_unwind_protect_int (close_file_unwind, fd);
1183 }
1184
1166 /* Check if we're stuck in a recursive load cycle. 1185 /* Check if we're stuck in a recursive load cycle.
1167 1186
1168 2000-09-21: It's not possible to just check for the file loaded 1187 2000-09-21: It's not possible to just check for the file loaded
@@ -1178,11 +1197,7 @@ Return t if the file exists and loads successfully. */)
1178 Lisp_Object tem; 1197 Lisp_Object tem;
1179 for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem)) 1198 for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem))
1180 if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3)) 1199 if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3))
1181 { 1200 signal_error ("Recursive load", Fcons (found, Vloads_in_progress));
1182 if (fd >= 0)
1183 emacs_close (fd);
1184 signal_error ("Recursive load", Fcons (found, Vloads_in_progress));
1185 }
1186 record_unwind_protect (record_load_unwind, Vloads_in_progress); 1201 record_unwind_protect (record_load_unwind, Vloads_in_progress);
1187 Vloads_in_progress = Fcons (found, Vloads_in_progress); 1202 Vloads_in_progress = Fcons (found, Vloads_in_progress);
1188 } 1203 }
@@ -1195,9 +1210,8 @@ Return t if the file exists and loads successfully. */)
1195 1210
1196 /* Get the name for load-history. */ 1211 /* Get the name for load-history. */
1197 hist_file_name = (! NILP (Vpurify_flag) 1212 hist_file_name = (! NILP (Vpurify_flag)
1198 ? Fconcat (2, (tmp[0] = Ffile_name_directory (file), 1213 ? concat2 (Ffile_name_directory (file),
1199 tmp[1] = Ffile_name_nondirectory (found), 1214 Ffile_name_nondirectory (found))
1200 tmp))
1201 : found) ; 1215 : found) ;
1202 1216
1203 version = -1; 1217 version = -1;
@@ -1223,12 +1237,7 @@ Return t if the file exists and loads successfully. */)
1223 { 1237 {
1224 safe_p = 0; 1238 safe_p = 0;
1225 if (!load_dangerous_libraries) 1239 if (!load_dangerous_libraries)
1226 { 1240 error ("File `%s' was not compiled in Emacs", SDATA (found));
1227 if (fd >= 0)
1228 emacs_close (fd);
1229 error ("File `%s' was not compiled in Emacs",
1230 SDATA (found));
1231 }
1232 else if (!NILP (nomessage) && !force_load_messages) 1241 else if (!NILP (nomessage) && !force_load_messages)
1233 message_with_string ("File `%s' not compiled in Emacs", found, 1); 1242 message_with_string ("File `%s' not compiled in Emacs", found, 1);
1234 } 1243 }
@@ -1274,7 +1283,10 @@ Return t if the file exists and loads successfully. */)
1274 Lisp_Object val; 1283 Lisp_Object val;
1275 1284
1276 if (fd >= 0) 1285 if (fd >= 0)
1277 emacs_close (fd); 1286 {
1287 emacs_close (fd);
1288 clear_unwind_protect (fd_index);
1289 }
1278 val = call4 (Vload_source_file_function, found, hist_file_name, 1290 val = call4 (Vload_source_file_function, found, hist_file_name,
1279 NILP (noerror) ? Qnil : Qt, 1291 NILP (noerror) ? Qnil : Qt,
1280 (NILP (nomessage) || force_load_messages) ? Qnil : Qt); 1292 (NILP (nomessage) || force_load_messages) ? Qnil : Qt);
@@ -1284,26 +1296,28 @@ Return t if the file exists and loads successfully. */)
1284 1296
1285 GCPRO3 (file, found, hist_file_name); 1297 GCPRO3 (file, found, hist_file_name);
1286 1298
1287#ifdef WINDOWSNT 1299 if (fd < 0)
1288 efound = ENCODE_FILE (found);
1289 /* If we somehow got here with fd == -2, meaning the file is deemed
1290 to be remote, don't even try to reopen the file locally; just
1291 force a failure instead. */
1292 if (fd >= 0)
1293 { 1300 {
1294 emacs_close (fd); 1301 /* We somehow got here with fd == -2, meaning the file is deemed
1295 stream = emacs_fopen (SSDATA (efound), fmode); 1302 to be remote. Don't even try to reopen the file locally;
1303 just force a failure. */
1304 stream = NULL;
1305 errno = EINVAL;
1296 } 1306 }
1297 else 1307 else
1298 stream = NULL;
1299#else /* not WINDOWSNT */
1300 stream = fdopen (fd, fmode);
1301#endif /* not WINDOWSNT */
1302 if (stream == 0)
1303 { 1308 {
1309#ifdef WINDOWSNT
1304 emacs_close (fd); 1310 emacs_close (fd);
1305 error ("Failure to create stdio stream for %s", SDATA (file)); 1311 clear_unwind_protect (fd_index);
1312 efound = ENCODE_FILE (found);
1313 stream = emacs_fopen (SSDATA (efound), fmode);
1314#else
1315 stream = fdopen (fd, fmode);
1316#endif
1306 } 1317 }
1318 if (! stream)
1319 report_file_error ("Opening stdio stream", file);
1320 set_unwind_protect_ptr (fd_index, load_unwind, stream);
1307 1321
1308 if (! NILP (Vpurify_flag)) 1322 if (! NILP (Vpurify_flag))
1309 Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); 1323 Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list);
@@ -1322,7 +1336,6 @@ Return t if the file exists and loads successfully. */)
1322 message_with_string ("Loading %s...", file, 1); 1336 message_with_string ("Loading %s...", file, 1);
1323 } 1337 }
1324 1338
1325 record_unwind_protect_ptr (load_unwind, stream);
1326 specbind (Qload_file_name, found); 1339 specbind (Qload_file_name, found);
1327 specbind (Qinhibit_file_name_operation, Qnil); 1340 specbind (Qinhibit_file_name_operation, Qnil);
1328 specbind (Qload_in_progress, Qt); 1341 specbind (Qload_in_progress, Qt);
@@ -1521,7 +1534,6 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
1521 if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate)) 1534 if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate))
1522 { 1535 {
1523 bool exists; 1536 bool exists;
1524 last_errno = ENOENT;
1525 if (NILP (predicate)) 1537 if (NILP (predicate))
1526 exists = !NILP (Ffile_readable_p (string)); 1538 exists = !NILP (Ffile_readable_p (string));
1527 else 1539 else
@@ -1576,7 +1588,10 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
1576 { 1588 {
1577 fd = emacs_open (pfn, O_RDONLY, 0); 1589 fd = emacs_open (pfn, O_RDONLY, 0);
1578 if (fd < 0) 1590 if (fd < 0)
1579 last_errno = errno; 1591 {
1592 if (errno != ENOENT)
1593 last_errno = errno;
1594 }
1580 else 1595 else
1581 { 1596 {
1582 struct stat st; 1597 struct stat st;