1 // Copyright (C) 2009-2016 Joel Rosdahl
3 // This program is free software; you can redistribute it and/or modify it
4 // under the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3 of the License, or (at your option)
8 // This program is distributed in the hope that it will be useful, but WITHOUT
9 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 // You should have received a copy of the GNU General Public License along with
14 // this program; if not, write to the Free Software Foundation, Inc., 51
15 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "macroskip.h"
20 #include "murmurhashneutral2.h"
23 hash_from_string(void *str)
25 return murmurhashneutral2(str, strlen((const char *)str), 0);
31 return murmurhashneutral2(&i, sizeof(int), 0);
35 strings_equal(void *str1, void *str2)
37 return str_eq((const char *)str1, (const char *)str2);
41 file_hashes_equal(struct file_hash *fh1, struct file_hash *fh2)
43 return memcmp(fh1->hash, fh2->hash, 16) == 0
44 && fh1->size == fh2->size;
47 // Search for the strings "__DATE__" and "__TIME__" in str.
49 // Returns a bitmask with HASH_SOURCE_CODE_FOUND_DATE and
50 // HASH_SOURCE_CODE_FOUND_TIME set appropriately.
52 check_for_temporal_macros(const char *str, size_t len)
56 // We're using the Boyer-Moore-Horspool algorithm, which searches starting
57 // from the *end* of the needle. Our needles are 8 characters long, so i
62 // Check whether the substring ending at str[i] has the form "__...E__". On
63 // the assumption that 'E' is less common in source than '_', we check
65 if (str[i - 2] == 'E' &&
70 // Check the remaining characters to see if the substring is "__DATE__"
72 if (str[i - 5] == 'D' && str[i - 4] == 'A' &&
74 result |= HASH_SOURCE_CODE_FOUND_DATE;
75 } else if (str[i - 5] == 'T' && str[i - 4] == 'I' &&
77 result |= HASH_SOURCE_CODE_FOUND_TIME;
81 // macro_skip tells us how far we can skip forward upon seeing str[i] at
82 // the end of a substring.
83 i += macro_skip[(uint8_t)str[i]];
89 // Hash a string. Returns a bitmask of HASH_SOURCE_CODE_* results.
91 hash_source_code_string(
92 struct conf *conf, struct mdfour *hash, const char *str, size_t len,
95 int result = HASH_SOURCE_CODE_OK;
97 // Check for __DATE__ and __TIME__ if the sloppiness configuration tells us
99 if (!(conf->sloppiness & SLOPPY_TIME_MACROS)) {
100 result |= check_for_temporal_macros(str, len);
103 // Hash the source string.
104 hash_buffer(hash, str, len);
106 if (result & HASH_SOURCE_CODE_FOUND_DATE) {
107 // Make sure that the hash sum changes if the (potential) expansion of
109 time_t t = time(NULL);
110 struct tm *now = localtime(&t);
111 cc_log("Found __DATE__ in %s", path);
112 hash_delimiter(hash, "date");
113 hash_buffer(hash, &now->tm_year, sizeof(now->tm_year));
114 hash_buffer(hash, &now->tm_mon, sizeof(now->tm_mon));
115 hash_buffer(hash, &now->tm_mday, sizeof(now->tm_mday));
117 if (result & HASH_SOURCE_CODE_FOUND_TIME) {
118 // We don't know for sure that the program actually uses the __TIME__
119 // macro, but we have to assume it anyway and hash the time stamp. However,
120 // that's not very useful since the chance that we get a cache hit later
121 // the same second should be quite slim... So, just signal back to the
122 // caller that __TIME__ has been found so that the direct mode can be
124 cc_log("Found __TIME__ in %s", path);
130 // Hash a file ignoring comments. Returns a bitmask of HASH_SOURCE_CODE_*
133 hash_source_code_file(struct conf *conf, struct mdfour *hash, const char *path)
135 if (is_precompiled_header(path)) {
136 if (hash_file(hash, path)) {
137 return HASH_SOURCE_CODE_OK;
139 return HASH_SOURCE_CODE_ERROR;
144 if (!read_file(path, 0, &data, &size)) {
145 return HASH_SOURCE_CODE_ERROR;
147 int result = hash_source_code_string(conf, hash, data, size, path);
154 hash_command_output(struct mdfour *hash, const char *command,
155 const char *compiler)
158 // Trim leading space.
159 while (isspace(*command)) {
163 // Add "echo" command.
165 if (str_startswith(command, "echo")) {
166 command = format("cmd.exe /c \"%s\"", command);
168 } else if (str_startswith(command,
169 "%compiler%") && str_eq(compiler, "echo")) {
170 command = format("cmd.exe /c \"%s%s\"", compiler, command + 10);
173 command = x_strdup(command);
178 struct args *args = args_init_from_string(command);
179 for (int i = 0; i < args->argc; i++) {
180 if (str_eq(args->argv[i], "%compiler%")) {
181 args_set(args, i, compiler);
184 cc_log_argv("Executing compiler check command ", args->argv);
187 PROCESS_INFORMATION pi;
188 memset(&pi, 0x00, sizeof(pi));
190 memset(&si, 0x00, sizeof(si));
192 char *path = find_executable(args->argv[0], NULL);
194 path = args->argv[0];
196 char *sh = win32getshell(path);
201 si.cb = sizeof(STARTUPINFO);
204 SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
205 CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0);
206 SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0);
207 si.hStdOutput = pipe_out[1];
208 si.hStdError = pipe_out[1];
209 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
210 si.dwFlags = STARTF_USESTDHANDLES;
214 win32args = win32argvtos(sh, args->argv);
216 win32args = (char *)command; // quoted
219 CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
220 CloseHandle(pipe_out[1]);
224 free((char *)command); // Original argument was replaced above.
227 stats_update(STATS_COMPCHECK);
230 int fd = _open_osfhandle((intptr_t) pipe_out[0], O_BINARY);
231 bool ok = hash_fd(hash, fd);
233 cc_log("Error hashing compiler check command output: %s", strerror(errno));
234 stats_update(STATS_COMPCHECK);
236 WaitForSingleObject(pi.hProcess, INFINITE);
238 GetExitCodeProcess(pi.hProcess, &exitcode);
239 CloseHandle(pipe_out[0]);
240 CloseHandle(pi.hProcess);
241 CloseHandle(pi.hThread);
243 cc_log("Compiler check command returned %d", (int) exitcode);
244 stats_update(STATS_COMPCHECK);
250 if (pipe(pipefd) == -1) {
251 fatal("pipe failed");
256 fatal("fork failed");
265 _exit(execvp(args->argv[0], args->argv));
266 return false; // Never reached.
271 bool ok = hash_fd(hash, pipefd[0]);
273 cc_log("Error hashing compiler check command output: %s", strerror(errno));
274 stats_update(STATS_COMPCHECK);
279 if (waitpid(pid, &status, 0) != pid) {
280 cc_log("waitpid failed");
283 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
284 cc_log("Compiler check command returned %d", WEXITSTATUS(status));
285 stats_update(STATS_COMPCHECK);
294 hash_multicommand_output(struct mdfour *hash, const char *commands,
295 const char *compiler)
297 char *command_string = x_strdup(commands);
298 char *p = command_string;
300 char *saveptr = NULL;
302 while ((command = strtok_r(p, ";", &saveptr))) {
303 if (!hash_command_output(hash, command, compiler)) {
308 free(command_string);