@@ -4863,23 +4863,19 @@ def test_ipc_inline_suppressions(tmp_path):
48634863 assert stdout_lines == stdout_exp
48644864 assert stderr .splitlines () == []
48654865
4866+ __strace_decorator = pytest .mark .skipif (sys .platform != 'linux' or 'ASAN_OPTIONS' in os .environ , reason = "uses strace" )
4867+
48664868test_redundant_file_reads_params = [
48674869 ([], 2 ),
48684870 (['--suppress=zerodiv' ], 1 ),
48694871 (['--template=cppcheck1' ], 1 ),
48704872 (['--xml' ], 1 ),
48714873]
48724874
4873- @pytest . mark . skipif ( sys . platform != 'linux' or 'ASAN_OPTIONS' in os . environ , reason = "uses strace" )
4875+ @__strace_decorator
48744876@pytest .mark .parametrize ('flags,expected' , test_redundant_file_reads_params )
48754877def test_redundant_file_reads (tmpdir , flags , expected ):
48764878 source_pathname = os .path .join (tmpdir , 'test.c' )
4877- content = """
4878- void f(int x) {
4879- int y = x / 0;
4880- int z = x / 0;
4881- }
4882- """
48834879 cppcheck_path = __lookup_cppcheck_exe ()
48844880
48854881 with open (source_pathname , 'wt' ) as f :
@@ -4904,3 +4900,129 @@ def test_redundant_file_reads(tmpdir, flags, expected):
49044900
49054901 assert proc .returncode == 0
49064902 assert stderr .splitlines ()[- 1 ].strip () == f'{ expected } total' .encode ('utf-8' )
4903+
4904+ @__strace_decorator
4905+ def test_errorlogger_sourcecache (tmpdir ):
4906+ header_pathname = os .path .join (tmpdir , 'header.h' )
4907+ file_1_pathname = os .path .join (tmpdir , 'file_1.c' )
4908+ file_2_pathname = os .path .join (tmpdir , 'file_2.c' )
4909+ file_3_pathname = os .path .join (tmpdir , 'file_3.c' )
4910+ output_pathname = os .path .join (tmpdir , 'out.txt' )
4911+
4912+ # Project setup that results in error paths
4913+ # spanning multiple files (ctuuninitvar)
4914+
4915+ header_content = """
4916+ int func_1(int *ptr);
4917+ int func_2(int *ptr);
4918+ """
4919+
4920+ file_1_content = f"""
4921+ #include "{ header_pathname } "
4922+
4923+ int func_1(int *ptr)
4924+ {{
4925+ return *ptr;
4926+ }}
4927+ """
4928+
4929+ file_2_content = f"""
4930+ #include "{ header_pathname } "
4931+
4932+ int func_2(int *ptr)
4933+ {{
4934+ return *ptr;
4935+ }}
4936+ """
4937+
4938+ file_3_content = f"""
4939+ #include "{ header_pathname } "
4940+
4941+ int func_3(void)
4942+ {{
4943+ int x, y;
4944+ return func_1(&x) + func_2(&y);
4945+ }}
4946+ """
4947+
4948+ with open (header_pathname , 'wt' ) as f :
4949+ f .write (header_content )
4950+
4951+ with open (file_1_pathname , 'wt' ) as f :
4952+ f .write (file_1_content )
4953+
4954+ with open (file_2_pathname , 'wt' ) as f :
4955+ f .write (file_2_content )
4956+
4957+ with open (file_3_pathname , 'wt' ) as f :
4958+ f .write (file_3_content )
4959+
4960+ cppcheck_path = __lookup_cppcheck_exe ()
4961+
4962+ args = [
4963+ 'strace' ,
4964+ '--summary-only' ,
4965+ '--summary-columns=count' ,
4966+ '--trace=openat' ,
4967+ '--follow-forks' ,
4968+ f'--trace-path={ file_1_pathname } ' ,
4969+ f'--trace-path={ file_2_pathname } ' ,
4970+ f'--trace-path={ file_3_pathname } ' ,
4971+ cppcheck_path ,
4972+ '-q' ,
4973+ '--enable=all' ,
4974+ f'--output-file={ output_pathname } ' ,
4975+ file_1_pathname ,
4976+ file_2_pathname ,
4977+ file_3_pathname ,
4978+ ]
4979+
4980+ proc = subprocess .Popen (args , stdout = subprocess .DEVNULL , stderr = subprocess .PIPE )
4981+ _ , strace_output = proc .communicate ()
4982+
4983+ expected_cppcheck_output = f"""{ file_1_pathname } :4:17: style: Parameter 'ptr' can be declared as pointer to const [constParameterPointer]
4984+ int func_1(int *ptr)
4985+ ^
4986+ { file_2_pathname } :4:17: style: Parameter 'ptr' can be declared as pointer to const [constParameterPointer]
4987+ int func_2(int *ptr)
4988+ ^
4989+ { file_1_pathname } :6:13: error: Using argument ptr that points at uninitialized variable x [ctuuninitvar]
4990+ return *ptr;
4991+ ^
4992+ { file_3_pathname } :7:18: note: Calling function func_1, 1st argument is uninitialized
4993+ return func_1(&x) + func_2(&y);
4994+ ^
4995+ { file_1_pathname } :6:13: note: Using argument ptr
4996+ return *ptr;
4997+ ^
4998+ { file_2_pathname } :6:13: error: Using argument ptr that points at uninitialized variable y [ctuuninitvar]
4999+ return *ptr;
5000+ ^
5001+ { file_3_pathname } :7:31: note: Calling function func_2, 1st argument is uninitialized
5002+ return func_1(&x) + func_2(&y);
5003+ ^
5004+ { file_2_pathname } :6:13: note: Using argument ptr
5005+ return *ptr;
5006+ ^
5007+ { file_3_pathname } :4:5: style: The function 'func_3' is never used. [unusedFunction]
5008+ int func_3(void)
5009+ ^
5010+ nofile:0:0: information: Active checkers: 114/188 (use --checkers-report=<filename> to see details) [checkersReport]
5011+
5012+ """
5013+
5014+ # Each source file is opened exactly twice: once for analysis,
5015+ # once for error reporting. If ErrorLogger::mSourceCacheSize
5016+ # is ever changed, this may have to be updated.
5017+ expected_strace_output = """ calls syscall
5018+ --------- ----------------
5019+ 6 openat
5020+ --------- ----------------
5021+ 6 total
5022+ """
5023+
5024+ with open (output_pathname , 'r' ) as f :
5025+ output_content = f .read ()
5026+
5027+ assert output_content == expected_cppcheck_output
5028+ assert strace_output .decode ('utf-8' ) == expected_strace_output
0 commit comments