diff --git a/vndk/tools/header-checker/src/repr/json/ir_dumper.cpp b/vndk/tools/header-checker/src/repr/json/ir_dumper.cpp index 187a1183c..0b8f966a7 100644 --- a/vndk/tools/header-checker/src/repr/json/ir_dumper.cpp +++ b/vndk/tools/header-checker/src/repr/json/ir_dumper.cpp @@ -373,7 +373,7 @@ static std::string DumpJson(const JsonObject &obj) { return Json::writeString(factory, obj); } -static void WriteTailTrimmedLinesToFile(const std::string &path, +static bool WriteTailTrimmedLinesToFile(const std::string &path, const std::string &output_string) { std::ofstream output_file(path); size_t line_start = 0; @@ -389,19 +389,25 @@ static void WriteTailTrimmedLinesToFile(const std::string &path, } // Only write this line if this line contains non-whitespace characters. if (trailing_space_start != line_start) { - output_file.write(output_string.data() + line_start, - trailing_space_start - line_start); - output_file.write("\n", 1); + if (output_file + .write(output_string.data() + line_start, + trailing_space_start - line_start) + .fail()) { + return false; + } + if (output_file.write("\n", 1).fail()) { + return false; + } } line_start = index + 1; } + return output_file.flush().good(); } bool JsonIRDumper::Dump(const ModuleIR &module) { DumpModule(module); std::string output_string = DumpJson(translation_unit_); - WriteTailTrimmedLinesToFile(dump_path_, output_string); - return true; + return WriteTailTrimmedLinesToFile(dump_path_, output_string); } JsonIRDumper::JsonIRDumper(const std::string &dump_path) diff --git a/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp b/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp index ecc2ac37d..0dab87bf4 100644 --- a/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp +++ b/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp @@ -378,8 +378,13 @@ bool ProtobufIRDiffDumper::Dump() { GOOGLE_PROTOBUF_VERIFY_VERSION; assert(diff_tu_.get() != nullptr); std::ofstream text_output(dump_path_); - google::protobuf::io::OstreamOutputStream text_os(&text_output); - return google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os); + { + google::protobuf::io::OstreamOutputStream text_os(&text_output); + if (!google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os)) { + return false; + } + } + return text_output.flush().good(); } std::unique_ptr CreateProtobufIRDiffDumper( diff --git a/vndk/tools/header-checker/src/repr/protobuf/ir_dumper.cpp b/vndk/tools/header-checker/src/repr/protobuf/ir_dumper.cpp index 42123db3c..38b2adfa4 100644 --- a/vndk/tools/header-checker/src/repr/protobuf/ir_dumper.cpp +++ b/vndk/tools/header-checker/src/repr/protobuf/ir_dumper.cpp @@ -477,8 +477,13 @@ bool ProtobufIRDumper::Dump(const ModuleIR &module) { DumpModule(module); assert( tu_ptr_.get() != nullptr); std::ofstream text_output(dump_path_); - google::protobuf::io::OstreamOutputStream text_os(&text_output); - return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os); + { + google::protobuf::io::OstreamOutputStream text_os(&text_output); + if (!google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os)) { + return false; + } + } + return text_output.flush().good(); } std::unique_ptr CreateProtobufIRDumper(const std::string &dump_path) { diff --git a/vndk/tools/header-checker/tests/test.py b/vndk/tools/header-checker/tests/test.py index c99c08d29..26d15e3d1 100755 --- a/vndk/tools/header-checker/tests/test.py +++ b/vndk/tools/header-checker/tests/test.py @@ -2,6 +2,7 @@ import os import shutil +import stat import subprocess import sys import tempfile @@ -11,7 +12,8 @@ import_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) import_path = os.path.abspath(os.path.join(import_path, 'utils')) sys.path.insert(1, import_path) -from utils import run_abi_diff, run_header_abi_dumper +from utils import (run_abi_diff, run_and_read_abi_diff, run_header_abi_dumper, + run_header_abi_linker) from module import Module @@ -78,8 +80,8 @@ class HeaderCheckerTest(unittest.TestCase): def run_and_compare_abi_diff(self, old_dump, new_dump, lib, arch, expected_return_code, flags=[]): - return_code, output = run_abi_diff(old_dump, new_dump, arch, lib, - flags) + return_code, output = run_and_read_abi_diff( + old_dump, new_dump, arch, lib, flags) self.assertEqual(return_code, expected_return_code) return output @@ -488,6 +490,54 @@ class HeaderCheckerTest(unittest.TestCase): def test_enum_diff(self): self.prepare_and_absolute_diff_all_archs("libenum", "libenum") + def test_io_error(self): + cpp_path = os.path.join(self.get_tmp_dir(), "test.cpp") + sdump_path = os.path.join(self.get_tmp_dir(), "test.sdump") + version_script_path = os.path.join(self.get_tmp_dir(), "map.txt") + lsdump_path = os.path.join(self.get_tmp_dir(), "test.lsdump") + abidiff_path = os.path.join(self.get_tmp_dir(), "test.abidiff") + read_only_path = os.path.join(self.get_tmp_dir(), "read_only.txt") + + with open(cpp_path, "w") as cpp_file: + cpp_file.write("void func(int) {}") + with open(version_script_path, "w") as version_script_file: + pass + fd = os.open(read_only_path, flags=(os.O_CREAT | os.O_EXCL), + mode=(stat.S_IROTH | stat.S_IRGRP | stat.S_IRUSR)) + self.assertGreaterEqual(fd, 0) + os.close(fd) + + # Make sure that the commands are valid. + dumper_flags = ('-output-format', 'Json') + run_header_abi_dumper(cpp_path, sdump_path, flags=dumper_flags) + self.assertGreater(os.stat(sdump_path).st_size, 0) + linker_flags = ('-input-format', 'Json', + '-output-format', 'ProtobufTextFormat') + run_header_abi_linker([sdump_path], lsdump_path, version_script_path, + "current", "x86_64", linker_flags) + self.assertGreater(os.stat(lsdump_path).st_size, 0) + diff_flags = ('-input-format-old', 'ProtobufTextFormat', + '-input-format-new', 'ProtobufTextFormat') + return_code = run_abi_diff(lsdump_path, lsdump_path, abidiff_path, + 'x86_64', 'libtest', diff_flags) + self.assertEqual(return_code, 0) + self.assertGreater(os.stat(abidiff_path).st_size, 0) + + # Test with output error. + with self.assertRaises(subprocess.CalledProcessError) as assertion: + run_header_abi_dumper(cpp_path, read_only_path, flags=dumper_flags) + self.assertEqual(assertion.exception.returncode, 1) + + with self.assertRaises(subprocess.CalledProcessError) as assertion: + run_header_abi_linker([sdump_path], read_only_path, + version_script_path, "current", "x86_64", + linker_flags) + self.assertEqual(assertion.exception.returncode, 255) + + return_code = run_abi_diff(lsdump_path, lsdump_path, read_only_path, + 'x86_64', 'libtest', diff_flags) + self.assertEqual(return_code, 1) + if __name__ == '__main__': unittest.main() diff --git a/vndk/tools/header-checker/utils/utils.py b/vndk/tools/header-checker/utils/utils.py index 9f2b031d9..b2f48e9bd 100644 --- a/vndk/tools/header-checker/utils/utils.py +++ b/vndk/tools/header-checker/utils/utils.py @@ -293,25 +293,27 @@ def find_lib_lsdumps(lsdump_paths, libs, target): return [(tag, os.path.join(AOSP_DIR, path)) for tag, path in result] -def run_abi_diff(old_test_dump_path, new_test_dump_path, arch, lib_name, - flags=tuple()): - abi_diff_cmd = ['header-abi-diff', '-new', new_test_dump_path, '-old', - old_test_dump_path, '-arch', arch, '-lib', lib_name] +def run_abi_diff(old_dump_path, new_dump_path, output_path, arch, lib_name, + flags): + abi_diff_cmd = ['header-abi-diff', '-new', new_dump_path, '-old', + old_dump_path, '-arch', arch, '-lib', lib_name, + '-o', output_path] + abi_diff_cmd += flags + if '-input-format-old' not in flags: + abi_diff_cmd += ['-input-format-old', DEFAULT_FORMAT] + if '-input-format-new' not in flags: + abi_diff_cmd += ['-input-format-new', DEFAULT_FORMAT] + return subprocess.run(abi_diff_cmd).returncode + + +def run_and_read_abi_diff(old_dump_path, new_dump_path, arch, lib_name, + flags=tuple()): with tempfile.TemporaryDirectory() as tmp: output_name = os.path.join(tmp, lib_name) + '.abidiff' - abi_diff_cmd += ['-o', output_name] - abi_diff_cmd += flags - if '-input-format-old' not in flags: - abi_diff_cmd += ['-input-format-old', DEFAULT_FORMAT] - if '-input-format-new' not in flags: - abi_diff_cmd += ['-input-format-new', DEFAULT_FORMAT] - - result = subprocess.run(abi_diff_cmd) - output = "" - if os.path.isfile(output_name): - with open(output_name, 'r') as output_file: - output = output_file.read() - return result.returncode, output + result = run_abi_diff(old_dump_path, new_dump_path, output_name, arch, + lib_name, flags) + with open(output_name, 'r') as output_file: + return result, output_file.read() def get_build_vars_for_product(names, product=None, variant=None):