kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/verifier/verifier_main.cc (about) 1 /* 2 * Copyright 2014 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <sys/resource.h> 19 #include <unistd.h> 20 21 #include <string> 22 23 #include "absl/flags/flag.h" 24 #include "absl/flags/parse.h" 25 #include "absl/flags/usage.h" 26 #include "absl/log/log.h" 27 #include "absl/strings/str_format.h" 28 #include "absl/time/clock.h" 29 #include "absl/time/time.h" 30 #include "assertion_ast.h" 31 #include "google/protobuf/io/coded_stream.h" 32 #include "google/protobuf/io/zero_copy_stream.h" 33 #include "google/protobuf/io/zero_copy_stream_impl.h" 34 #include "kythe/cxx/common/init.h" 35 #include "kythe/proto/storage.pb.h" 36 #include "verifier.h" 37 38 ABSL_FLAG(bool, show_protos, false, 39 "Show protocol buffers read from standard in"); 40 ABSL_FLAG(bool, show_goals, false, "Show goals after parsing"); 41 ABSL_FLAG(bool, ignore_dups, false, 42 "Ignore duplicate facts during verification"); 43 ABSL_FLAG(bool, ignore_code_conflicts, false, 44 "Ignore conflicting /kythe/code facts during verification"); 45 ABSL_FLAG(bool, graphviz, false, 46 "Only dump facts as a GraphViz-compatible graph"); 47 ABSL_FLAG(bool, annotated_graphviz, false, 48 "Solve and annotate a GraphViz graph."); 49 ABSL_FLAG(bool, minimal_graphviz, false, 50 "Solve and dump a GraphViz graph eliding unused nodes."); 51 ABSL_FLAG(std::string, goal_prefix, "//-", "Denote goals with this string."); 52 ABSL_FLAG(bool, use_file_nodes, false, 53 "Look for assertions in UTF8 file nodes."); 54 ABSL_FLAG(bool, check_for_singletons, true, "Fail on singleton variables."); 55 ABSL_FLAG(std::string, goal_regex, "", 56 "If nonempty, denote goals with this regex. " 57 "The regex must match the entire line. Expects one capture group."); 58 ABSL_FLAG(bool, convert_marked_source, false, 59 "Convert MarkedSource-valued facts to subgraphs."); 60 ABSL_FLAG(bool, show_anchors, false, "Show anchor locations instead of @s"); 61 ABSL_FLAG(bool, show_vnames, true, 62 "Show VNames for nodes which also have labels."); 63 ABSL_FLAG(bool, show_fact_prefix, true, 64 "Include the /kythe or /kythe/edge prefix on facts and edges."); 65 ABSL_FLAG(bool, file_vnames, true, 66 "Find file vnames by matching file content."); 67 ABSL_FLAG(bool, allow_missing_file_vnames, false, 68 "If file_vnames is set, treat missing file vnames as non-fatal."); 69 ABSL_FLAG(bool, verbose, false, 70 "If verbose is set, more logging will be emitted."); 71 ABSL_FLAG(bool, use_fast_solver, true, "Use the fast solver."); 72 ABSL_FLAG(bool, print_timing_information, false, 73 "Print timing information for profiling."); 74 ABSL_FLAG(std::string, default_file_corpus, "", 75 "Use this corpus for anchor goals for file nodes without a corpus " 76 "set. In the future, if this flag is left empty, these file nodes " 77 "will raise an error."); 78 79 namespace { 80 // The fast solver needs extra stack space for modest programs. 81 constexpr rlim_t kSolverStack = 64L * 1024L * 1024L; 82 } // namespace 83 84 int main(int argc, char** argv) { 85 GOOGLE_PROTOBUF_VERIFY_VERSION; 86 kythe::InitializeProgram(argv[0]); 87 absl::SetProgramUsageMessage(R"(Verification tool for Kythe databases. 88 Reads Kythe facts from standard input and checks them against one or more rule 89 files. See https://kythe.io/docs/kythe-verifier.html for more details on 90 invocation and rule syntax. 91 92 Example: 93 ${INDEXER_BIN} -i $1 | ${VERIFIER_BIN} --show_protos --show_goals $1 94 cat foo.entries | ${VERIFIER_BIN} goals1.cc goals2.cc 95 cat foo.entries | ${VERIFIER_BIN} --use_file_nodes 96 )"); 97 auto start_time = absl::Now(); 98 std::vector<char*> remain = absl::ParseCommandLine(argc, argv); 99 100 kythe::verifier::Verifier v; 101 if (absl::GetFlag(FLAGS_goal_regex).empty()) { 102 v.SetGoalCommentPrefix(absl::GetFlag(FLAGS_goal_prefix)); 103 } else { 104 std::string error; 105 if (!v.SetGoalCommentRegex(absl::GetFlag(FLAGS_goal_regex), &error)) { 106 absl::FPrintF(stderr, "While parsing goal regex: %s\n", error); 107 return 1; 108 } 109 } 110 111 if (absl::GetFlag(FLAGS_ignore_dups)) { 112 v.IgnoreDuplicateFacts(); 113 } 114 115 if (absl::GetFlag(FLAGS_ignore_code_conflicts)) { 116 v.IgnoreCodeConflicts(); 117 } 118 119 if (absl::GetFlag(FLAGS_annotated_graphviz)) { 120 v.SaveEVarAssignments(); 121 } 122 123 if (absl::GetFlag(FLAGS_minimal_graphviz)) { 124 v.SaveEVarAssignments(); 125 v.ElideUnlabeled(); 126 } 127 128 if (absl::GetFlag(FLAGS_use_file_nodes)) { 129 v.UseFileNodes(); 130 } 131 132 if (absl::GetFlag(FLAGS_convert_marked_source)) { 133 v.ConvertMarkedSource(); 134 } 135 136 if (absl::GetFlag(FLAGS_show_anchors)) { 137 v.ShowAnchors(); 138 } 139 140 if (absl::GetFlag(FLAGS_show_vnames)) { 141 v.ShowLabeledVnames(); 142 } 143 144 if (!absl::GetFlag(FLAGS_file_vnames)) { 145 v.IgnoreFileVnames(); 146 } 147 148 if (absl::GetFlag(FLAGS_allow_missing_file_vnames)) { 149 if (!absl::GetFlag(FLAGS_file_vnames)) { 150 fprintf(stderr, "--allow_missing_file_vnames needs --file_vnames\n"); 151 return 1; 152 } 153 v.AllowMissingFileVNames(); 154 } 155 156 if (absl::GetFlag(FLAGS_verbose)) { 157 v.Verbose(); 158 } 159 160 if (absl::GetFlag(FLAGS_show_fact_prefix)) { 161 v.ShowFactPrefix(); 162 } 163 164 if (!absl::GetFlag(FLAGS_default_file_corpus).empty()) { 165 v.UseDefaultFileCorpus(absl::GetFlag(FLAGS_default_file_corpus)); 166 } 167 168 v.UseFastSolver(absl::GetFlag(FLAGS_use_fast_solver)); 169 170 if (absl::GetFlag(FLAGS_use_fast_solver)) { 171 struct rlimit rl; 172 int r = getrlimit(RLIMIT_STACK, &rl); 173 if (r != 0) { 174 perror("failed getting solver stack size"); 175 return 1; 176 } 177 if (rl.rlim_cur < kSolverStack) { 178 rl.rlim_cur = kSolverStack; 179 r = setrlimit(RLIMIT_STACK, &rl); 180 if (r != 0) { 181 perror("failed increasing solver stack size"); 182 return 1; 183 } 184 } 185 } 186 187 std::string dbname = "database"; 188 size_t facts = 0; 189 auto start_read_time = absl::Now(); 190 kythe::proto::Entry entry; 191 uint32_t byte_size; 192 google::protobuf::io::FileInputStream raw_input(STDIN_FILENO); 193 for (;;) { 194 google::protobuf::io::CodedInputStream coded_input(&raw_input); 195 coded_input.SetTotalBytesLimit(INT_MAX); 196 if (!coded_input.ReadVarint32(&byte_size)) { 197 break; 198 } 199 auto limit = coded_input.PushLimit(byte_size); 200 if (!entry.ParseFromCodedStream(&coded_input)) { 201 absl::FPrintF(stderr, "Error reading around fact %zu\n", facts); 202 return 1; 203 } 204 if (absl::GetFlag(FLAGS_show_protos)) { 205 entry.PrintDebugString(); 206 putchar('\n'); 207 } 208 if (!v.AssertSingleFact(&dbname, facts, entry)) { 209 absl::FPrintF(stderr, "Error asserting fact %zu\n", facts); 210 return 1; 211 } 212 ++facts; 213 } 214 auto done_read_time = absl::Now(); 215 216 if (!absl::GetFlag(FLAGS_use_fast_solver) && !v.PrepareDatabase()) { 217 return 1; 218 } 219 auto done_db_time = absl::Now(); 220 221 if (!absl::GetFlag(FLAGS_graphviz)) { 222 std::vector<std::string> rule_files(remain.begin() + 1, remain.end()); 223 if (rule_files.empty() && !absl::GetFlag(FLAGS_use_file_nodes)) { 224 absl::FPrintF(stderr, "No rule files specified\n"); 225 return 1; 226 } 227 228 for (const auto& rule_file : rule_files) { 229 if (rule_file.empty()) { 230 continue; 231 } 232 if (!v.LoadInlineRuleFile(rule_file)) { 233 absl::FPrintF(stderr, "Failed loading %s.\n", rule_file); 234 return 2; 235 } 236 } 237 } 238 239 if (absl::GetFlag(FLAGS_check_for_singletons) && v.CheckForSingletonEVars()) { 240 return 1; 241 } 242 243 if (absl::GetFlag(FLAGS_show_goals)) { 244 v.ShowGoals(); 245 } 246 247 int result = 0; 248 249 auto pre_solve_time = absl::Now(); 250 if (!v.VerifyAllGoals()) { 251 // Flush stdout in case any data is stuck in buffers, to avoid mangling a 252 // joined output stream. 253 fflush(stdout); 254 absl::FPrintF( 255 stderr, "Could not verify all goals. The furthest we reached was:\n "); 256 v.DumpErrorGoal(v.highest_group_reached(), v.highest_goal_reached()); 257 result = 1; 258 } 259 auto post_solve_time = absl::Now(); 260 261 if (absl::GetFlag(FLAGS_graphviz) || 262 absl::GetFlag(FLAGS_annotated_graphviz) || 263 absl::GetFlag(FLAGS_minimal_graphviz)) { 264 v.DumpAsDot(); 265 } 266 267 if (absl::GetFlag(FLAGS_print_timing_information)) { 268 auto print_timer = [](absl::Duration duration, absl::string_view name) { 269 absl::FPrintF(stderr, "%s took %ld msec\n", name, 270 absl::ToInt64Milliseconds(duration)); 271 }; 272 print_timer(start_read_time - start_time, "startup"); 273 print_timer(done_read_time - start_read_time, "read input stream"); 274 print_timer(done_db_time - done_read_time, "database preparation"); 275 print_timer(pre_solve_time - done_db_time, "other prep"); 276 print_timer(post_solve_time - pre_solve_time, "solve"); 277 print_timer(post_solve_time - start_time, "total elapsed"); 278 } 279 280 return result; 281 }