aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-09-11 11:26:07 -0700
committerPaul Eggert2019-09-11 11:27:14 -0700
commit5fafa40d076ee24baf880e97d4290b6196cf838a (patch)
tree03452b023e9777409d979932b53f9ef347601b76 /src
parenta6daae7b3df3a964b3dcde85987c02fd0af66a89 (diff)
downloademacs-5fafa40d076ee24baf880e97d4290b6196cf838a.tar.gz
emacs-5fafa40d076ee24baf880e97d4290b6196cf838a.zip
Improve checking of pdump load failures
* src/alloc.c (memory_full): Just report "memory exhausted" if failure occurs during initialization, since fancier recovery schemes are not likely to work when not initialized. * src/emacs.c (dump_error_to_string): Accept int, not enum pdumper_load_result, since the result might not fit in the enum. Use strerror if it was derived from errno. This is for better diagnostics of pdump load failures. (load_pdump_find_executable): Return char *, not enum. 2nd arg is now pointer to buffer size, rather than pointer to pointer to buffer. All callers changed. Use Emacs allocator since they should now be OK even during early startup. Use check_executable instead access, to use effective rather than real permissions. (load_pdump): Return void since callers ignore result. Use int where enum could be too narrow. Use heap rather than stack for possibly-long string. Prefer ptrdiff_t to size_t. * src/fileio.c (check_executable): Now extern. * src/pdumper.c (pdumper_load): Return int that may have errno added to it, for better diagnostics when loads fail.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c3
-rw-r--r--src/emacs.c182
-rw-r--r--src/fileio.c2
-rw-r--r--src/lisp.h1
-rw-r--r--src/pdumper.c11
-rw-r--r--src/pdumper.h4
6 files changed, 91 insertions, 112 deletions
diff --git a/src/alloc.c b/src/alloc.c
index be98cfd5f53..2d490f3bb75 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3844,6 +3844,9 @@ set_interval_marked (INTERVAL i)
3844void 3844void
3845memory_full (size_t nbytes) 3845memory_full (size_t nbytes)
3846{ 3846{
3847 if (!initialized)
3848 fatal ("memory exhausted");
3849
3847 /* Do not go into hysterics merely because a large request failed. */ 3850 /* Do not go into hysterics merely because a large request failed. */
3848 bool enough_free_memory = false; 3851 bool enough_free_memory = false;
3849 if (SPARE_MEMORY < nbytes) 3852 if (SPARE_MEMORY < nbytes)
diff --git a/src/emacs.c b/src/emacs.c
index 53572d7f0c8..5a526687b14 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -662,7 +662,7 @@ argmatch (char **argv, int argc, const char *sstr, const char *lstr,
662#ifdef HAVE_PDUMPER 662#ifdef HAVE_PDUMPER
663 663
664static const char * 664static const char *
665dump_error_to_string (enum pdumper_load_result result) 665dump_error_to_string (int result)
666{ 666{
667 switch (result) 667 switch (result)
668 { 668 {
@@ -681,37 +681,29 @@ dump_error_to_string (enum pdumper_load_result result)
681 case PDUMPER_LOAD_VERSION_MISMATCH: 681 case PDUMPER_LOAD_VERSION_MISMATCH:
682 return "not built for this Emacs executable"; 682 return "not built for this Emacs executable";
683 default: 683 default:
684 return "generic error"; 684 return (result <= PDUMPER_LOAD_ERROR
685 ? "generic error"
686 : strerror (result - PDUMPER_LOAD_ERROR));
685 } 687 }
686} 688}
687 689
688/* Find a path (absolute or relative) to the Emacs executable. 690/* Find a name (absolute or relative) of the Emacs executable whose
689 Called early in initialization by portable dumper loading code, so we 691 name (as passed into this program) is ARGV0. Called early in
690 can't use lisp and associated machinery. On success, *EXENAME is 692 initialization by portable dumper loading code, so avoid Lisp and
691 set to a heap-allocated string giving a path to the Emacs 693 associated machinery. Return a heap-allocated string giving a name
692 executable or to NULL if we can't determine the path immediately. 694 of the Emacs executable, or an empty heap-allocated string or NULL
693 */ 695 if not found. Store into *CANDIDATE_SIZE a lower bound on the size
694static enum pdumper_load_result 696 of any heap allocation. */
695load_pdump_find_executable (const char* argv0, char **exename) 697static char *
698load_pdump_find_executable (char const *argv0, ptrdiff_t *candidate_size)
696{ 699{
697 enum pdumper_load_result result; 700 *candidate_size = 0;
701
702 /* Use xstrdup etc. to allocate storage, so as to call our private
703 implementation of malloc, since the caller calls our free. */
698#ifdef WINDOWSNT 704#ifdef WINDOWSNT
699 result = PDUMPER_LOAD_ERROR;
700 *exename = NULL;
701 char *prog_fname = w32_my_exename (); 705 char *prog_fname = w32_my_exename ();
702 if (prog_fname) 706 return prog_fname ? xstrdup (prog_fname) : NULL;
703 {
704 result = PDUMPER_LOAD_OOM;
705 /* Use xstrdup, so as to call our private implementation of
706 malloc, since the caller calls our free. */
707 char *ret = xstrdup (prog_fname);
708 if (ret)
709 {
710 *exename = ret;
711 result = PDUMPER_LOAD_SUCCESS;
712 }
713 }
714 return result;
715#else /* !WINDOWSNT */ 707#else /* !WINDOWSNT */
716 char *candidate = NULL; 708 char *candidate = NULL;
717 709
@@ -719,33 +711,23 @@ load_pdump_find_executable (const char* argv0, char **exename)
719 path already, so just copy it. */ 711 path already, so just copy it. */
720 eassert (argv0); 712 eassert (argv0);
721 if (strchr (argv0, DIRECTORY_SEP)) 713 if (strchr (argv0, DIRECTORY_SEP))
722 { 714 return xstrdup (argv0);
723 result = PDUMPER_LOAD_OOM; 715 ptrdiff_t argv0_length = strlen (argv0);
724 char *ret = strdup (argv0);
725 if (!ret)
726 goto out;
727 result = PDUMPER_LOAD_SUCCESS;
728 *exename = ret;
729 goto out;
730 }
731 size_t argv0_length = strlen (argv0);
732 716
733 const char *path = getenv ("PATH"); 717 const char *path = getenv ("PATH");
734 if (!path) 718 if (!path)
735 { 719 {
736 /* Default PATH is implementation-defined, so we don't know how 720 /* Default PATH is implementation-defined, so we don't know how
737 to conduct the search. */ 721 to conduct the search. */
738 result = PDUMPER_LOAD_SUCCESS; 722 return NULL;
739 *exename = NULL;
740 goto out;
741 } 723 }
742 724
743 /* Actually try each concatenation of a path element and the 725 /* Actually try each concatenation of a path element and the
744 executable basename. */ 726 executable basename. */
745 const char path_sep[] = { SEPCHAR, '\0' };
746 do 727 do
747 { 728 {
748 size_t path_part_length = strcspn (path, path_sep); 729 static char const path_sep[] = { SEPCHAR, '\0' };
730 ptrdiff_t path_part_length = strcspn (path, path_sep);
749 const char *path_part = path; 731 const char *path_part = path;
750 path += path_part_length; 732 path += path_part_length;
751 if (path_part_length == 0) 733 if (path_part_length == 0)
@@ -753,46 +735,34 @@ load_pdump_find_executable (const char* argv0, char **exename)
753 path_part = "."; 735 path_part = ".";
754 path_part_length = 1; 736 path_part_length = 1;
755 } 737 }
756 size_t candidate_length = path_part_length + 1 + argv0_length; 738 ptrdiff_t needed = path_part_length + 1 + argv0_length + 1;
757 { 739 if (*candidate_size <= needed)
758 char *new_candidate = realloc (candidate, candidate_length + 1); 740 {
759 if (!new_candidate) 741 xfree (candidate);
760 { 742 candidate = xpalloc (NULL, candidate_size,
761 result = PDUMPER_LOAD_OOM; 743 needed - *candidate_size + 1, -1, 1);
762 goto out; 744 }
763 }
764 candidate = new_candidate;
765 }
766 memcpy (candidate + 0, path_part, path_part_length); 745 memcpy (candidate + 0, path_part, path_part_length);
767 candidate[path_part_length] = DIRECTORY_SEP; 746 candidate[path_part_length] = DIRECTORY_SEP;
768 memcpy (candidate + path_part_length + 1, argv0, argv0_length + 1); 747 memcpy (candidate + path_part_length + 1, argv0, argv0_length + 1);
769 struct stat st; 748 struct stat st;
770 if (!access (candidate, X_OK) && 749 if (check_executable (candidate)
771 !stat (candidate, &st) && 750 && stat (candidate, &st) == 0 && S_ISREG (st.st_mode))
772 S_ISREG (st.st_mode)) 751 return candidate;
773 { 752 *candidate = '\0';
774 *exename = candidate; 753 }
775 candidate = NULL; 754 while (*path++ != '\0');
776 break;
777 }
778 } while ((path++)[0] != '\0');
779
780 result = PDUMPER_LOAD_SUCCESS;
781 755
782 out: 756 return candidate;
783 free (candidate);
784 return result;
785#endif /* !WINDOWSNT */ 757#endif /* !WINDOWSNT */
786} 758}
787 759
788static enum pdumper_load_result 760static void
789load_pdump (int argc, char **argv) 761load_pdump (int argc, char **argv)
790{ 762{
791 const char *const suffix = ".pdmp"; 763 const char *const suffix = ".pdmp";
792 enum pdumper_load_result result; 764 int result;
793 char *exename = NULL; 765 const char *strip_suffix =
794 char *real_exename = NULL;
795 const char* strip_suffix =
796#if defined DOS_NT || defined CYGWIN 766#if defined DOS_NT || defined CYGWIN
797 ".exe" 767 ".exe"
798#else 768#else
@@ -821,7 +791,6 @@ load_pdump (int argc, char **argv)
821 skip_args++; 791 skip_args++;
822 } 792 }
823 793
824 result = PDUMPER_NOT_LOADED;
825 if (dump_file) 794 if (dump_file)
826 { 795 {
827 result = pdumper_load (dump_file); 796 result = pdumper_load (dump_file);
@@ -829,8 +798,7 @@ load_pdump (int argc, char **argv)
829 if (result != PDUMPER_LOAD_SUCCESS) 798 if (result != PDUMPER_LOAD_SUCCESS)
830 fatal ("could not load dump file \"%s\": %s", 799 fatal ("could not load dump file \"%s\": %s",
831 dump_file, dump_error_to_string (result)); 800 dump_file, dump_error_to_string (result));
832 else 801 return;
833 goto out;
834 } 802 }
835 803
836 /* Look for a dump file in the same directory as the executable; it 804 /* Look for a dump file in the same directory as the executable; it
@@ -839,44 +807,41 @@ load_pdump (int argc, char **argv)
839 so we can't use decode_env_path. We're working in whatever 807 so we can't use decode_env_path. We're working in whatever
840 encoding the system natively uses for filesystem access, so 808 encoding the system natively uses for filesystem access, so
841 there's no need for character set conversion. */ 809 there's no need for character set conversion. */
842 result = load_pdump_find_executable (argv[0], &exename); 810 ptrdiff_t bufsize;
843 if (result != PDUMPER_LOAD_SUCCESS) 811 dump_file = load_pdump_find_executable (argv[0], &bufsize);
844 goto out;
845 812
846 /* If we couldn't find our executable, go straight to looking for 813 /* If we couldn't find our executable, go straight to looking for
847 the dump in the hardcoded location. */ 814 the dump in the hardcoded location. */
848 if (exename) 815 if (dump_file && *dump_file)
849 { 816 {
850#ifdef WINDOWSNT 817#ifdef WINDOWSNT
851 /* w32_my_exename resolves symlinks internally, so no need to 818 /* w32_my_exename resolves symlinks internally, so no need to
852 call realpath. */ 819 call realpath. */
853 real_exename = exename;
854 exename = NULL;
855#else 820#else
856 real_exename = realpath (exename, NULL); 821 char *real_exename = realpath (dump_file, NULL);
857 if (!real_exename) 822 if (!real_exename)
858 fatal ("could not resolve realpath of \"%s\": %s", 823 fatal ("could not resolve realpath of \"%s\": %s",
859 exename, strerror (errno)); 824 dump_file, strerror (errno));
825 xfree (dump_file);
826 dump_file = real_exename;
827#endif
828 ptrdiff_t exenamelen = strlen (dump_file);
829#ifndef WINDOWSNT
830 bufsize = exenamelen + 1;
860#endif 831#endif
861 size_t real_exename_length = strlen (real_exename);
862 if (strip_suffix) 832 if (strip_suffix)
863 { 833 {
864 size_t strip_suffix_length = strlen (strip_suffix); 834 ptrdiff_t strip_suffix_length = strlen (strip_suffix);
865 if (real_exename_length >= strip_suffix_length) 835 ptrdiff_t prefix_length = exenamelen - strip_suffix_length;
866 { 836 if (0 <= prefix_length
867 size_t prefix_length = 837 && !memcmp (&dump_file[prefix_length], strip_suffix,
868 real_exename_length - strip_suffix_length; 838 strip_suffix_length))
869 if (!memcmp (&real_exename[prefix_length], 839 exenamelen = prefix_length;
870 strip_suffix,
871 strip_suffix_length))
872 real_exename_length = prefix_length;
873 }
874 } 840 }
875 dump_file = alloca (real_exename_length + strlen (suffix) + 1); 841 ptrdiff_t needed = exenamelen + strlen (suffix) + 1;
876 memcpy (dump_file, real_exename, real_exename_length); 842 if (bufsize < needed)
877 memcpy (dump_file + real_exename_length, 843 dump_file = xpalloc (dump_file, &bufsize, needed - bufsize, -1, 1);
878 suffix, 844 strcpy (dump_file + exenamelen, suffix);
879 strlen (suffix) + 1);
880 result = pdumper_load (dump_file); 845 result = pdumper_load (dump_file);
881 if (result == PDUMPER_LOAD_SUCCESS) 846 if (result == PDUMPER_LOAD_SUCCESS)
882 goto out; 847 goto out;
@@ -896,16 +861,19 @@ load_pdump (int argc, char **argv)
896 "emacs.pdmp" so that the Emacs binary still works if the user 861 "emacs.pdmp" so that the Emacs binary still works if the user
897 copies and renames it. */ 862 copies and renames it. */
898 const char *argv0_base = "emacs"; 863 const char *argv0_base = "emacs";
899 dump_file = alloca (strlen (path_exec) 864 ptrdiff_t needed = (strlen (path_exec)
900 + 1 865 + 1
901 + strlen (argv0_base) 866 + strlen (argv0_base)
902 + strlen (suffix) 867 + strlen (suffix)
903 + 1); 868 + 1);
869 if (bufsize < needed)
870 {
871 xfree (dump_file);
872 dump_file = xpalloc (NULL, &bufsize, needed - bufsize, -1, 1);
873 }
904 sprintf (dump_file, "%s%c%s%s", 874 sprintf (dump_file, "%s%c%s%s",
905 path_exec, DIRECTORY_SEP, argv0_base, suffix); 875 path_exec, DIRECTORY_SEP, argv0_base, suffix);
906 result = pdumper_load (dump_file); 876 result = pdumper_load (dump_file);
907 if (result == PDUMPER_LOAD_SUCCESS)
908 goto out;
909 877
910 if (result == PDUMPER_LOAD_FILE_NOT_FOUND) 878 if (result == PDUMPER_LOAD_FILE_NOT_FOUND)
911 { 879 {
@@ -920,13 +888,18 @@ load_pdump (int argc, char **argv)
920 last_sep = p; 888 last_sep = p;
921 } 889 }
922 argv0_base = last_sep ? last_sep + 1 : argv[0]; 890 argv0_base = last_sep ? last_sep + 1 : argv[0];
923 dump_file = alloca (strlen (path_exec) 891 ptrdiff_t needed = (strlen (path_exec)
924 + 1 892 + 1
925 + strlen (argv0_base) 893 + strlen (argv0_base)
926 + strlen (suffix) 894 + strlen (suffix)
927 + 1); 895 + 1);
896 if (bufsize < needed)
897 {
898 xfree (dump_file);
899 dump_file = xmalloc (needed);
900 }
928#ifdef DOS_NT 901#ifdef DOS_NT
929 size_t argv0_len = strlen (argv0_base); 902 ptrdiff_t argv0_len = strlen (argv0_base);
930 if (argv0_len >= 4 903 if (argv0_len >= 4
931 && c_strcasecmp (argv0_base + argv0_len - 4, ".exe") == 0) 904 && c_strcasecmp (argv0_base + argv0_len - 4, ".exe") == 0)
932 sprintf (dump_file, "%s%c%.*s%s", path_exec, DIRECTORY_SEP, 905 sprintf (dump_file, "%s%c%.*s%s", path_exec, DIRECTORY_SEP,
@@ -943,13 +916,10 @@ load_pdump (int argc, char **argv)
943 if (result != PDUMPER_LOAD_FILE_NOT_FOUND) 916 if (result != PDUMPER_LOAD_FILE_NOT_FOUND)
944 fatal ("could not load dump file \"%s\": %s", 917 fatal ("could not load dump file \"%s\": %s",
945 dump_file, dump_error_to_string (result)); 918 dump_file, dump_error_to_string (result));
946 dump_file = NULL;
947 } 919 }
948 920
949 out: 921 out:
950 free (exename); 922 xfree (dump_file);
951 free (real_exename);
952 return result;
953} 923}
954#endif /* HAVE_PDUMPER */ 924#endif /* HAVE_PDUMPER */
955 925
diff --git a/src/fileio.c b/src/fileio.c
index 968a55e5956..cbc0c89cf3e 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -150,7 +150,7 @@ check_existing (const char *filename)
150 150
151/* Return true if file FILENAME exists and can be executed. */ 151/* Return true if file FILENAME exists and can be executed. */
152 152
153static bool 153bool
154check_executable (char *filename) 154check_executable (char *filename)
155{ 155{
156 return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0; 156 return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0;
diff --git a/src/lisp.h b/src/lisp.h
index a7b19ab576e..024e5edb26e 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4298,6 +4298,7 @@ extern void syms_of_marker (void);
4298 4298
4299/* Defined in fileio.c. */ 4299/* Defined in fileio.c. */
4300 4300
4301extern bool check_executable (char *);
4301extern char *splice_dir_file (char *, char const *, char const *); 4302extern char *splice_dir_file (char *, char const *, char const *);
4302extern bool file_name_absolute_p (const char *); 4303extern bool file_name_absolute_p (const char *);
4303extern char const *get_homedir (void); 4304extern char const *get_homedir (void);
diff --git a/src/pdumper.c b/src/pdumper.c
index 98090238b1a..2e382145be2 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -5303,7 +5303,7 @@ enum dump_section
5303 5303
5304 N.B. We run very early in initialization, so we can't use lisp, 5304 N.B. We run very early in initialization, so we can't use lisp,
5305 unwinding, xmalloc, and so on. */ 5305 unwinding, xmalloc, and so on. */
5306enum pdumper_load_result 5306int
5307pdumper_load (const char *dump_filename) 5307pdumper_load (const char *dump_filename)
5308{ 5308{
5309 intptr_t dump_size; 5309 intptr_t dump_size;
@@ -5328,10 +5328,15 @@ pdumper_load (const char *dump_filename)
5328 /* We can load only one dump. */ 5328 /* We can load only one dump. */
5329 eassert (!dump_loaded_p ()); 5329 eassert (!dump_loaded_p ());
5330 5330
5331 enum pdumper_load_result err = PDUMPER_LOAD_FILE_NOT_FOUND; 5331 int err;
5332 int dump_fd = emacs_open (dump_filename, O_RDONLY, 0); 5332 int dump_fd = emacs_open (dump_filename, O_RDONLY, 0);
5333 if (dump_fd < 0) 5333 if (dump_fd < 0)
5334 goto out; 5334 {
5335 err = (errno == ENOENT || errno == ENOTDIR
5336 ? PDUMPER_LOAD_FILE_NOT_FOUND
5337 : PDUMPER_LOAD_ERROR + errno);
5338 goto out;
5339 }
5335 5340
5336 err = PDUMPER_LOAD_FILE_NOT_FOUND; 5341 err = PDUMPER_LOAD_FILE_NOT_FOUND;
5337 if (fstat (dump_fd, &stat) < 0) 5342 if (fstat (dump_fd, &stat) < 0)
diff --git a/src/pdumper.h b/src/pdumper.h
index 83c094f3caa..31b0d53b073 100644
--- a/src/pdumper.h
+++ b/src/pdumper.h
@@ -124,10 +124,10 @@ enum pdumper_load_result
124 PDUMPER_LOAD_FAILED_DUMP, 124 PDUMPER_LOAD_FAILED_DUMP,
125 PDUMPER_LOAD_OOM, 125 PDUMPER_LOAD_OOM,
126 PDUMPER_LOAD_VERSION_MISMATCH, 126 PDUMPER_LOAD_VERSION_MISMATCH,
127 PDUMPER_LOAD_ERROR, 127 PDUMPER_LOAD_ERROR /* Must be last, as errno may be added. */
128 }; 128 };
129 129
130enum pdumper_load_result pdumper_load (const char *dump_filename); 130int pdumper_load (const char *dump_filename);
131 131
132struct pdumper_loaded_dump 132struct pdumper_loaded_dump
133{ 133{