From e5d479b06e74e04b3ef3108e6098424b2130cbe5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 4 Apr 2020 12:26:57 -0400 Subject: [PATCH] detect an endless loop when trying to detect native libc installation closes #4810 --- src-self-hosted/libc_installation.zig | 19 +++++++++++++++++++ src-self-hosted/stage2.zig | 2 ++ src/error.cpp | 1 + src/stage2.h | 1 + 4 files changed, 23 insertions(+) diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index f3441cec0d..db9db64a67 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -32,6 +32,7 @@ pub const LibCInstallation = struct { LibCKernel32LibNotFound, UnsupportedArchitecture, WindowsSdkNotFound, + ZigIsTheCCompiler, }; pub fn parse( @@ -229,10 +230,19 @@ pub const LibCInstallation = struct { "-xc", dev_null, }; + var env_map = try std.process.getEnvMap(allocator); + defer env_map.deinit(); + + // Detect infinite loops. + const inf_loop_env_key = "ZIG_IS_DETECTING_LIBC_PATHS"; + if (env_map.get(inf_loop_env_key) != null) return error.ZigIsTheCCompiler; + try env_map.set(inf_loop_env_key, "1"); + const exec_res = std.ChildProcess.exec(.{ .allocator = allocator, .argv = &argv, .max_output_bytes = 1024 * 1024, + .env_map = &env_map, // Some C compilers, such as Clang, are known to rely on argv[0] to find the path // to their own executable, without even bothering to resolve PATH. This results in the message: // error: unable to execute command: Executable "" doesn't exist! @@ -518,10 +528,19 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 { defer allocator.free(arg1); const argv = [_][]const u8{ cc_exe, arg1 }; + var env_map = try std.process.getEnvMap(allocator); + defer env_map.deinit(); + + // Detect infinite loops. + const inf_loop_env_key = "ZIG_IS_DETECTING_LIBC_PATHS"; + if (env_map.get(inf_loop_env_key) != null) return error.ZigIsTheCCompiler; + try env_map.set(inf_loop_env_key, "1"); + const exec_res = std.ChildProcess.exec(.{ .allocator = allocator, .argv = &argv, .max_output_bytes = 1024 * 1024, + .env_map = &env_map, // Some C compilers, such as Clang, are known to rely on argv[0] to find the path // to their own executable, without even bothering to resolve PATH. This results in the message: // error: unable to execute command: Executable "" doesn't exist! diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index bfc49a876b..3f96ff2110 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -115,6 +115,7 @@ const Error = extern enum { InvalidOperatingSystemVersion, UnknownClangOption, NestedResponseFile, + ZigIsTheCCompiler, }; const FILE = std.c.FILE; @@ -868,6 +869,7 @@ export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error { error.LibCKernel32LibNotFound => return .LibCKernel32LibNotFound, error.UnsupportedArchitecture => return .UnsupportedArchitecture, error.WindowsSdkNotFound => return .WindowsSdkNotFound, + error.ZigIsTheCCompiler => return .ZigIsTheCCompiler, }; stage1_libc.initFromStage2(libc); return .None; diff --git a/src/error.cpp b/src/error.cpp index 76b510ecf3..0ca7d25b79 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -85,6 +85,7 @@ const char *err_str(Error err) { case ErrorInvalidOperatingSystemVersion: return "invalid operating system version"; case ErrorUnknownClangOption: return "unknown Clang option"; case ErrorNestedResponseFile: return "nested response file"; + case ErrorZigIsTheCCompiler: return "Zig was not provided with libc installation information, and so it does not know where the libc paths are on the system. Zig attempted to use the system C compiler to find out where the libc paths are, but discovered that Zig is being used as the system C compiler."; } return "(invalid error)"; } diff --git a/src/stage2.h b/src/stage2.h index e397291f52..7dd2de988e 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -107,6 +107,7 @@ enum Error { ErrorInvalidOperatingSystemVersion, ErrorUnknownClangOption, ErrorNestedResponseFile, + ErrorZigIsTheCCompiler, }; // ABI warning