diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 13 | ||||
| -rw-r--r-- | src/filelock.c | 6 | ||||
| -rw-r--r-- | src/image.c | 35 | ||||
| -rw-r--r-- | src/process.c | 22 | ||||
| -rw-r--r-- | src/xfaces.c | 20 |
5 files changed, 61 insertions, 35 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 73e24bcf829..a63e441dcb2 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,18 @@ | |||
| 1 | 2013-07-19 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2013-07-19 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Fix some minor file descriptor leaks and related glitches. | ||
| 4 | * filelock.c (create_lock_file) [!O_CLOEXEC]: Use fcntl with FD_CLOEXEC. | ||
| 5 | (create_lock_file): Use write, not emacs_write. | ||
| 6 | * image.c (slurp_file, png_load_body): | ||
| 7 | * process.c (Fnetwork_interface_list, Fnetwork_interface_info) | ||
| 8 | (server_accept_connection): | ||
| 9 | Don't leak an fd on memory allocation failure. | ||
| 10 | * image.c (slurp_file): Add a cheap heuristic for growing files. | ||
| 11 | * xfaces.c (Fx_load_color_file): Block input around the fopen too, | ||
| 12 | as that's what the other routines do. Maybe input need not be | ||
| 13 | blocked at all, but it's better to be consistent. | ||
| 14 | Avoid undefined behavior when strlen is zero. | ||
| 15 | |||
| 3 | * alloc.c (staticpro): Avoid buffer overrun on repeated calls. | 16 | * alloc.c (staticpro): Avoid buffer overrun on repeated calls. |
| 4 | (NSTATICS): Now a constant; doesn't need to be a macro. | 17 | (NSTATICS): Now a constant; doesn't need to be a macro. |
| 5 | 18 | ||
diff --git a/src/filelock.c b/src/filelock.c index fefd14b3a92..b9c991e4baf 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -430,12 +430,14 @@ create_lock_file (char *lfname, char *lock_info_str, bool force) | |||
| 430 | else | 430 | else |
| 431 | { | 431 | { |
| 432 | ptrdiff_t lock_info_len; | 432 | ptrdiff_t lock_info_len; |
| 433 | #if ! HAVE_MKOSTEMP | 433 | #if ! (HAVE_MKOSTEMP && O_CLOEXEC) |
| 434 | fcntl (fd, F_SETFD, FD_CLOEXEC); | 434 | fcntl (fd, F_SETFD, FD_CLOEXEC); |
| 435 | #endif | 435 | #endif |
| 436 | lock_info_len = strlen (lock_info_str); | 436 | lock_info_len = strlen (lock_info_str); |
| 437 | err = 0; | 437 | err = 0; |
| 438 | if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len | 438 | /* Use 'write', not 'emacs_write', as garbage collection |
| 439 | might signal an error, which would leak FD. */ | ||
| 440 | if (write (fd, lock_info_str, lock_info_len) != lock_info_len | ||
| 439 | || fchmod (fd, S_IRUSR | S_IRGRP | S_IROTH) != 0) | 441 | || fchmod (fd, S_IRUSR | S_IRGRP | S_IROTH) != 0) |
| 440 | err = errno; | 442 | err = errno; |
| 441 | /* There is no need to call fsync here, as the contents of | 443 | /* There is no need to call fsync here, as the contents of |
diff --git a/src/image.c b/src/image.c index 95d385dc9e2..1e3944ac1a1 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -2276,23 +2276,28 @@ slurp_file (char *file, ptrdiff_t *size) | |||
| 2276 | unsigned char *buf = NULL; | 2276 | unsigned char *buf = NULL; |
| 2277 | struct stat st; | 2277 | struct stat st; |
| 2278 | 2278 | ||
| 2279 | if (fp && fstat (fileno (fp), &st) == 0 | 2279 | if (fp) |
| 2280 | && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX) | ||
| 2281 | && (buf = xmalloc (st.st_size), | ||
| 2282 | fread (buf, 1, st.st_size, fp) == st.st_size)) | ||
| 2283 | { | ||
| 2284 | *size = st.st_size; | ||
| 2285 | fclose (fp); | ||
| 2286 | } | ||
| 2287 | else | ||
| 2288 | { | 2280 | { |
| 2289 | if (fp) | 2281 | ptrdiff_t count = SPECPDL_INDEX (); |
| 2290 | fclose (fp); | 2282 | record_unwind_protect_ptr (fclose_unwind, fp); |
| 2291 | if (buf) | 2283 | |
| 2284 | if (fstat (fileno (fp), &st) == 0 | ||
| 2285 | && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX)) | ||
| 2292 | { | 2286 | { |
| 2293 | xfree (buf); | 2287 | /* Report an error if we read past the purported EOF. |
| 2294 | buf = NULL; | 2288 | This can happen if the file grows as we read it. */ |
| 2289 | ptrdiff_t buflen = st.st_size; | ||
| 2290 | buf = xmalloc (buflen + 1); | ||
| 2291 | if (fread (buf, 1, buflen + 1, fp) == buflen) | ||
| 2292 | *size = buflen; | ||
| 2293 | else | ||
| 2294 | { | ||
| 2295 | xfree (buf); | ||
| 2296 | buf = NULL; | ||
| 2297 | } | ||
| 2295 | } | 2298 | } |
| 2299 | |||
| 2300 | unbind_to (count, Qnil); | ||
| 2296 | } | 2301 | } |
| 2297 | 2302 | ||
| 2298 | return buf; | 2303 | return buf; |
| @@ -5732,8 +5737,8 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c) | |||
| 5732 | if (fread (sig, 1, sizeof sig, fp) != sizeof sig | 5737 | if (fread (sig, 1, sizeof sig, fp) != sizeof sig |
| 5733 | || fn_png_sig_cmp (sig, 0, sizeof sig)) | 5738 | || fn_png_sig_cmp (sig, 0, sizeof sig)) |
| 5734 | { | 5739 | { |
| 5735 | image_error ("Not a PNG file: `%s'", file, Qnil); | ||
| 5736 | fclose (fp); | 5740 | fclose (fp); |
| 5741 | image_error ("Not a PNG file: `%s'", file, Qnil); | ||
| 5737 | return 0; | 5742 | return 0; |
| 5738 | } | 5743 | } |
| 5739 | } | 5744 | } |
diff --git a/src/process.c b/src/process.c index 7c63964aee6..f4ae662468b 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -3526,10 +3526,13 @@ format; see the description of ADDRESS in `make-network-process'. */) | |||
| 3526 | ptrdiff_t buf_size = 512; | 3526 | ptrdiff_t buf_size = 512; |
| 3527 | int s; | 3527 | int s; |
| 3528 | Lisp_Object res; | 3528 | Lisp_Object res; |
| 3529 | ptrdiff_t count; | ||
| 3529 | 3530 | ||
| 3530 | s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); | 3531 | s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); |
| 3531 | if (s < 0) | 3532 | if (s < 0) |
| 3532 | return Qnil; | 3533 | return Qnil; |
| 3534 | count = SPECPDL_INDEX (); | ||
| 3535 | record_unwind_protect_int (close_file_unwind, s); | ||
| 3533 | 3536 | ||
| 3534 | do | 3537 | do |
| 3535 | { | 3538 | { |
| @@ -3545,9 +3548,7 @@ format; see the description of ADDRESS in `make-network-process'. */) | |||
| 3545 | } | 3548 | } |
| 3546 | while (ifconf.ifc_len == buf_size); | 3549 | while (ifconf.ifc_len == buf_size); |
| 3547 | 3550 | ||
| 3548 | emacs_close (s); | 3551 | res = unbind_to (count, Qnil); |
| 3549 | |||
| 3550 | res = Qnil; | ||
| 3551 | ifreq = ifconf.ifc_req; | 3552 | ifreq = ifconf.ifc_req; |
| 3552 | while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len) | 3553 | while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len) |
| 3553 | { | 3554 | { |
| @@ -3672,6 +3673,7 @@ FLAGS is the current flags of the interface. */) | |||
| 3672 | Lisp_Object elt; | 3673 | Lisp_Object elt; |
| 3673 | int s; | 3674 | int s; |
| 3674 | bool any = 0; | 3675 | bool any = 0; |
| 3676 | ptrdiff_t count; | ||
| 3675 | #if (! (defined SIOCGIFHWADDR && defined HAVE_STRUCT_IFREQ_IFR_HWADDR) \ | 3677 | #if (! (defined SIOCGIFHWADDR && defined HAVE_STRUCT_IFREQ_IFR_HWADDR) \ |
| 3676 | && defined HAVE_GETIFADDRS && defined LLADDR) | 3678 | && defined HAVE_GETIFADDRS && defined LLADDR) |
| 3677 | struct ifaddrs *ifap; | 3679 | struct ifaddrs *ifap; |
| @@ -3686,6 +3688,8 @@ FLAGS is the current flags of the interface. */) | |||
| 3686 | s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); | 3688 | s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); |
| 3687 | if (s < 0) | 3689 | if (s < 0) |
| 3688 | return Qnil; | 3690 | return Qnil; |
| 3691 | count = SPECPDL_INDEX (); | ||
| 3692 | record_unwind_protect_int (close_file_unwind, s); | ||
| 3689 | 3693 | ||
| 3690 | elt = Qnil; | 3694 | elt = Qnil; |
| 3691 | #if defined (SIOCGIFFLAGS) && defined (HAVE_STRUCT_IFREQ_IFR_FLAGS) | 3695 | #if defined (SIOCGIFFLAGS) && defined (HAVE_STRUCT_IFREQ_IFR_FLAGS) |
| @@ -3802,9 +3806,7 @@ FLAGS is the current flags of the interface. */) | |||
| 3802 | #endif | 3806 | #endif |
| 3803 | res = Fcons (elt, res); | 3807 | res = Fcons (elt, res); |
| 3804 | 3808 | ||
| 3805 | emacs_close (s); | 3809 | return unbind_to (count, any ? res : Qnil); |
| 3806 | |||
| 3807 | return any ? res : Qnil; | ||
| 3808 | } | 3810 | } |
| 3809 | #endif | 3811 | #endif |
| 3810 | #endif /* defined (HAVE_NET_IF_H) */ | 3812 | #endif /* defined (HAVE_NET_IF_H) */ |
| @@ -3978,6 +3980,7 @@ server_accept_connection (Lisp_Object server, int channel) | |||
| 3978 | #endif | 3980 | #endif |
| 3979 | } saddr; | 3981 | } saddr; |
| 3980 | socklen_t len = sizeof saddr; | 3982 | socklen_t len = sizeof saddr; |
| 3983 | ptrdiff_t count; | ||
| 3981 | 3984 | ||
| 3982 | s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC); | 3985 | s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC); |
| 3983 | 3986 | ||
| @@ -4000,6 +4003,9 @@ server_accept_connection (Lisp_Object server, int channel) | |||
| 4000 | return; | 4003 | return; |
| 4001 | } | 4004 | } |
| 4002 | 4005 | ||
| 4006 | count = SPECPDL_INDEX (); | ||
| 4007 | record_unwind_protect_int (close_file_unwind, s); | ||
| 4008 | |||
| 4003 | connect_counter++; | 4009 | connect_counter++; |
| 4004 | 4010 | ||
| 4005 | /* Setup a new process to handle the connection. */ | 4011 | /* Setup a new process to handle the connection. */ |
| @@ -4116,6 +4122,10 @@ server_accept_connection (Lisp_Object server, int channel) | |||
| 4116 | pset_filter (p, ps->filter); | 4122 | pset_filter (p, ps->filter); |
| 4117 | pset_command (p, Qnil); | 4123 | pset_command (p, Qnil); |
| 4118 | p->pid = 0; | 4124 | p->pid = 0; |
| 4125 | |||
| 4126 | /* Discard the unwind protect for closing S. */ | ||
| 4127 | specpdl_ptr = specpdl + count; | ||
| 4128 | |||
| 4119 | p->infd = s; | 4129 | p->infd = s; |
| 4120 | p->outfd = s; | 4130 | p->outfd = s; |
| 4121 | pset_status (p, Qrun); | 4131 | pset_status (p, Qrun); |
diff --git a/src/xfaces.c b/src/xfaces.c index d35851220b0..f647ff2e209 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -6283,6 +6283,7 @@ where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */) | |||
| 6283 | CHECK_STRING (filename); | 6283 | CHECK_STRING (filename); |
| 6284 | abspath = Fexpand_file_name (filename, Qnil); | 6284 | abspath = Fexpand_file_name (filename, Qnil); |
| 6285 | 6285 | ||
| 6286 | block_input (); | ||
| 6286 | fp = emacs_fopen (SSDATA (abspath), "rt"); | 6287 | fp = emacs_fopen (SSDATA (abspath), "rt"); |
| 6287 | if (fp) | 6288 | if (fp) |
| 6288 | { | 6289 | { |
| @@ -6290,29 +6291,24 @@ where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */) | |||
| 6290 | int red, green, blue; | 6291 | int red, green, blue; |
| 6291 | int num; | 6292 | int num; |
| 6292 | 6293 | ||
| 6293 | block_input (); | ||
| 6294 | |||
| 6295 | while (fgets (buf, sizeof (buf), fp) != NULL) { | 6294 | while (fgets (buf, sizeof (buf), fp) != NULL) { |
| 6296 | if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3) | 6295 | if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3) |
| 6297 | { | 6296 | { |
| 6298 | char *name = buf + num; | ||
| 6299 | num = strlen (name) - 1; | ||
| 6300 | if (num >= 0 && name[num] == '\n') | ||
| 6301 | name[num] = 0; | ||
| 6302 | cmap = Fcons (Fcons (build_string (name), | ||
| 6303 | #ifdef HAVE_NTGUI | 6297 | #ifdef HAVE_NTGUI |
| 6304 | make_number (RGB (red, green, blue))), | 6298 | int color = RGB (red, green, blue); |
| 6305 | #else | 6299 | #else |
| 6306 | make_number ((red << 16) | (green << 8) | blue)), | 6300 | int color = (red << 16) | (green << 8) | blue; |
| 6307 | #endif | 6301 | #endif |
| 6302 | char *name = buf + num; | ||
| 6303 | ptrdiff_t len = strlen (name); | ||
| 6304 | len -= 0 < len && name[len - 1] == '\n'; | ||
| 6305 | cmap = Fcons (Fcons (make_string (name, len), make_number (color)), | ||
| 6308 | cmap); | 6306 | cmap); |
| 6309 | } | 6307 | } |
| 6310 | } | 6308 | } |
| 6311 | fclose (fp); | 6309 | fclose (fp); |
| 6312 | |||
| 6313 | unblock_input (); | ||
| 6314 | } | 6310 | } |
| 6315 | 6311 | unblock_input (); | |
| 6316 | return cmap; | 6312 | return cmap; |
| 6317 | } | 6313 | } |
| 6318 | #endif | 6314 | #endif |