Skip to content

Commit 6f97471

Browse files
committed
PROOF: add support for output-parameter predicates
1 parent cba47b2 commit 6f97471

File tree

4 files changed

+161
-2
lines changed

4 files changed

+161
-2
lines changed

chc/proof/CFilePredicateDictionary.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ def f(index: int, tags: List[str], args: List[int]) -> PO.CPOPredicate:
194194
p = cast(PO.CPOInitialized, p)
195195
args = [self.dictionary.index_lval(p.lval, subst=subst)]
196196

197+
elif p.is_locally_initialized:
198+
p = cast(PO.CPOLocallyInitialized, p)
199+
args = [self.dictionary.index_lval(p.lval, subst=subst)]
200+
197201
elif p.is_initialized_range:
198202
p = cast(PO.CPOInitializedRange, p)
199203
args = [

chc/proof/CFilePredicateRecord.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# ------------------------------------------------------------------------------
55
# The MIT License (MIT)
66
#
7-
# Copyright (c) 2023-2024 Aarno Labs LLC
7+
# Copyright (c) 2023-2025 Aarno Labs LLC
88
#
99
# Permission is hereby granted, free of charge, to any person obtaining a copy
1010
# of this software and associated documentation files (the "Software"), to deal
@@ -37,6 +37,7 @@
3737
if TYPE_CHECKING:
3838
from chc.app.CDictionary import CDictionary
3939
from chc.app.CFile import CFile
40+
from chc.app.CFileDeclarations import CFileDeclarations
4041
from chc.proof.CFilePredicateDictionary import CFilePredicateDictionary
4142

4243

@@ -59,6 +60,10 @@ def pd(self) -> "CFilePredicateDictionary":
5960
def cd(self) -> "CDictionary":
6061
return self.pd.dictionary
6162

63+
@property
64+
def cdeclarations(self) -> "CFileDeclarations":
65+
return self.cfile.declarations
66+
6267
@property
6368
def cfile(self) -> "CFile":
6469
return self.pd.cfile

chc/proof/CFunctionProofs.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
import xml.etree.ElementTree as ET
3232

33-
from typing import Callable, List, Optional, TYPE_CHECKING
33+
from typing import Callable, cast, List, Optional, TYPE_CHECKING
3434

3535
from chc.proof.CFunctionCallsiteSPOs import CFunctionCallsiteSPOs
3636
from chc.proof.CFunctionPO import CFunctionPO
@@ -44,6 +44,10 @@
4444
from chc.app.CApplication import CApplication
4545
from chc.app.CFile import CFile
4646
from chc.app.CFunction import CFunction
47+
from chc.proof.CPOPredicate import (
48+
CPOLocallyInitialized,
49+
CPOOutputParameterInitialized,
50+
CPOOutputParameterUnaltered)
4751

4852

4953
class CFunctionProofs:
@@ -240,6 +244,23 @@ def _get_spos(self, force=False):
240244
+ self.cfile.name
241245
)
242246

247+
def get_output_parameter_ppos(self, vname: str) -> List[CFunctionPO]:
248+
result: List[CFunctionPO] = []
249+
for ppo in self.ppolist:
250+
if ppo.predicate.is_locally_initialized:
251+
vinfo = cast("CPOLocallyInitialized", ppo.predicate).varinfo
252+
if vinfo.vname == vname:
253+
result.append(ppo)
254+
elif ppo.predicate.is_output_parameter_initialized:
255+
vinfo = cast("CPOOutputParameterInitialized", ppo.predicate).varinfo
256+
if vinfo.vname == vname:
257+
result.append(ppo)
258+
elif ppo.predicate.is_output_parameter_unaltered:
259+
vinfo = cast("CPOOutputParameterUnaltered", ppo.predicate).varinfo
260+
if vinfo.vname == vname:
261+
result.append(ppo)
262+
return result
263+
243264
def _save_spos(self, cnode: ET.Element) -> None:
244265
UF.save_spo_file(
245266
self.targetpath,

chc/proof/CPOPredicate.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
from chc.app.CExp import CExp, CExpLval
4141
from chc.app.CLHost import CLHostVar
4242
from chc.app.CLval import CLval
43+
from chc.app.COffset import COffset
4344
from chc.app.CTyp import CTyp
45+
from chc.app.CVarInfo import CVarInfo
4446
from chc.proof.CFilePredicateDictionary import CFilePredicateDictionary
4547

4648

@@ -71,12 +73,15 @@
7173
'iu': 'int-underflow',
7274
'iub': 'index-upper-bound',
7375
'lb': 'lower-bound',
76+
'li': 'locally-initialized',
7477
'nm': 'new-memory',
7578
'nn': 'not-null',
7679
'nneg': 'non-negative',
7780
'no': 'no-overlap',
7881
'nt': 'null-terminated',
7982
'null': 'null',
83+
'opi': 'output_parameter-initialized',
84+
'opu': 'output_parameter-unaltered',
8085
'pc': 'pointer-cast',
8186
'plb': 'ptr-lower-bound',
8287
'pre': 'precondition',
@@ -180,6 +185,10 @@ def is_index_upper_bound(self) -> bool:
180185
def is_initialized(self) -> bool:
181186
return False
182187

188+
@property
189+
def is_locally_initialized(self) -> bool:
190+
return False
191+
183192
@property
184193
def is_initialized_range(self) -> bool:
185194
return False
@@ -224,6 +233,14 @@ def is_null(self) -> bool:
224233
def is_null_terminated(self) -> bool:
225234
return False
226235

236+
@property
237+
def is_output_parameter_initialized(self) -> bool:
238+
return False
239+
240+
@property
241+
def is_output_parameter_unaltered(self) -> bool:
242+
return False
243+
227244
@property
228245
def is_pointer_cast(self) -> bool:
229246
return False
@@ -962,6 +979,48 @@ def __str__(self) -> str:
962979
return "initialized(" + str(self.lval) + ")"
963980

964981

982+
@pdregistry.register_tag("li", CPOPredicate)
983+
class CPOLocallyInitialized(CPOPredicate):
984+
"""locally initialized(lval): location initialized within the function.
985+
986+
- args[0]: index of lval in cdictionary
987+
"""
988+
989+
def __init__(
990+
self, pd: "CFilePredicateDictionary", ixval: IT.IndexedTableValue
991+
) -> None:
992+
CPOPredicate.__init__(self, pd, ixval)
993+
994+
@property
995+
def varinfo(self) -> "CVarInfo":
996+
return self.cdeclarations.get_varinfo(self.args[0])
997+
998+
@property
999+
def lval(self) -> "CLval":
1000+
return self.cd.get_lval(self.args[1])
1001+
1002+
@property
1003+
def is_locally_initialized(self) -> bool:
1004+
return True
1005+
1006+
def has_variable(self, vid: int) -> bool:
1007+
return self.lval.has_variable(vid)
1008+
1009+
def has_variable_deref(self, vid: int) -> bool:
1010+
return self.lval.has_variable_deref(vid)
1011+
1012+
def has_ref_type(self) -> bool:
1013+
return self.lval.has_ref_type()
1014+
1015+
def __str__(self) -> str:
1016+
return (
1017+
"locally-initialized("
1018+
+ str(self.varinfo.vname)
1019+
+ ", "
1020+
+ str(self.lval)
1021+
+ ")")
1022+
1023+
9651024
@pdregistry.register_tag("ir", CPOPredicate)
9661025
class CPOInitializedRange(CPOPredicate):
9671026
"""initialized-range(exp, size): the memory range starting at the address
@@ -2162,3 +2221,73 @@ def has_variable(self, vid: int) -> bool:
21622221

21632222
def __str__(self) -> str:
21642223
return "preserves-value(" + str(self.exp) + ")"
2224+
2225+
2226+
@pdregistry.register_tag("opi", CPOPredicate)
2227+
class CPOOutputParameterInitialized(CPOPredicate):
2228+
"""
2229+
2230+
- args[0]: index of varinfo in cdecls
2231+
"""
2232+
def __init__(
2233+
self, pd: "CFilePredicateDictionary", ixval: IT.IndexedTableValue
2234+
) -> None:
2235+
CPOPredicate.__init__(self, pd, ixval)
2236+
2237+
@property
2238+
def varinfo(self) -> "CVarInfo":
2239+
return self.cdeclarations.get_varinfo(self.args[0])
2240+
2241+
@property
2242+
def offset(self) -> "COffset":
2243+
return self.cd.get_offset(self.args[1])
2244+
2245+
@property
2246+
def is_output_parameter_initialized(self) -> bool:
2247+
return True
2248+
2249+
def has_variable(self, vid: int) -> bool:
2250+
return self.varinfo.vid == vid
2251+
2252+
def __str__(self) -> str:
2253+
return (
2254+
"output_parameter-initialized("
2255+
+ str(self.varinfo.vname)
2256+
+ ", "
2257+
+ str(self.offset)
2258+
+ ")")
2259+
2260+
2261+
@pdregistry.register_tag("opu", CPOPredicate)
2262+
class CPOOutputParameterUnaltered(CPOPredicate):
2263+
"""
2264+
2265+
- args[0]: index of varinfo in cdecls
2266+
"""
2267+
def __init__(
2268+
self, pd: "CFilePredicateDictionary", ixval: IT.IndexedTableValue
2269+
) -> None:
2270+
CPOPredicate.__init__(self, pd, ixval)
2271+
2272+
@property
2273+
def varinfo(self) -> "CVarInfo":
2274+
return self.cdeclarations.get_varinfo(self.args[0])
2275+
2276+
@property
2277+
def offset(self) -> "COffset":
2278+
return self.cd.get_offset(self.args[1])
2279+
2280+
@property
2281+
def is_output_parameter_unaltered(self) -> bool:
2282+
return True
2283+
2284+
def has_variable(self, vid: int) -> bool:
2285+
return self.varinfo.vid == vid
2286+
2287+
def __str__(self) -> str:
2288+
return (
2289+
"output_parameter-unaltered("
2290+
+ str(self.varinfo.vname)
2291+
+ ", "
2292+
+ str(self.offset)
2293+
+ ")")

0 commit comments

Comments
 (0)