Skip to content

Commit c6f5e62

Browse files
committed
CMD: add cmdline options to choose analysis
1 parent 32fa1c8 commit c6f5e62

File tree

5 files changed

+171
-25
lines changed

5 files changed

+171
-25
lines changed

chc/cmdline/AnalysisManager.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,14 @@ class AnalysisManager:
4949
"""Provide the interface to the codehawk (ocaml) analyzer."""
5050

5151
def __init__(
52-
self,
53-
capp: "CApplication",
54-
wordsize: int = 0,
55-
unreachability: bool = False,
56-
thirdpartysummaries: List[str] = [],
57-
keep_system_includes: bool = False,
58-
verbose: bool = False,
52+
self,
53+
capp: "CApplication",
54+
wordsize: int = 0,
55+
unreachability: bool = False,
56+
thirdpartysummaries: List[str] = [],
57+
keep_system_includes: bool = False,
58+
verbose: bool = False,
59+
collectdiagnostics: bool = False
5960
) -> None:
6061
"""Initialize the analyzer location and target file location.
6162
@@ -78,6 +79,7 @@ def __init__(
7879
self.thirdpartysummaries = thirdpartysummaries
7980
self.unreachability = unreachability
8081
self.verbose = verbose
82+
self._collectdiagnostics = collectdiagnostics
8183

8284
@property
8385
def capp(self) -> "CApplication":
@@ -87,6 +89,10 @@ def capp(self) -> "CApplication":
8789
def keep_system_includes(self) -> bool:
8890
return self._keep_system_includes
8991

92+
@property
93+
def collect_diagnostics(self) -> bool:
94+
return self._collectdiagnostics
95+
9096
@property
9197
def contractpath(self) -> Optional[str]:
9298
return self.capp.contractpath
@@ -178,9 +184,11 @@ def _execute_cmd(self, CMD: List[str]) -> None:
178184
print(args)
179185
exit(1)
180186

181-
def _create_file_primary_proofobligations_cmd_partial(self) -> List[str]:
187+
def _create_file_primary_proofobligations_cmd_partial(
188+
self, po_cmd="undefined-behavior-primary"
189+
) -> List[str]:
182190
cmd: List[str] = [
183-
self.canalyzer, "-summaries", self.chsummaries, "-command", "primary"]
191+
self.canalyzer, "-summaries", self.chsummaries, "-command", po_cmd]
184192
if not (self.thirdpartysummaries is None):
185193
for s in self.thirdpartysummaries:
186194
cmd.extend(["-summaries", s])
@@ -192,19 +200,26 @@ def _create_file_primary_proofobligations_cmd_partial(self) -> List[str]:
192200
cmd.append("-keep_system_includes")
193201
if self.wordsize > 0:
194202
cmd.extend(["-wordsize", str(self.wordsize)])
203+
if self.collect_diagnostics:
204+
cmd.append("-diagnostics")
195205
cmd.append(self.targetpath)
196206
cmd.append("-cfilename")
197207
return cmd
198208

199209
def create_file_primary_proofobligations(
200-
self, cfilename: str, cfilepath: Optional[str] = None) -> None:
210+
self,
211+
cfilename: str,
212+
cfilepath: Optional[str] = None,
213+
po_cmd: str = "undefined-behavior-primary"
214+
) -> None:
201215
"""Call analyzer to create primary proof obligations for a single file."""
202216

203217
chklogger.logger.info(
204218
"Create primiary proof obligations for file %s with path %s",
205219
cfilename, ("none" if cfilepath is None else cfilepath))
206220
try:
207-
cmd = self._create_file_primary_proofobligations_cmd_partial()
221+
cmd = self._create_file_primary_proofobligations_cmd_partial(
222+
po_cmd=po_cmd)
208223
cmd.append(cfilename)
209224
if cfilepath is not None:
210225
cmd.extend(["-cfilepath", cfilepath])
@@ -237,13 +252,17 @@ def create_file_primary_proofobligations(
237252
print(args)
238253
exit(1)
239254

240-
def create_app_primary_proofobligations(self, processes: int = 1) -> None:
255+
def create_app_primary_proofobligations(
256+
self,
257+
po_cmd: str = "undefined-behavior-primary",
258+
processes: int = 1) -> None:
241259
"""Call analyzer to create ppo's for all application files."""
242260

243261
if processes > 1:
244262

245263
def f(cfile: "CFile") -> None:
246-
cmd = self._create_file_primary_proofobligations_cmd_partial()
264+
cmd = self._create_file_primary_proofobligations_cmd_partial(
265+
po_cmd=po_cmd)
247266
cmd.append(cfile.cfilename)
248267
if cfile.cfilepath is not None:
249268
cmd.extend(["-cfilepath", cfile.cfilepath])
@@ -290,6 +309,8 @@ def _generate_and_check_file_cmd_partial(
290309
cmd.append("-unreachability")
291310
if self.verbose:
292311
cmd.append("-verbose")
312+
if self.collect_diagnostics:
313+
cmd.append("-diagnostics")
293314
cmd.append(self.targetpath)
294315
if cfilepath is not None:
295316
cmd.extend(["-cfilepath", cfilepath])
@@ -317,7 +338,7 @@ def generate_and_check_file(
317338
result = subprocess.call(
318339
cmd,
319340
cwd=self.targetpath,
320-
stdout=open(os.devnull, "w"),
341+
# stdout=open(os.devnull, "w"),
321342
stderr=subprocess.STDOUT,
322343
)
323344
if result != 0:

chc/cmdline/c_file/cfileutil.py

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
from chc.app.CApplication import CApplication
6767
from chc.app.CPrettyPrinter import CPrettyPrinter
6868

69+
from chc.proof.OutputParameterChecker import OutputParameterChecker
70+
6971
import chc.reporting.ProofObligations as RP
7072

7173
from chc.util.Config import Config
@@ -421,7 +423,10 @@ def cfile_analyze_file(args: argparse.Namespace) -> NoReturn:
421423
opttgtpath: Optional[str] = args.tgtpath
422424
wordsize: int = args.wordsize
423425
keep_system_includes: bool = args.keep_system_includes
426+
analysis: str = args.analysis
424427
verbose: bool = args.verbose
428+
analysisdomains: str = args.analysis_domains
429+
collectdiagnostics: bool = args.collect_diagnostics
425430
loglevel: str = args.loglevel
426431
logfilename: Optional[str] = args.logfilename
427432
logfilemode: str = args.logfilemode
@@ -433,6 +438,8 @@ def cfile_analyze_file(args: argparse.Namespace) -> NoReturn:
433438
cfilename = cfilename_ext[:-2]
434439
projectname = cfilename
435440

441+
po_cmd = analysis + "-primary"
442+
436443
set_logging(
437444
loglevel,
438445
targetpath,
@@ -484,20 +491,21 @@ def cfile_analyze_file(args: argparse.Namespace) -> NoReturn:
484491
am = AnalysisManager(
485492
capp,
486493
verbose=verbose,
494+
collectdiagnostics=collectdiagnostics,
487495
wordsize=wordsize,
488496
keep_system_includes=keep_system_includes)
489497

490-
am.create_file_primary_proofobligations(cfilename)
498+
am.create_file_primary_proofobligations(cfilename, po_cmd=po_cmd)
491499
am.reset_tables(cfile)
492500
capp.collect_post_assumes()
493501

494-
am.generate_and_check_file(cfilename, None, "llrvisp")
502+
am.generate_and_check_file(cfilename, None, analysisdomains)
495503
am.reset_tables(cfile)
496504
capp.collect_post_assumes()
497505

498506
for k in range(5):
499507
capp.update_spos()
500-
am.generate_and_check_file(cfilename, None, "llrvisp")
508+
am.generate_and_check_file(cfilename, None, analysisdomains)
501509
am.reset_tables(cfile)
502510

503511
chklogger.logger.info("cfile analyze completed")
@@ -518,6 +526,7 @@ def cfile_report_file(args: argparse.Namespace) -> NoReturn:
518526
# arguments
519527
xcfilename: str = args.filename
520528
opttgtpath: Optional[str] = args.tgtpath
529+
canalysis: str = args.analysis
521530
cshowcode: bool = args.showcode
522531
cshowinvariants: bool = args.showinvariants
523532
cfunctions: Optional[List[str]] = args.functions
@@ -573,6 +582,16 @@ def pofilter(po: "CFunctionPO") -> bool:
573582
cfile, pofilter=pofilter, showinvs=cshowinvariants))
574583

575584
print(RP.file_proofobligation_stats_tostring(cfile))
585+
586+
if canalysis == "outputparameters":
587+
for cfun in cfile.functions.values():
588+
try:
589+
op_checker = OutputParameterChecker(cfun)
590+
print(str(op_checker))
591+
except UF.CHCError as e:
592+
print("Skipping function " + cfun.name)
593+
continue
594+
576595
exit(0)
577596

578597
for fnname in cfunctions:
@@ -591,6 +610,9 @@ def cfile_run_file(args: argparse.Namespace) -> NoReturn:
591610
pcfilename: str = os.path.abspath(args.filename)
592611
opttgtpath: Optional[str] = args.tgtpath
593612
keep_system_includes: bool = args.keep_system_includes
613+
analysis: str = args.analysis
614+
analysisdomains: str = args.analysis_domains
615+
collectdiagnostics: bool = args.collect_diagnostics
594616
cshowcode: bool = args.showcode
595617
copen: bool = args.open
596618
cshowinvariants: bool = args.showinvariants
@@ -622,6 +644,8 @@ def cfile_run_file(args: argparse.Namespace) -> NoReturn:
622644
cfilename = cfilename_c[:-2]
623645
projectname = cfilename
624646

647+
po_cmd = analysis + "-primary"
648+
625649
if not os.path.isdir(targetpath):
626650
print_error("Target directory: " + targetpath + " does not exist")
627651
exit(1)
@@ -696,19 +720,23 @@ def cfile_run_file(args: argparse.Namespace) -> NoReturn:
696720
capp.initialize_single_file(cfilename)
697721
cfile = capp.get_cfile()
698722

699-
am = AnalysisManager(capp, verbose=verbose)
723+
am = AnalysisManager(
724+
capp,
725+
verbose=verbose,
726+
collectdiagnostics=collectdiagnostics,
727+
keep_system_includes=keep_system_includes)
700728

701-
am.create_file_primary_proofobligations(cfilename)
729+
am.create_file_primary_proofobligations(cfilename, po_cmd=po_cmd)
702730
am.reset_tables(cfile)
703731
capp.collect_post_assumes()
704732

705-
am.generate_and_check_file(cfilename, None, "llrvisp")
733+
am.generate_and_check_file(cfilename, None, analysisdomains)
706734
am.reset_tables(cfile)
707735
capp.collect_post_assumes()
708736

709737
for k in range(5):
710738
capp.update_spos()
711-
am.generate_and_check_file(cfilename, None, "llrvisp")
739+
am.generate_and_check_file(cfilename, None, analysisdomains)
712740
am.reset_tables(cfile)
713741

714742
chklogger.logger.info("cfile analyze completed")
@@ -745,6 +773,16 @@ def pofilter(po: "CFunctionPO") -> bool:
745773
cfile, pofilter=pofilter, showinvs=cshowinvariants))
746774

747775
print(RP.file_proofobligation_stats_tostring(cfile))
776+
777+
if analysis == "outputparameters":
778+
for cfun in cfile.functions.values():
779+
try:
780+
op_checker = OutputParameterChecker(cfun)
781+
print(str(op_checker))
782+
except UF.CHCError as e:
783+
print("Skipping function " + cfun.name + ": " + str(e))
784+
continue
785+
748786
exit(0)
749787

750788

chc/cmdline/c_project/cprojectutil.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949

5050
from chc.linker.CLinker import CLinker
5151

52+
from chc.proof.OutputParameterChecker import OutputParameterChecker
53+
5254
import chc.reporting.ProofObligations as RP
5355

5456
from chc.util.Config import Config
@@ -426,6 +428,9 @@ def cproject_analyze_project(args: argparse.Namespace) -> NoReturn:
426428
tgtpath: str = args.tgtpath
427429
projectname: str = args.projectname
428430
keep_system_includes: bool = args.keep_system_includes
431+
analysis: str = args.analysis
432+
analysisdomains: str = args.analysis_domains
433+
collectdiagnostics: bool = args.collect_diagnostics
429434
maxprocesses: int = args.maxprocesses
430435
loglevel: str = args.loglevel
431436
logfilename: Optional[str] = args.logfilename
@@ -435,6 +440,8 @@ def cproject_analyze_project(args: argparse.Namespace) -> NoReturn:
435440
if excludefiles is None:
436441
excludefiles = []
437442

443+
po_cmd = analysis + "-primary"
444+
438445
if not os.path.isdir(tgtpath):
439446
print_error(f"Target directory {tgtpath} not found")
440447
exit(1)
@@ -482,26 +489,31 @@ def save_xrefs(f: "CFile") -> None:
482489
keep_system_includes=keep_system_includes,
483490
excludefiles=excludefiles)
484491

485-
am = AnalysisManager(capp, verbose=True, keep_system_includes=keep_system_includes)
492+
am = AnalysisManager(
493+
capp,
494+
verbose=True,
495+
collectdiagnostics=collectdiagnostics,
496+
keep_system_includes=keep_system_includes)
486497

487498
with timing("analysis"):
488499

489500
try:
490-
am.create_app_primary_proofobligations(processes=maxprocesses)
501+
am.create_app_primary_proofobligations(
502+
po_cmd=po_cmd, processes=maxprocesses)
491503
capp.reinitialize_tables()
492504
capp.collect_post_assumes()
493505
except UF.CHError as e:
494506
print(str(e.wrap()))
495507
exit(1)
496508

497509
for i in range(1):
498-
am.generate_and_check_app("visp", processes=maxprocesses)
510+
am.generate_and_check_app(analysisdomains, processes=maxprocesses)
499511
capp.reinitialize_tables()
500512
capp.update_spos()
501513

502514
for i in range(5):
503515
capp.update_spos()
504-
am.generate_and_check_app("visp", processes=maxprocesses)
516+
am.generate_and_check_app(analysisdomains, processes=maxprocesses)
505517
capp.reinitialize_tables()
506518

507519
timestamp = os.stat(UF.get_cchpath(targetpath, projectname)).st_ctime
@@ -563,6 +575,7 @@ def cproject_report_file(args: argparse.Namespace) -> NoReturn:
563575
tgtpath: str = args.tgtpath
564576
projectname: str = args.projectname
565577
filename: str = args.filename
578+
canalysis: str = args.analysis
566579
showcode: bool = args.showcode
567580
showopen: bool = args.open
568581
showinvariants: bool = args.showinvariants
@@ -600,6 +613,15 @@ def pofilter(po: "CFunctionPO") -> bool:
600613

601614
print(RP.file_proofobligation_stats_tostring(cfile))
602615

616+
if canalysis == "outputparameters":
617+
for cfun in cfile.functions.values():
618+
try:
619+
op_checker = OutputParameterChecker(cfun)
620+
print(str(op_checker))
621+
except UF.CHCError as e:
622+
print("Skipping function " + cfun.name)
623+
continue
624+
603625
exit(0)
604626

605627

0 commit comments

Comments
 (0)