From: Joel Rosdahl Date: Sun, 25 Apr 2010 15:03:23 +0000 (+0200) Subject: Disable direct mode if __{DATE,FILE,TIME}__ is used X-Git-Tag: v3.0pre1~61 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=149d4912dcda693cade96f7da7bf41af92f3884d;p=thirdparty%2Fccache.git Disable direct mode if __{DATE,FILE,TIME}__ is used --- diff --git a/ccache.c b/ccache.c index 8a43519a7..1ce1513e4 100644 --- a/ccache.c +++ b/ccache.c @@ -288,7 +288,12 @@ static char *get_path_in_cache(const char *name, const char *suffix) return result; } -/* Takes over ownership of path. */ +/* + * This function hashes an include file and stores the path and hash in the + * global included_files variable. It also checks if the include file contains + * __DATE__/__FILE__/__TIME__ macros, in which case the file is not stored and + * direct mode is disabled. Takes over ownership of path. + */ static void remember_include_file(char *path, size_t path_len) { struct file_hash *h; @@ -296,6 +301,7 @@ static void remember_include_file(char *path, size_t path_len) struct stat st; int fd = -1; char *data = (char *)-1; + enum hash_source_code_result result; if (!included_files) { goto ignore; @@ -342,7 +348,16 @@ static void remember_include_file(char *path, size_t path_len) } hash_start(&fhash); - hash_include_file_string(&fhash, data, st.st_size); + result = hash_source_code_string(&fhash, data, st.st_size, 1); + switch (result) { + case HASH_SOURCE_CODE_OK: + break; + case HASH_SOURCE_CODE_FOUND_VOLATILE_MACRO: + cc_log("Found __DATE__/__FILE__/__TIME__ macro in %s", path); + /* Fall through. */ + case HASH_SOURCE_CODE_ERROR: + goto failure; + } h = x_malloc(sizeof(*h)); hash_result_as_bytes(&fhash, h->hash); @@ -354,8 +369,6 @@ static void remember_include_file(char *path, size_t path_len) failure: cc_log("Disabling direct mode"); enable_direct = 0; - hashtable_destroy(included_files, 1); - included_files = NULL; /* Fall through. */ ignore: free(path); @@ -386,10 +399,12 @@ static char *make_relative_path(char *path) /* * This function reads and hashes a file. While doing this, it also does these - * things with preprocessor lines starting with a hash: + * things: * - * - Makes include file paths whose prefix is CCACHE_BASEDIR relative. - * - Stores the paths of included files in the global variable included_files. + * - Makes include file paths whose prefix is CCACHE_BASEDIR relative when + * computing the hash sum. + * - Stores the paths and hashes of included files in the global variable + * included_files. */ static int process_preprocessed_file(struct mdfour *hash, const char *path) { @@ -746,6 +761,7 @@ static int find_hash(ARGS *args, enum findhash_call_mode mode) char *object_name; char *manifest_name; const char *compilercheck; + enum hash_source_code_result result; switch (mode) { case FINDHASH_DIRECT_MODE: @@ -860,9 +876,19 @@ static int find_hash(ARGS *args, enum findhash_call_mode mode) switch (mode) { case FINDHASH_DIRECT_MODE: - if (!hash_include_file(&hash, input_file)) { - cc_log("Failed to hash %s", input_file); + result = hash_source_code_file(&hash, input_file, 1); + switch (result) { + case HASH_SOURCE_CODE_OK: + break; + case HASH_SOURCE_CODE_ERROR: failed(); + break; + case HASH_SOURCE_CODE_FOUND_VOLATILE_MACRO: + cc_log("Found __DATE__/__FILE__/__TIME__ macro in %s", + input_file); + cc_log("Disabling direct mode"); + enable_direct = 0; + break; } manifest_name = hash_result(&hash); manifest_path = get_path_in_cache(manifest_name, ".manifest"); @@ -1046,7 +1072,8 @@ static void from_cache(enum fromcache_call_mode mode, int put_object_in_manifest } /* Create or update the manifest file. */ - if (put_object_in_manifest + if (enable_direct + && put_object_in_manifest && included_files && !getenv("CCACHE_READONLY")) { if (manifest_put(manifest_path, object_hash, included_files)) { diff --git a/ccache.txt b/ccache.txt index 91365c20b..6859c64aa 100644 --- a/ccache.txt +++ b/ccache.txt @@ -381,13 +381,14 @@ disabled), ccache falls back to the preprocessor mode. The direct mode will be disabled if any of the following holds: -* the environment variable CCACHE_NODIRECT is set +* the environment variable *CCACHE_NODIRECT* is set * a modification time of one of the include files is too new (needed to avoid a race condition) * the unifier is enabled (the environment variable *CCACHE_UNIFY* is set) -* a compiler option unsupported by the direct mode is used -** Currently, *-Wp,_X_* options are not supported, except if _X_ is - *-MD,_path_* or *-MMD,_path_*. +* a *-Wp,_X_* compiler option other than *-Wp,-MD,_path_* and *-Wp,-MMD,_path_* + is used +* a *\_\_DATE\_\_*, *\_\_FILE\_\_* or *\_\_TIME__* macro is used in the source + code THE PREPROCESSOR MODE diff --git a/hashutil.c b/hashutil.c index bf97eff6a..6f012962a 100644 --- a/hashutil.c +++ b/hashutil.c @@ -50,8 +50,15 @@ int file_hashes_equal(struct file_hash *fh1, struct file_hash *fh2) } \ } while (0) -void hash_include_file_string( - struct mdfour *hash, const char *str, size_t len) +/* + * Hash a string ignoring comments. If check_volatile_macros is true, also + * check for volatile preprocessor macros (__{DATE,FILE,TIME}__) and, if found, + * stop hashing. + */ +enum hash_source_code_result +hash_source_code_string( + struct mdfour *hash, const char *str, size_t len, + int check_volatile_macros) { const char *p; const char *end; @@ -115,6 +122,20 @@ void hash_include_file_string( } break; + /* Potential start of volatile macro. */ + case '_': + if (check_volatile_macros + && p + 7 < end + && p[1] == '_' + && p[6] == '_' + && p[7] == '_' + && (strncmp(p + 2, "DATE", 4) == 0 + || strncmp(p + 2, "FILE", 4) == 0 + || strncmp(p + 2, "TIME", 4) == 0)) { + return HASH_SOURCE_CODE_FOUND_VOLATILE_MACRO; + } + break; + default: break; } @@ -125,38 +146,45 @@ void hash_include_file_string( end: hash_buffer(hash, hashbuf, hashbuflen); + return HASH_SOURCE_CODE_OK; } /* - * Add contents of a file to a hash, but don't hash comments. Returns 1 on - * success, otherwise 0. + * Add contents of a source code file to a hash, but don't hash comments. */ -int hash_include_file(struct mdfour *hash, const char *path) +enum hash_source_code_result +hash_source_code_file( + struct mdfour *hash, const char *path, + int check_volatile_macros) { int fd; struct stat st; char *data; + enum hash_source_code_result result; - fd = open(path, O_RDONLY); + fd = open(path, O_RDONLY|O_BINARY); if (fd == -1) { - return 0; + cc_log("Failed to open %s", path); + return HASH_SOURCE_CODE_ERROR; } if (fstat(fd, &st) == -1) { + cc_log("Failed to fstat %s", path); close(fd); - return 0; + return HASH_SOURCE_CODE_ERROR; } if (st.st_size == 0) { close(fd); - return 1; + return HASH_SOURCE_CODE_OK; } data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); if (data == (void *)-1) { - return 0; + cc_log("Failed to mmap %s", path); + return HASH_SOURCE_CODE_ERROR; } - hash_include_file_string(hash, data, st.st_size); - + result = hash_source_code_string( + hash, data, st.st_size, check_volatile_macros); munmap(data, st.st_size); - return 1; + return result; } diff --git a/hashutil.h b/hashutil.h index 1696f79c0..96f11fc3c 100644 --- a/hashutil.h +++ b/hashutil.h @@ -14,8 +14,19 @@ unsigned int hash_from_string(void *str); int strings_equal(void *str1, void *str2); int file_hashes_equal(struct file_hash *fh1, struct file_hash *fh2); -void hash_include_file_string( - struct mdfour *hash, const char *str, size_t len); -int hash_include_file(struct mdfour *hash, const char *path); +enum hash_source_code_result { + HASH_SOURCE_CODE_OK, + HASH_SOURCE_CODE_ERROR, + HASH_SOURCE_CODE_FOUND_VOLATILE_MACRO +}; + +enum hash_source_code_result +hash_source_code_string( + struct mdfour *hash, const char *str, size_t len, + int check_volatile_macros); +enum hash_source_code_result +hash_source_code_file( + struct mdfour *hash, const char *path, + int check_volatile_macros); #endif diff --git a/manifest.c b/manifest.c index 9339d4751..c8d1de135 100644 --- a/manifest.c +++ b/manifest.c @@ -370,7 +370,9 @@ static int verify_object(struct manifest *mf, struct object *obj, if (!actual) { actual = x_malloc(sizeof(*actual)); hash_start(&hash); - if (!hash_include_file(&hash, mf->files[fi->index])) { + if (hash_source_code_file(&hash, mf->files[fi->index], + 0) + != HASH_SOURCE_CODE_OK) { cc_log("Failed hashing %s", mf->files[fi->index]); free(actual); diff --git a/test.sh b/test.sh index 08c5c8fb1..de6bd2d57 100755 --- a/test.sh +++ b/test.sh @@ -506,6 +506,7 @@ EOF test_failed "$dep_file missing" fi done + rm -rf test.dir ################################################################## # Check that -Wp,-MD,file.d works. @@ -774,6 +775,40 @@ EOF checkstat 'cache hit (preprocessed)' 0 checkstat 'cache miss' 1 + ################################################################## + # Check that direct mode is disabled if __DATE__, __FILE__ or __TIME__ + # macros are used. + for x in date file time; do + X=`echo $x | tr 'a-z' 'A-Z'` + testname="__${X}__ in source file" + $CCACHE -Cz >/dev/null + cat <$x.c +char $x[] = __${X}__; +EOF + $CCACHE $COMPILER -c $x.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c $x.c + checkstat 'cache hit (direct)' 0 + + testname="__${X}__ in include file" + $CCACHE -Cz >/dev/null + cat <$x.h +char $x[] = __${X}__; +EOF + backdate $x.h + cat <${x}_h.c +#include "$x.h" +EOF + $CCACHE $COMPILER -c ${x}_h.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c ${x}_h.c + checkstat 'cache hit (direct)' 0 + done + ################################################################## # Reset things. CCACHE_NODIRECT=1