]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Disable direct mode if __{DATE,FILE,TIME}__ is used
authorJoel Rosdahl <joel@rosdahl.net>
Sun, 25 Apr 2010 15:03:23 +0000 (17:03 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sun, 25 Apr 2010 15:03:23 +0000 (17:03 +0200)
ccache.c
ccache.txt
hashutil.c
hashutil.h
manifest.c
test.sh

index 8a43519a734566cc4d28ce0290c10e0b6897b3fd..1ce1513e460ee269c9bc1c6d8607541697a56197 100644 (file)
--- 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)) {
index 91365c20b615b5dac32d226f6756090d115a66ea..6859c64aa9cf9b8b3e1959e0bd0ff08378fcef5d 100644 (file)
@@ -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
index bf97eff6a946b6bbb1cd2bf70aadabfae6efe8cb..6f012962a3818ad9a73935472aabaa082a66f090 100644 (file)
@@ -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;
 }
index 1696f79c0895358ffdd9b6f975b131f0a62cbaa6..96f11fc3c826d31e05331488b804aae27afa8175 100644 (file)
@@ -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
index 9339d47516332c7c93dc65294d4ffbd26e2922f2..c8d1de1357b1c521473cda75e01ce93d89f0edad 100644 (file)
@@ -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 08c5c8fb19eda5c7b10bf52ae6ea2a4568dfead7..de6bd2d570341325fbea8a09c789123ffa2dd239 100755 (executable)
--- 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 <<EOF >$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 <<EOF >$x.h
+char $x[] = __${X}__;
+EOF
+        backdate $x.h
+        cat <<EOF >${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