diff options
| author | Paul Eggert | 2011-03-15 00:04:00 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-03-15 00:04:00 -0700 |
| commit | 15206ed9236f4957cb62a0cfbd5397cf8f0cb76b (patch) | |
| tree | c5b79dc24fd900342aaed46555ef28480014f502 /src | |
| parent | 4a6bea268fbac2fd64018374652f5b2c9b04b4fd (diff) | |
| download | emacs-15206ed9236f4957cb62a0cfbd5397cf8f0cb76b.tar.gz emacs-15206ed9236f4957cb62a0cfbd5397cf8f0cb76b.zip | |
Fix a race condition diagnosed by gcc -Wsequence-point (Bug#8254).
An expression of the form (DOWNCASE (x) == DOWNCASE (y)), found in
dired.c's scmp function, had undefined behavior.
* lisp.h (DOWNCASE_TABLE, UPCASE_TABLE, DOWNCASE, UPPERCASEP):
(NOCASEP, LOWERCASEP, UPCASE, UPCASE1): Move from here ...
* buffer.h: ... to here, because these macros use current_buffer,
and the new implementation with inline functions needs to have
current_buffer in scope now, rather than later when the macros
are used.
(downcase, upcase1): New static inline functions.
(DOWNCASE, UPCASE1): Reimplement using these functions.
This avoids undefined behavior in expressions like
DOWNCASE (x) == DOWNCASE (y), which previously suffered
from race conditions in accessing the global variables
case_temp1 and case_temp2.
* casetab.c (case_temp1, case_temp2): Remove; no longer needed.
* lisp.h (case_temp1, case_temp2): Remove their decls.
* character.h (ASCII_CHAR_P): Move from here ...
* lisp.h: ... to here, so that the inline functions mentioned
above can use them.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 21 | ||||
| -rw-r--r-- | src/buffer.h | 43 | ||||
| -rw-r--r-- | src/casetab.c | 6 | ||||
| -rw-r--r-- | src/character.h | 3 | ||||
| -rw-r--r-- | src/lisp.h | 47 |
5 files changed, 67 insertions, 53 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 7468af4c725..7e873e3d85d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,26 @@ | |||
| 1 | 2011-03-15 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2011-03-15 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Fix a race condition diagnosed by gcc -Wsequence-point (Bug#8254). | ||
| 4 | An expression of the form (DOWNCASE (x) == DOWNCASE (y)), found in | ||
| 5 | dired.c's scmp function, had undefined behavior. | ||
| 6 | * lisp.h (DOWNCASE_TABLE, UPCASE_TABLE, DOWNCASE, UPPERCASEP): | ||
| 7 | (NOCASEP, LOWERCASEP, UPCASE, UPCASE1): Move from here ... | ||
| 8 | * buffer.h: ... to here, because these macros use current_buffer, | ||
| 9 | and the new implementation with inline functions needs to have | ||
| 10 | current_buffer in scope now, rather than later when the macros | ||
| 11 | are used. | ||
| 12 | (downcase, upcase1): New static inline functions. | ||
| 13 | (DOWNCASE, UPCASE1): Reimplement using these functions. | ||
| 14 | This avoids undefined behavior in expressions like | ||
| 15 | DOWNCASE (x) == DOWNCASE (y), which previously suffered | ||
| 16 | from race conditions in accessing the global variables | ||
| 17 | case_temp1 and case_temp2. | ||
| 18 | * casetab.c (case_temp1, case_temp2): Remove; no longer needed. | ||
| 19 | * lisp.h (case_temp1, case_temp2): Remove their decls. | ||
| 20 | * character.h (ASCII_CHAR_P): Move from here ... | ||
| 21 | * lisp.h: ... to here, so that the inline functions mentioned | ||
| 22 | above can use them. | ||
| 23 | |||
| 3 | * dired.c (directory_files_internal_unwind): Now static. | 24 | * dired.c (directory_files_internal_unwind): Now static. |
| 4 | 25 | ||
| 5 | * fileio.c (file_name_as_directory, directory_file_name): | 26 | * fileio.c (file_name_as_directory, directory_file_name): |
diff --git a/src/buffer.h b/src/buffer.h index 0975d2e3adc..996e4e59c27 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
| @@ -1026,4 +1026,47 @@ extern int last_per_buffer_idx; | |||
| 1026 | 1026 | ||
| 1027 | #define PER_BUFFER_VALUE(BUFFER, OFFSET) \ | 1027 | #define PER_BUFFER_VALUE(BUFFER, OFFSET) \ |
| 1028 | (*(Lisp_Object *)((OFFSET) + (char *) (BUFFER))) | 1028 | (*(Lisp_Object *)((OFFSET) + (char *) (BUFFER))) |
| 1029 | |||
| 1030 | /* Current buffer's map from characters to lower-case characters. */ | ||
| 1031 | |||
| 1032 | #define DOWNCASE_TABLE BVAR (current_buffer, downcase_table) | ||
| 1033 | |||
| 1034 | /* Current buffer's map from characters to upper-case characters. */ | ||
| 1035 | |||
| 1036 | #define UPCASE_TABLE BVAR (current_buffer, upcase_table) | ||
| 1037 | |||
| 1038 | /* Downcase a character, or make no change if that cannot be done. */ | ||
| 1039 | |||
| 1040 | static inline EMACS_INT | ||
| 1041 | downcase (int ch) | ||
| 1042 | { | ||
| 1043 | Lisp_Object down = CHAR_TABLE_REF (DOWNCASE_TABLE, ch); | ||
| 1044 | return NATNUMP (down) ? XFASTINT (down) : ch; | ||
| 1045 | } | ||
| 1046 | #define DOWNCASE(CH) downcase (CH) | ||
| 1047 | |||
| 1048 | /* 1 if CH is upper case. */ | ||
| 1049 | |||
| 1050 | #define UPPERCASEP(CH) (DOWNCASE (CH) != (CH)) | ||
| 1029 | 1051 | ||
| 1052 | /* 1 if CH is neither upper nor lower case. */ | ||
| 1053 | |||
| 1054 | #define NOCASEP(CH) (UPCASE1 (CH) == (CH)) | ||
| 1055 | |||
| 1056 | /* 1 if CH is lower case. */ | ||
| 1057 | |||
| 1058 | #define LOWERCASEP(CH) (!UPPERCASEP (CH) && !NOCASEP(CH)) | ||
| 1059 | |||
| 1060 | /* Upcase a character, or make no change if that cannot be done. */ | ||
| 1061 | |||
| 1062 | #define UPCASE(CH) (!UPPERCASEP (CH) ? UPCASE1 (CH) : (CH)) | ||
| 1063 | |||
| 1064 | /* Upcase a character known to be not upper case. */ | ||
| 1065 | |||
| 1066 | static inline EMACS_INT | ||
| 1067 | upcase1 (int ch) | ||
| 1068 | { | ||
| 1069 | Lisp_Object up = CHAR_TABLE_REF (UPCASE_TABLE, ch); | ||
| 1070 | return NATNUMP (up) ? XFASTINT (up) : ch; | ||
| 1071 | } | ||
| 1072 | #define UPCASE1(CH) upcase1 (CH) | ||
diff --git a/src/casetab.c b/src/casetab.c index 5207e5315ae..56f6b065358 100644 --- a/src/casetab.c +++ b/src/casetab.c | |||
| @@ -28,11 +28,6 @@ Lisp_Object Qcase_table_p, Qcase_table; | |||
| 28 | Lisp_Object Vascii_downcase_table, Vascii_upcase_table; | 28 | Lisp_Object Vascii_downcase_table, Vascii_upcase_table; |
| 29 | Lisp_Object Vascii_canon_table, Vascii_eqv_table; | 29 | Lisp_Object Vascii_canon_table, Vascii_eqv_table; |
| 30 | 30 | ||
| 31 | /* Used as a temporary in DOWNCASE and other macros in lisp.h. No | ||
| 32 | need to mark it, since it is used only very temporarily. */ | ||
| 33 | int case_temp1; | ||
| 34 | Lisp_Object case_temp2; | ||
| 35 | |||
| 36 | static void set_canon (Lisp_Object case_table, Lisp_Object range, Lisp_Object elt); | 31 | static void set_canon (Lisp_Object case_table, Lisp_Object range, Lisp_Object elt); |
| 37 | static void set_identity (Lisp_Object table, Lisp_Object c, Lisp_Object elt); | 32 | static void set_identity (Lisp_Object table, Lisp_Object c, Lisp_Object elt); |
| 38 | static void shuffle (Lisp_Object table, Lisp_Object c, Lisp_Object elt); | 33 | static void shuffle (Lisp_Object table, Lisp_Object c, Lisp_Object elt); |
| @@ -302,4 +297,3 @@ syms_of_casetab (void) | |||
| 302 | defsubr (&Sset_case_table); | 297 | defsubr (&Sset_case_table); |
| 303 | defsubr (&Sset_standard_case_table); | 298 | defsubr (&Sset_standard_case_table); |
| 304 | } | 299 | } |
| 305 | |||
diff --git a/src/character.h b/src/character.h index d29ab41557b..6d5b8110109 100644 --- a/src/character.h +++ b/src/character.h | |||
| @@ -128,9 +128,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 128 | XSETCDR ((x), tmp); \ | 128 | XSETCDR ((x), tmp); \ |
| 129 | } while (0) | 129 | } while (0) |
| 130 | 130 | ||
| 131 | /* Nonzero iff C is an ASCII character. */ | ||
| 132 | #define ASCII_CHAR_P(c) ((unsigned) (c) < 0x80) | ||
| 133 | |||
| 134 | /* Nonzero iff C is a character of code less than 0x100. */ | 131 | /* Nonzero iff C is a character of code less than 0x100. */ |
| 135 | #define SINGLE_BYTE_CHAR_P(c) ((unsigned) (c) < 0x100) | 132 | #define SINGLE_BYTE_CHAR_P(c) ((unsigned) (c) < 0x100) |
| 136 | 133 | ||
diff --git a/src/lisp.h b/src/lisp.h index 3ba18186497..15c13e0467b 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -841,6 +841,9 @@ struct Lisp_Vector | |||
| 841 | 841 | ||
| 842 | #endif /* not __GNUC__ */ | 842 | #endif /* not __GNUC__ */ |
| 843 | 843 | ||
| 844 | /* Nonzero iff C is an ASCII character. */ | ||
| 845 | #define ASCII_CHAR_P(c) ((unsigned) (c) < 0x80) | ||
| 846 | |||
| 844 | /* Almost equivalent to Faref (CT, IDX) with optimization for ASCII | 847 | /* Almost equivalent to Faref (CT, IDX) with optimization for ASCII |
| 845 | characters. Do not check validity of CT. */ | 848 | characters. Do not check validity of CT. */ |
| 846 | #define CHAR_TABLE_REF(CT, IDX) \ | 849 | #define CHAR_TABLE_REF(CT, IDX) \ |
| @@ -2041,50 +2044,6 @@ extern int pending_signals; | |||
| 2041 | 2044 | ||
| 2042 | #define QUITP (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) | 2045 | #define QUITP (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) |
| 2043 | 2046 | ||
| 2044 | /* Variables used locally in the following case handling macros. */ | ||
| 2045 | extern int case_temp1; | ||
| 2046 | extern Lisp_Object case_temp2; | ||
| 2047 | |||
| 2048 | /* Current buffer's map from characters to lower-case characters. */ | ||
| 2049 | |||
| 2050 | #define DOWNCASE_TABLE BVAR (current_buffer, downcase_table) | ||
| 2051 | |||
| 2052 | /* Current buffer's map from characters to upper-case characters. */ | ||
| 2053 | |||
| 2054 | #define UPCASE_TABLE BVAR (current_buffer, upcase_table) | ||
| 2055 | |||
| 2056 | /* Downcase a character, or make no change if that cannot be done. */ | ||
| 2057 | |||
| 2058 | #define DOWNCASE(CH) \ | ||
| 2059 | ((case_temp1 = (CH), \ | ||
| 2060 | case_temp2 = CHAR_TABLE_REF (DOWNCASE_TABLE, case_temp1), \ | ||
| 2061 | NATNUMP (case_temp2)) \ | ||
| 2062 | ? XFASTINT (case_temp2) : case_temp1) | ||
| 2063 | |||
| 2064 | /* 1 if CH is upper case. */ | ||
| 2065 | |||
| 2066 | #define UPPERCASEP(CH) (DOWNCASE (CH) != (CH)) | ||
| 2067 | |||
| 2068 | /* 1 if CH is neither upper nor lower case. */ | ||
| 2069 | |||
| 2070 | #define NOCASEP(CH) (UPCASE1 (CH) == (CH)) | ||
| 2071 | |||
| 2072 | /* 1 if CH is lower case. */ | ||
| 2073 | |||
| 2074 | #define LOWERCASEP(CH) (!UPPERCASEP (CH) && !NOCASEP(CH)) | ||
| 2075 | |||
| 2076 | /* Upcase a character, or make no change if that cannot be done. */ | ||
| 2077 | |||
| 2078 | #define UPCASE(CH) (!UPPERCASEP (CH) ? UPCASE1 (CH) : (CH)) | ||
| 2079 | |||
| 2080 | /* Upcase a character known to be not upper case. */ | ||
| 2081 | |||
| 2082 | #define UPCASE1(CH) \ | ||
| 2083 | ((case_temp1 = (CH), \ | ||
| 2084 | case_temp2 = CHAR_TABLE_REF (UPCASE_TABLE, case_temp1), \ | ||
| 2085 | NATNUMP (case_temp2)) \ | ||
| 2086 | ? XFASTINT (case_temp2) : case_temp1) | ||
| 2087 | |||
| 2088 | extern Lisp_Object Vascii_downcase_table, Vascii_upcase_table; | 2047 | extern Lisp_Object Vascii_downcase_table, Vascii_upcase_table; |
| 2089 | extern Lisp_Object Vascii_canon_table, Vascii_eqv_table; | 2048 | extern Lisp_Object Vascii_canon_table, Vascii_eqv_table; |
| 2090 | 2049 | ||