()
| 257 | |
| 258 | |
| 259 | def main(): |
| 260 | parser = argparse.ArgumentParser(description="This program checks that the number of arguments passed " |
| 261 | "to a variadic format string function matches the number of format " |
| 262 | "specifiers in the format string.") |
| 263 | parser.add_argument("--skip-arguments", type=int, help="number of arguments before the format string " |
| 264 | "argument (e.g. 1 in the case of fprintf)", default=0) |
| 265 | parser.add_argument("function_name", help="function name (e.g. fprintf)", default=None) |
| 266 | parser.add_argument("file", nargs="*", help="C++ source code file (e.g. foo.cpp)") |
| 267 | args = parser.parse_args() |
| 268 | exit_code = 0 |
| 269 | for filename in args.file: |
| 270 | with open(filename, "r", encoding="utf-8") as f: |
| 271 | for function_call_str in parse_function_calls(args.function_name, f.read()): |
| 272 | parts = parse_function_call_and_arguments(args.function_name, function_call_str) |
| 273 | relevant_function_call_str = unescape("".join(parts))[:512] |
| 274 | if (f.name, relevant_function_call_str) in FALSE_POSITIVES: |
| 275 | continue |
| 276 | if len(parts) < 3 + args.skip_arguments: |
| 277 | exit_code = 1 |
| 278 | print("{}: Could not parse function call string \"{}(...)\": {}".format(f.name, args.function_name, relevant_function_call_str)) |
| 279 | continue |
| 280 | argument_count = len(parts) - 3 - args.skip_arguments |
| 281 | format_str = parse_string_content(parts[1 + args.skip_arguments]) |
| 282 | format_specifier_count = count_format_specifiers(format_str) |
| 283 | if format_specifier_count != argument_count: |
| 284 | exit_code = 1 |
| 285 | print("{}: Expected {} argument(s) after format string but found {} argument(s): {}".format(f.name, format_specifier_count, argument_count, relevant_function_call_str)) |
| 286 | continue |
| 287 | sys.exit(exit_code) |
| 288 | |
| 289 | |
| 290 | if __name__ == "__main__": |
no test coverage detected