Skip to content

Commit 5039f6b

Browse files
hanno-beckermkannwischer
authored andcommitted
CBMC: Allow specification of per-proof timeouts
This commit adds support for per-proof timeouts in CBMC proofs to prevent CI from running for hours on failing or slow proofs. The implementation leverages Litani's existing timeout mechanism via the CBMC_TIMEOUT environment variable. Add --per-proof-timeout argument to run-cbmc-proofs.py (default: 1800s) Pass timeout to Litani via CBMC_TIMEOUT environment variable Modify lib/summarize.py to detect timeout_reached flag and display "timeout" instead. Add --per-proof-timeout argument to tests cbmc command Set explicit 30-minute timeout in CI workflow Signed-off-by: Hanno Becker <beckphan@amazon.co.uk>
1 parent ce37b3f commit 5039f6b

File tree

4 files changed

+62
-9
lines changed

4 files changed

+62
-9
lines changed

.github/actions/cbmc/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ runs:
5353
shell: ${{ env.SHELL }}
5454
run: |
5555
echo "::group::cbmc_${{ inputs.mlkem_k }}"
56-
tests cbmc --k ${{ inputs.mlkem_k }};
56+
tests cbmc --k ${{ inputs.mlkem_k }} --per-proof-timeout 1800;
5757
echo "::endgroup::"

proofs/cbmc/lib/summarize.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,32 @@ def _get_status_and_proof_summaries(run_dict):
9090
for proof_pipeline in run_dict["pipelines"]:
9191
if proof_pipeline["name"] == "print_tool_versions":
9292
continue
93-
status_pretty_name = proof_pipeline["status"].title().replace("_", " ")
94-
try:
95-
count_statuses[status_pretty_name] += 1
96-
except KeyError:
97-
count_statuses[status_pretty_name] = 1
93+
94+
# Check if any job timed out
95+
has_timeout = False
9896
duration = 0
9997
for stage in proof_pipeline["ci_stages"]:
10098
for job in stage["jobs"]:
99+
if job.get("timeout_reached", False):
100+
has_timeout = True
101101
if "duration" in job.keys():
102102
duration += int(job["duration"])
103-
proofs.append([proof_pipeline["name"], status_pretty_name, str(duration)])
103+
104+
# Determine status display
105+
if has_timeout:
106+
status_pretty_name = "Timeout"
107+
duration_str = "TIMEOUT"
108+
else:
109+
status_pretty_name = proof_pipeline["status"].title().replace("_", " ")
110+
duration_str = str(duration)
111+
112+
# Count statuses
113+
try:
114+
count_statuses[status_pretty_name] += 1
115+
except KeyError:
116+
count_statuses[status_pretty_name] = 1
117+
118+
proofs.append([proof_pipeline["name"], status_pretty_name, duration_str])
104119
statuses = [["Status", "Count"]]
105120
for status, count in count_statuses.items():
106121
statuses.append([status, str(count)])
@@ -134,8 +149,15 @@ def print_proof_results(out_file):
134149
"Click the 'Summary' button to view a Markdown table "
135150
"summarizing all proof results"
136151
)
137-
if run_dict["status"] != "success":
152+
153+
# Check for timeouts by examining status table
154+
has_timeout = any(row[0] == "Timeout" for row in status_table[1:])
155+
has_failure = run_dict["status"] != "success"
156+
157+
if has_timeout or has_failure:
138158
logging.error("Not all proofs passed.")
159+
if has_timeout:
160+
logging.error("Some proofs timed out.")
139161
logging.error(msg)
140162
sys.exit(1)
141163
logging.info(msg)

proofs/cbmc/run-cbmc-proofs.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ def get_args():
181181
"action": "store_true",
182182
"help": "do property checking without coverage checking",
183183
},
184+
{
185+
"flags": ["--per-proof-timeout"],
186+
"type": int,
187+
"metavar": "SECONDS",
188+
"default": 1800,
189+
"help": "timeout for each individual proof in seconds (default: 1800)",
190+
},
184191
]:
185192
flags = arg.pop("flags")
186193
pars.add_argument(*flags, **arg)
@@ -342,6 +349,7 @@ async def configure_proof_dirs( # pylint: disable=too-many-arguments
342349
enable_memory_profiling,
343350
report_target,
344351
debug,
352+
timeout,
345353
):
346354
while True:
347355
print_counter(counter)
@@ -352,6 +360,10 @@ async def configure_proof_dirs( # pylint: disable=too-many-arguments
352360
pools = ["ENABLE_POOLS=true"] if enable_pools else []
353361
profiling = ["ENABLE_MEMORY_PROFILING=true"] if enable_memory_profiling else []
354362

363+
# Set up environment with CBMC_TIMEOUT
364+
env = os.environ.copy()
365+
env["CBMC_TIMEOUT"] = str(timeout)
366+
355367
# delete old reports
356368
proc = await asyncio.create_subprocess_exec(
357369
"make",
@@ -373,6 +385,7 @@ async def configure_proof_dirs( # pylint: disable=too-many-arguments
373385
report_target,
374386
"" if debug else "--quiet",
375387
cwd=path,
388+
env=env,
376389
stdout=asyncio.subprocess.PIPE,
377390
stderr=asyncio.subprocess.PIPE,
378391
)
@@ -497,6 +510,7 @@ async def main(): # pylint: disable=too-many-locals
497510
enable_memory_profiling,
498511
report_target,
499512
args.debug,
513+
args.per_proof_timeout,
500514
)
501515
)
502516
tasks.append(task)

scripts/tests

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,8 @@ class Tests:
857857
"run-cbmc-proofs.py",
858858
"--summarize",
859859
"--no-coverage",
860+
"--per-proof-timeout",
861+
str(self.args.per_proof_timeout),
860862
"-p",
861863
func,
862864
]
@@ -911,7 +913,15 @@ class Tests:
911913
return
912914
envvars = {"MLKEM_K": mlkem_k}
913915
p = subprocess.run(
914-
["python3", "run-cbmc-proofs.py", "--summarize", "--no-coverage", "-p"]
916+
[
917+
"python3",
918+
"run-cbmc-proofs.py",
919+
"--summarize",
920+
"--no-coverage",
921+
"--per-proof-timeout",
922+
str(self.args.per_proof_timeout),
923+
"-p",
924+
]
915925
+ proofs
916926
+ self.make_j(),
917927
cwd="proofs/cbmc",
@@ -1287,6 +1297,13 @@ def cli():
12871297
default=3600,
12881298
)
12891299

1300+
cbmc_parser.add_argument(
1301+
"--per-proof-timeout",
1302+
help="Timeout for each individual CBMC proof passed to run-cbmc-proofs.py, in seconds (default: 1800)",
1303+
type=int,
1304+
default=1800,
1305+
)
1306+
12901307
cbmc_parser.add_argument(
12911308
"-f",
12921309
"--fail-upon-error",

0 commit comments

Comments
 (0)