Skip to content

Commit 51262d9

Browse files
committed
[llvm-test-suite/utils] Add a simple not tool to the test suite
Add a tool similar to LLVM's not utility which inverts the return code of a command. The major difference is that the utility is not dependent on LLVM's libraries and performs less error checking than LLVM's not. It supports the --crash option when the command is expected to crash. The tests in Fortran/gfortran have been updated to use this.
1 parent c678caa commit 51262d9

File tree

3 files changed

+109
-13
lines changed

3 files changed

+109
-13
lines changed

Fortran/gfortran/CMakeLists.txt

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ function(gfortran_add_compile_test expect_error main others fflags ldflags)
445445
if (expect_error)
446446
# Since we don't check for any particular error, we expect "some" error.
447447
# In that case, the compiler's diagnostic output will be non-empty.
448-
llvm_test_verify(${TESTCMD} -s %S/${out})
448+
llvm_test_verify(%b/not ${DIFFPROG} %S/${relpath}/${EMPTY_FILE} %S/${out})
449449
else ()
450450
llvm_test_verify(${DIFFPROG} %S/${relpath}/${EMPTY_FILE} %S/${out})
451451
endif ()
@@ -658,22 +658,10 @@ get_filename_component(ISO_FORTRAN_C_HEADER_DIR
658658
# otherwise.
659659
set(DIFFPROG)
660660
if (WIN32)
661-
# Windows support has been disabled earlier anyway, but at some point, we
662-
# should find a way to check if a file is non-empty on windows.
663-
message(FATAL_ERROR "No way to check file size in Windows.")
664661
find_program(DIFFPROG
665662
NAMES fc.exe
666663
REQUIRED)
667664
else ()
668-
# FIXME: For the moment, check if a file is not empty, by using the test
669-
# command/shell built-in on *nix. But it is not clear that all systems will
670-
# have this. What we really need is to invert the result of DIFFPROG. LLVM has
671-
# a not utility that will do just this. But it needs LLVM's build directory
672-
# to be present unless it is installed on the system already. It is not clear
673-
# if we can depend on this.
674-
find_program(TESTCMD
675-
NAMES test
676-
REQUIRED)
677665
find_program(DIFFPROG
678666
NAMES diff cmp
679667
REQUIRED)

tools/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ else()
3939
add_executable(build-timeit-target ALIAS timeit-target)
4040
llvm_add_host_executable(build-timeit timeit timeit.c)
4141
endif()
42+
43+
add_executable(not ${CMAKE_CURRENT_SOURCE_DIR}/not.cpp)

tools/not.cpp

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//===- not.cpp - The 'not' testing tool -----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// Usage:
9+
// not cmd
10+
// Will return true if cmd doesn't crash and returns false.
11+
// not --crash cmd
12+
// Will return true if cmd crashes (e.g. for testing crash reporting).
13+
14+
// This file is a stripped down version of not.cpp from llvm/utils. This does
15+
// not depend on any LLVM library.
16+
17+
#include <cstdlib>
18+
#include <iostream>
19+
#include <sstream>
20+
21+
#ifdef _WIN32
22+
#define WIN32_LEAN_AND_MEAN
23+
#define NOMINMAX
24+
#include <windows.h>
25+
#endif
26+
27+
int main(int argc, const char **argv) {
28+
bool expectCrash = false;
29+
30+
++argv;
31+
--argc;
32+
33+
if (argc > 0 && std::string(argv[0]) == "--crash") {
34+
++argv;
35+
--argc;
36+
expectCrash = true;
37+
38+
// Crash is expected, so disable crash report and symbolization to reduce
39+
// output and avoid potentially slow symbolization.
40+
#ifdef _WIN32
41+
SetEnvironmentVariableA("LLVM_DISABLE_CRASH_REPORT", "1");
42+
SetEnvironmentVariableA("LLVM_DISABLE_SYMBOLIZATION", "1");
43+
#else
44+
setenv("LLVM_DISABLE_CRASH_REPORT", "1", 0);
45+
setenv("LLVM_DISABLE_SYMBOLIZATION", "1", 0);
46+
#endif
47+
}
48+
49+
if (argc == 0)
50+
return 1;
51+
52+
std::stringstream ss;
53+
ss << argv[0];
54+
for (int i = 1; i < argc; ++i)
55+
ss << " " << argv[i];
56+
std::string cmd = ss.str();
57+
58+
int result = std::system(cmd.c_str());
59+
int retcode = 0;
60+
int signal = 0;
61+
62+
#ifdef _WIN32
63+
// Handle abort() in msvcrt -- It has exit code as 3. abort(), aka
64+
// unreachable, should be recognized as a crash. However, some binaries use
65+
// exit code 3 on non-crash failure paths, so only do this if we expect a
66+
// crash.
67+
if (expectCrash && result == 3) {
68+
retcode = 3;
69+
signal = 1;
70+
} else if (errno) {
71+
// If the command interpreter was not found, errno will be set and 0 will
72+
// be returned. It is unlikely that this will happen in our use case, but
73+
// check anyway.
74+
retcode = 1;
75+
signal = 1;
76+
} else {
77+
// On Windows, result is the exit code, except for the special case above.
78+
retcode = result;
79+
signal = 0;
80+
}
81+
#elif defined(WEXITSTATUS) && defined(WTERMSIG)
82+
// On POSIX systems and Solaris, result is a composite value of the exit code
83+
// and, potentially, the signal that caused termination of the command.
84+
retcode = WEXITSTATUS(result);
85+
signal = WTERMSIG(result);
86+
#else
87+
#error "Unsupported system"
88+
#endif
89+
90+
// If signal is non-zero, the command caused a crash, usually SIGABRT.
91+
if (signal) {
92+
if (expectCrash)
93+
return EXIT_SUCCESS;
94+
return EXIT_FAILURE;
95+
}
96+
97+
// The command exited normally. If the command was expected to crash, return
98+
// EXIT_FAILURE since EXIT_SUCCESS is returned in the event of an expected
99+
// crash. Otherwise, invert the return code.
100+
if (expectCrash)
101+
return EXIT_FAILURE;
102+
else if (retcode == EXIT_SUCCESS)
103+
return EXIT_FAILURE;
104+
else
105+
return EXIT_SUCCESS;
106+
}

0 commit comments

Comments
 (0)