Disable direct mode if __{DATE,FILE,TIME}__ is used

This commit is contained in:
Joel Rosdahl 2010-04-25 17:03:23 +02:00
parent 6faf3267d2
commit 149d4912dc
6 changed files with 135 additions and 31 deletions

View File

@ -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)) {

View 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

View 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;
}

View 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

View 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);

35
test.sh
View File

@ -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