@@ -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,128 @@ 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+ def test_errorlogger_sourcecache (tmpdir ):
4905+ header_pathname = os .path .join (tmpdir , 'header.h' )
4906+ file_1_pathname = os .path .join (tmpdir , 'file_1.c' )
4907+ file_2_pathname = os .path .join (tmpdir , 'file_2.c' )
4908+ file_3_pathname = os .path .join (tmpdir , 'file_3.c' )
4909+ output_pathname = os .path .join (tmpdir , 'out.txt' )
4910+
4911+ # Project setup that results in error paths
4912+ # spanning multiple files (ctuuninitvar)
4913+
4914+ header_content = """
4915+ int func_1(int *ptr);
4916+ int func_2(int *ptr);
4917+ """
4918+
4919+ file_1_content = f"""
4920+ #include "{ header_pathname } "
4921+
4922+ int func_1(int *ptr)
4923+ {{
4924+ return *ptr;
4925+ }}
4926+ """
4927+
4928+ file_2_content = f"""
4929+ #include "{ header_pathname } "
4930+
4931+ int func_2(int *ptr)
4932+ {{
4933+ return *ptr;
4934+ }}
4935+ """
4936+
4937+ file_3_content = f"""
4938+ #include "{ header_pathname } "
4939+
4940+ int func_3(void)
4941+ {{
4942+ int x, y;
4943+ return func_1(&x) + func_2(&y);
4944+ }}
4945+ """
4946+
4947+ with open (header_pathname , 'wt' ) as f :
4948+ f .write (header_content )
4949+
4950+ with open (file_1_pathname , 'wt' ) as f :
4951+ f .write (file_1_content )
4952+
4953+ with open (file_2_pathname , 'wt' ) as f :
4954+ f .write (file_2_content )
4955+
4956+ with open (file_3_pathname , 'wt' ) as f :
4957+ f .write (file_3_content )
4958+
4959+ cppcheck_path = __lookup_cppcheck_exe ()
4960+
4961+ args = [
4962+ 'strace' ,
4963+ '--summary-only' ,
4964+ '--summary-columns=count' ,
4965+ '--trace=openat' ,
4966+ '--follow-forks' ,
4967+ f'--trace-path={ file_1_pathname } ' ,
4968+ f'--trace-path={ file_2_pathname } ' ,
4969+ f'--trace-path={ file_3_pathname } ' ,
4970+ cppcheck_path ,
4971+ '-q' ,
4972+ '--enable=all' ,
4973+ f'--output-file={ output_pathname } ' ,
4974+ file_1_pathname ,
4975+ file_2_pathname ,
4976+ file_3_pathname ,
4977+ ]
4978+
4979+ proc = subprocess .Popen (args , stdout = subprocess .DEVNULL , stderr = subprocess .PIPE )
4980+ _ , strace_output = proc .communicate ()
4981+
4982+ expected_cppcheck_output = f"""{ file_1_pathname } :4:17: style: Parameter 'ptr' can be declared as pointer to const [constParameterPointer]
4983+ int func_1(int *ptr)
4984+ ^
4985+ { file_2_pathname } :4:17: style: Parameter 'ptr' can be declared as pointer to const [constParameterPointer]
4986+ int func_2(int *ptr)
4987+ ^
4988+ { file_1_pathname } :6:13: error: Using argument ptr that points at uninitialized variable x [ctuuninitvar]
4989+ return *ptr;
4990+ ^
4991+ { file_3_pathname } :7:18: note: Calling function func_1, 1st argument is uninitialized
4992+ return func_1(&x) + func_2(&y);
4993+ ^
4994+ { file_1_pathname } :6:13: note: Using argument ptr
4995+ return *ptr;
4996+ ^
4997+ { file_2_pathname } :6:13: error: Using argument ptr that points at uninitialized variable y [ctuuninitvar]
4998+ return *ptr;
4999+ ^
5000+ { file_3_pathname } :7:31: note: Calling function func_2, 1st argument is uninitialized
5001+ return func_1(&x) + func_2(&y);
5002+ ^
5003+ { file_2_pathname } :6:13: note: Using argument ptr
5004+ return *ptr;
5005+ ^
5006+ { file_3_pathname } :4:5: style: The function 'func_3' is never used. [unusedFunction]
5007+ int func_3(void)
5008+ ^
5009+ nofile:0:0: information: Active checkers: 114/188 (use --checkers-report=<filename> to see details) [checkersReport]
5010+
5011+ """
5012+
5013+ # Each source file is opened exactly twice: once for analysis,
5014+ # once for error reporting. If ErrorLogger::mSourceCacheSize
5015+ # is ever changed, this may have to be updated.
5016+ expected_strace_output = """ calls syscall
5017+ --------- ----------------
5018+ 6 openat
5019+ --------- ----------------
5020+ 6 total
5021+ """
5022+
5023+ with open (output_pathname , 'r' ) as f :
5024+ output_content = f .read ()
5025+
5026+ assert output_content == expected_cppcheck_output
5027+ assert strace_output .decode ('utf-8' ) == expected_strace_output
0 commit comments