From bd0f0cc7fcfe61e5c80a2ac91af1b94dc153584f Mon Sep 17 00:00:00 2001 From: Andrzej Kotulski Date: Mon, 5 Dec 2016 05:07:20 -0800 Subject: [PATCH] [DB] Don't fail hard when realpath fails Summary: When infer runs on preprocessed source, original files may not be around anymore. Don't crash infer when that happens. Reviewed By: jvillard, jberdine Differential Revision: D4258285 fbshipit-source-id: a19569c --- infer/lib/python/inferlib/issues.py | 4 +--- infer/lib/python/inferlib/source.py | 3 +++ infer/src/backend/InferPrint.re | 16 +++----------- infer/src/base/DB.ml | 8 +++---- infer/src/base/Utils.ml | 21 ++++++++++++++----- .../codetoanalyze/preprocessed.c | 16 ++++++++++++++ .../tests/build_systems/preprocessed/Makefile | 18 ++++++++++++++++ .../build_systems/preprocessed/issues.exp | 1 + 8 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 infer/tests/build_systems/codetoanalyze/preprocessed.c create mode 100644 infer/tests/build_systems/preprocessed/Makefile create mode 100644 infer/tests/build_systems/preprocessed/issues.exp diff --git a/infer/lib/python/inferlib/issues.py b/infer/lib/python/inferlib/issues.py index 71a1e8a77..4168ca93d 100644 --- a/infer/lib/python/inferlib/issues.py +++ b/infer/lib/python/inferlib/issues.py @@ -171,10 +171,8 @@ def _text_of_report_list(project_root, reports, bugs_txt_path, limit=None, def _is_user_visible(project_root, report): - filename = report[JSON_INDEX_FILENAME] kind = report[JSON_INDEX_KIND] - return (os.path.isfile(os.path.join(project_root, filename)) and - kind in [ISSUE_KIND_ERROR, ISSUE_KIND_WARNING, ISSUE_KIND_ADVICE]) + return kind in [ISSUE_KIND_ERROR, ISSUE_KIND_WARNING, ISSUE_KIND_ADVICE] def print_and_save_errors(infer_out, project_root, json_report, bugs_out, diff --git a/infer/lib/python/inferlib/source.py b/infer/lib/python/inferlib/source.py index eb33c54f3..7eb57bf78 100644 --- a/infer/lib/python/inferlib/source.py +++ b/infer/lib/python/inferlib/source.py @@ -11,6 +11,7 @@ from __future__ import print_function from __future__ import unicode_literals import codecs +import os from . import colorize, config @@ -67,6 +68,8 @@ def build_source_context(source_name, mode, report_line): # get source excerpt line_number = 1 excerpt = '' + if not os.path.isfile(source_name): + return '' with codecs.open(source_name, 'r', encoding=config.CODESET, errors="replace") as source_file: # avoid going past the end of the file diff --git a/infer/src/backend/InferPrint.re b/infer/src/backend/InferPrint.re index 8e79e1a66..1cb375d82 100644 --- a/infer/src/backend/InferPrint.re +++ b/infer/src/backend/InferPrint.re @@ -386,13 +386,6 @@ let should_report (issue_kind: Exceptions.err_kind) issue_type error_desc => } }; -let is_file source_file => - switch (Unix.stat (DB.source_file_to_abs_path source_file)) { - | {st_kind: S_REG | S_LNK} => true - | _ => false - | exception Unix.Unix_error _ => false - }; - let module IssuesCsv = { let csv_issues_id = ref 0; let pp_header fmt () => @@ -427,8 +420,7 @@ let module IssuesCsv = { }; if ( in_footprint && - error_filter source_file error_desc error_name && - should_report ekind error_name error_desc && is_file source_file + error_filter source_file error_desc error_name && should_report ekind error_name error_desc ) { let err_desc_string = error_desc_to_csv_string error_desc; let err_advice_string = error_advice_to_csv_string error_desc; @@ -504,8 +496,7 @@ let module IssuesJson = { if ( in_footprint && error_filter source_file error_desc error_name && - should_report_source_file && - should_report ekind error_name error_desc && is_file source_file + should_report_source_file && should_report ekind error_name error_desc ) { let kind = Exceptions.err_kind_string ekind; let bug_type = Localise.to_string error_name; @@ -826,8 +817,7 @@ let module Stats = { let error_strs = { let pp1 fmt () => F.fprintf fmt "%d: %s" stats.nerrors type_str; let pp2 fmt () => - F.fprintf - fmt " %a:%d" DB.source_file_pp loc.Location.file loc.Location.line; + F.fprintf fmt " %a:%d" DB.source_file_pp loc.Location.file loc.Location.line; let pp3 fmt () => F.fprintf fmt " (%a)" Localise.pp_error_desc error_desc; [pp_to_string pp1 (), pp_to_string pp2 (), pp_to_string pp3 ()] }; diff --git a/infer/src/base/DB.ml b/infer/src/base/DB.ml index 3164e70e0..e3633fab8 100644 --- a/infer/src/base/DB.ml +++ b/infer/src/base/DB.ml @@ -48,14 +48,14 @@ let rel_path_from_abs_path root fname = else None (* The project root is not a prefix of the file name *) let source_file_from_abs_path fname = - (* IMPORTANT: results of realpath are cached to not ruin performance *) - let fname_real = realpath fname in - let project_root_real = realpath Config.project_root in - let models_dir_real = Config.models_src_dir in if Filename.is_relative fname then (failwithf "ERROR: Path %s is relative, when absolute path was expected .@." fname); + (* try to get realpath of source file. Use original if it fails *) + let fname_real = try realpath fname with Unix.Unix_error _ -> fname in + let project_root_real = realpath Config.project_root in + let models_dir_real = Config.models_src_dir in match rel_path_from_abs_path project_root_real fname_real with | Some path -> RelativeProjectRoot path | None -> ( diff --git a/infer/src/base/Utils.ml b/infer/src/base/Utils.ml index 35bf3d8e3..75d16097b 100644 --- a/infer/src/base/Utils.ml +++ b/infer/src/base/Utils.ml @@ -600,8 +600,19 @@ let rec create_path path = let realpath_cache = Hashtbl.create 1023 let realpath path = - try Hashtbl.find realpath_cache path - with Not_found -> - let realpath = Core.Std.Filename.realpath path in - Hashtbl.add realpath_cache path realpath; - realpath + match Hashtbl.find realpath_cache path with + | exception Not_found -> ( + match Core.Std.Filename.realpath path with + | realpath -> + Hashtbl.add realpath_cache path (Ok realpath); + realpath + | exception Unix.Unix_error (code, f, arg) -> + F.eprintf + "WARNING: Failed to resolve file %s with \"%s\" \n@." arg (Unix.error_message code); + (* cache failures as well *) + Hashtbl.add realpath_cache path (Error (code, f, arg)); + raise (Unix.Unix_error (code, f, arg)) + + ) + | Ok path -> path + | Error (code, f, arg) -> raise (Unix.Unix_error (code, f, arg)) diff --git a/infer/tests/build_systems/codetoanalyze/preprocessed.c b/infer/tests/build_systems/codetoanalyze/preprocessed.c new file mode 100644 index 000000000..a90e6a0ac --- /dev/null +++ b/infer/tests/build_systems/codetoanalyze/preprocessed.c @@ -0,0 +1,16 @@ +# 1 "/tmp/removed_src.c" +# 1 "" 1 +# 1 "" 3 +# 330 "" 3 +# 1 "" 1 +# 1 "" 2 +# 1 "/tmp/removed_src.c" 2 + +# 1 "/tmp/removed_header.h" 1 + +void fun(); +# 3 "/tmp/removed_src.c" 2 + +int deref(int* a) { return *a; } + +int test() { return deref(0); } diff --git a/infer/tests/build_systems/preprocessed/Makefile b/infer/tests/build_systems/preprocessed/Makefile new file mode 100644 index 000000000..48d99c115 --- /dev/null +++ b/infer/tests/build_systems/preprocessed/Makefile @@ -0,0 +1,18 @@ +# Copyright (c) 2016 - present Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. + +TESTS_DIR = ../.. + +ANALYZER = infer +CLANG_OPTIONS = -c +INFER_OPTIONS = --report-custom-error --developer-mode --headers --project-root ../codetoanalyze +INFERPRINT_OPTIONS = --issues-tests + +SOURCES = \ + ../codetoanalyze/preprocessed.c + +include $(TESTS_DIR)/clang.make diff --git a/infer/tests/build_systems/preprocessed/issues.exp b/infer/tests/build_systems/preprocessed/issues.exp new file mode 100644 index 000000000..2d99626da --- /dev/null +++ b/infer/tests/build_systems/preprocessed/issues.exp @@ -0,0 +1 @@ +/tmp/removed_src.c, test, 0, NULL_DEREFERENCE, [start of procedure test(),start of procedure deref()]