forked from awslabs/AutoCorrode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimple_C_Functions.thy
More file actions
1791 lines (1441 loc) · 71.2 KB
/
Simple_C_Functions.thy
File metadata and controls
1791 lines (1441 loc) · 71.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
theory Simple_C_Functions
imports
"Micro_C_Parsing_Frontend.C_To_Core_Translation"
"Shallow_Micro_C.C_Arithmetic_Rules"
"Micro_Rust_Std_Lib.StdLib_All"
begin
section \<open>First end-to-end C verification example\<close>
text \<open>
This theory demonstrates end-to-end verification of C source code using
AutoCorrode. The pipeline is:
\<^enum> Parse C source via @{text micro_c_translate} to produce HOL definitions
\<^enum> Define a separation-logic contract
\<^enum> Prove the contract using @{text crush_boot} and @{text crush_base}
\<close>
subsection \<open>Locale setup\<close>
text \<open>
The locale provides the reference infrastructure: allocation, dereference,
and update operations with their separation-logic specifications.
This is the same boilerplate as the Rust examples.
\<close>
locale c_translation_ctx =
c_pointer_model c_ptr_add c_ptr_shift_signed c_ptr_diff c_ptr_less c_ptr_le c_ptr_greater c_ptr_ge
c_ptr_to_uintptr c_uintptr_to_ptr
for c_ptr_add :: \<open>('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_shift_signed :: \<open>('addr, 'gv) gref \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_diff :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> int\<close>
and c_ptr_less :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_le :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_greater :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_ge :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_to_uintptr :: \<open>('addr, 'gv) gref \<Rightarrow> int\<close>
and c_uintptr_to_ptr :: \<open>int \<Rightarrow> ('addr, 'gv) gref\<close>
locale c_base_verification_ctx =
c_pointer_model c_ptr_add c_ptr_shift_signed c_ptr_diff c_ptr_less c_ptr_le c_ptr_greater c_ptr_ge
c_ptr_to_uintptr c_uintptr_to_ptr +
reference reference_types
for c_ptr_add :: \<open>('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_shift_signed :: \<open>('addr, 'gv) gref \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_diff :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> int\<close>
and c_ptr_less :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_le :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_greater :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_ge :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_to_uintptr :: \<open>('addr, 'gv) gref \<Rightarrow> int\<close>
and c_uintptr_to_ptr :: \<open>int \<Rightarrow> ('addr, 'gv) gref\<close>
and reference_types :: \<open>'s::{sepalg} \<Rightarrow> 'addr \<Rightarrow> 'gv \<Rightarrow> c_abort \<Rightarrow> 'i prompt \<Rightarrow>
'o prompt_output \<Rightarrow> unit\<close>
locale c_verification_ctx =
c_pointer_model c_ptr_add c_ptr_shift_signed c_ptr_diff c_ptr_less c_ptr_le c_ptr_greater c_ptr_ge
c_ptr_to_uintptr c_uintptr_to_ptr +
reference reference_types +
ref_c_int: reference_allocatable reference_types _ _ _ _ _ _ _ c_int_prism
for c_ptr_add :: \<open>('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_shift_signed :: \<open>('addr, 'gv) gref \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_diff :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> int\<close>
and c_ptr_less :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_le :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_greater :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_ge :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_to_uintptr :: \<open>('addr, 'gv) gref \<Rightarrow> int\<close>
and c_uintptr_to_ptr :: \<open>int \<Rightarrow> ('addr, 'gv) gref\<close>
and reference_types :: \<open>'s::{sepalg} \<Rightarrow> 'addr \<Rightarrow> 'gv \<Rightarrow> c_abort \<Rightarrow> 'i prompt \<Rightarrow>
'o prompt_output \<Rightarrow> unit\<close>
and c_int_prism :: \<open>('gv, c_int) prism\<close>
begin
adhoc_overloading store_reference_const \<rightleftharpoons> ref_c_int.new
adhoc_overloading store_update_const \<rightleftharpoons> update_fun
subsection \<open>C swap function\<close>
text \<open>Parse the C swap function.\<close>
micro_c_translate \<open>
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
\<close>
thm c_swap_def
text \<open>
The contract for swap: given two disjoint references with values
@{text lval} and @{text rval}, after swap the references hold each
other's original values.
\<close>
definition c_swap_contract :: \<open>('addr, 'gv, c_int) Global_Store.ref \<Rightarrow>
('addr, 'gv, c_int) Global_Store.ref \<Rightarrow> 'gv \<Rightarrow> 'gv \<Rightarrow> c_int \<Rightarrow> c_int \<Rightarrow>
('s, 'a, 'b) function_contract\<close> where
\<open>c_swap_contract lref rref lg rg lval rval \<equiv>
let pre = can_alloc_reference \<star>
lref \<mapsto>\<langle>\<top>\<rangle> lg\<down>lval \<star> rref \<mapsto>\<langle>\<top>\<rangle> rg\<down>rval;
post = \<lambda> _. can_alloc_reference \<star>
lref \<mapsto>\<langle>\<top>\<rangle> (\<lambda>_. rval) \<sqdot> (lg\<down>lval) \<star>
rref \<mapsto>\<langle>\<top>\<rangle> (\<lambda>_. lval) \<sqdot> (rg\<down>rval)
in make_function_contract pre post\<close>
ucincl_auto c_swap_contract
text \<open>Prove that the C swap function satisfies its contract.\<close>
lemma c_swap_spec:
shows \<open>\<Gamma>; c_swap lref rref \<Turnstile>\<^sub>F c_swap_contract lref rref lg rg lval rval\<close>
by (crush_boot f: c_swap_def contract: c_swap_contract_def) crush_base
subsection \<open>C Max Function\<close>
text \<open>A simple function exercising conditionals and return.\<close>
micro_c_translate \<open>
int max(int a, int b) {
if (a > b)
return a;
else
return b;
}
\<close>
thm c_max_def
text \<open>
The contract for max uses signed comparison on words.
The translated code uses @{const c_signed_less} which compares
@{term "sint b < sint a"} (operands swapped for >).
\<close>
definition c_max_contract ::
\<open>c_int \<Rightarrow> c_int \<Rightarrow> ('s::{sepalg}, c_int, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_max_contract a b \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = (if sint b < sint a then a else b)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_max_contract
lemma c_max_spec [crush_specs]:
shows \<open>\<Gamma>; c_max a b \<Turnstile>\<^sub>F c_max_contract a b\<close>
by (crush_boot f: c_max_def contract: c_max_contract_def) (crush_base simp add: c_signed_less_def)
subsection \<open>C abs function\<close>
micro_c_translate \<open>
int abs_val(int x) {
if (x > 0)
return x;
else
return 0 - x;
}
\<close>
thm c_abs_val_def
text \<open>
The abs function requires a no-overflow precondition: subtraction
overflows when x is the minimum signed value. The precondition
ensures the negation is safe.
\<close>
definition c_abs_val_contract :: \<open>c_int \<Rightarrow> ('s::{sepalg}, c_int, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_abs_val_contract x \<equiv>
let pre = \<langle>-(2^31 :: int) < sint x\<rangle>;
post = \<lambda>r. \<langle>r = (if sint x > sint (0 :: c_int) then x else word_of_int (0 - sint x))\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_abs_val_contract
lemma c_abs_val_spec [crush_specs]:
shows \<open>\<Gamma>; c_abs_val x \<Turnstile>\<^sub>F c_abs_val_contract x\<close>
by (crush_boot f: c_abs_val_def contract: c_abs_val_contract_def) (crush_base simp add:
c_signed_less_def c_signed_sub_def c_signed_overflow_def Let_def)
subsection \<open>Signed Addition (with Overflow Precondition)\<close>
text \<open>
A function exercising signed addition directly.
The precondition establishes no-overflow using @{const c_signed_in_range},
and the postcondition shows the result equals @{term "word_of_int (sint a + sint b)"}.
\<close>
micro_c_translate \<open>
int signed_add(int a, int b) {
return a + b;
}
\<close>
definition c_signed_add_contract ::
\<open>c_int \<Rightarrow> c_int \<Rightarrow> ('s::{sepalg}, c_int, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_signed_add_contract a b \<equiv>
let pre = \<langle>c_signed_in_range (sint a + sint b) LENGTH(32)\<rangle>;
post = \<lambda>r. \<langle>r = word_of_int (sint a + sint b)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_signed_add_contract
lemma c_signed_add_spec [crush_specs]:
shows \<open>\<Gamma>; c_signed_add a b \<Turnstile>\<^sub>F c_signed_add_contract a b\<close>
by (crush_boot f: c_signed_add_def contract: c_signed_add_contract_def)
(crush_base simp add: c_signed_add_def c_signed_overflow_def Let_def)
subsection \<open>Signed Overflow UB Detection\<close>
text \<open>
When the precondition specifies that overflow \emph{does} occur, the function
correctly aborts with @{const SignedOverflow}. This demonstrates the core value
of the C frontend: UB is detected and turned into a verifiable abort.
\<close>
definition c_signed_add_overflow_contract ::
\<open>c_int \<Rightarrow> c_int \<Rightarrow> ('s::{sepalg}, c_int, c_abort) function_contract\<close> where
[crush_contracts]: \<open>c_signed_add_overflow_contract a b \<equiv>
let pre = \<langle>\<not> c_signed_in_range (sint a + sint b) LENGTH(32)\<rangle>;
post = \<lambda>_. \<bottom>;
abort_post = \<lambda>ab. \<langle>ab = CustomAbort SignedOverflow\<rangle>
in make_function_contract_with_abort pre post abort_post\<close>
ucincl_auto c_signed_add_overflow_contract
lemma c_signed_add_overflow_spec:
shows \<open>\<Gamma>; c_signed_add a b \<Turnstile>\<^sub>F c_signed_add_overflow_contract a b\<close>
apply (crush_boot f: c_signed_add_def contract: c_signed_add_overflow_contract_def)
apply (simp only: C_Numeric_Types.c_signed_add_def Let_def)
apply (crush_base simp add: c_signed_overflow_def c_abort_def)
done
end
section \<open>C Unsigned Arithmetic Verification\<close>
text \<open>
This section demonstrates verification of C code using unsigned integer types.
Unsigned arithmetic wraps modulo @{term \<open>2^32\<close>} and uses @{const c_unsigned_add}
instead of @{const c_signed_add}.
\<close>
locale c_uint_verification_ctx =
c_pointer_model c_ptr_add c_ptr_shift_signed c_ptr_diff c_ptr_less c_ptr_le c_ptr_greater c_ptr_ge
c_ptr_to_uintptr c_uintptr_to_ptr +
reference reference_types +
ref_c_uint: reference_allocatable reference_types _ _ _ _ _ _ _ c_uint_prism +
ref_c_uint_ptr: reference_allocatable reference_types _ _ _ _ _ _ _ c_uint_ptr_prism
for c_ptr_add :: \<open>('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_shift_signed :: \<open>('addr, 'gv) gref \<Rightarrow> int \<Rightarrow> nat \<Rightarrow> ('addr, 'gv) gref\<close>
and c_ptr_diff :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> nat \<Rightarrow> int\<close>
and c_ptr_less :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_le :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_greater :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_ge :: \<open>('addr, 'gv) gref \<Rightarrow> ('addr, 'gv) gref \<Rightarrow> bool\<close>
and c_ptr_to_uintptr :: \<open>('addr, 'gv) gref \<Rightarrow> int\<close>
and c_uintptr_to_ptr :: \<open>int \<Rightarrow> ('addr, 'gv) gref\<close>
and reference_types :: \<open>'s::{sepalg} \<Rightarrow> 'addr \<Rightarrow> 'gv \<Rightarrow> c_abort \<Rightarrow> 'i prompt \<Rightarrow>
'o prompt_output \<Rightarrow> unit\<close>
and c_uint_prism :: \<open>('gv, c_uint) prism\<close>
and c_uint_ptr_prism :: \<open>('gv, ('addr, 'gv, c_uint) Global_Store.ref) prism\<close>
begin
adhoc_overloading store_reference_const \<rightleftharpoons> ref_c_uint.new
adhoc_overloading store_reference_const \<rightleftharpoons> ref_c_uint_ptr.new
adhoc_overloading store_update_const \<rightleftharpoons> update_fun
micro_c_translate \<open>
unsigned int u_add(unsigned int a, unsigned int b) {
return a + b;
}
\<close>
thm c_u_add_def
micro_c_translate \<open>
unsigned int u_call_helper(unsigned int x) {
return x;
}
unsigned int u_call_caller(unsigned int a, unsigned int b) {
return u_call_helper(a) + u_call_helper(b);
}
\<close>
thm c_u_call_helper_def c_u_call_caller_def
text \<open>
Multi-function contract composition: verify the helper first, tag its spec
with @{text "[crush_specs]"}, then the caller's proof automatically uses it.
\<close>
definition c_u_call_helper_contract ::
\<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_u_call_helper_contract x \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = x\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_u_call_helper_contract
lemma c_u_call_helper_spec [crush_specs]:
shows \<open>\<Gamma>; c_u_call_helper x \<Turnstile>\<^sub>F c_u_call_helper_contract x\<close>
by (crush_boot f: c_u_call_helper_def contract: c_u_call_helper_contract_def) crush_base
definition c_u_call_caller_contract ::
\<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_u_call_caller_contract a b \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = a + b\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_u_call_caller_contract
lemma c_u_call_caller_spec [crush_specs]:
shows \<open>\<Gamma>; c_u_call_caller a b \<Turnstile>\<^sub>F c_u_call_caller_contract a b\<close>
by (crush_boot f: c_u_call_caller_def contract: c_u_call_caller_contract_def)
(crush_base simp add: c_unsigned_add_def)
text \<open>
The contract for @{text u_add}: unsigned addition wraps, so the result is
always @{term \<open>a + b\<close>} (Isabelle word addition already wraps).
No overflow precondition needed.
\<close>
definition c_u_add_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_u_add_contract a b \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = a + b\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_u_add_contract
lemma c_u_add_spec [crush_specs]:
shows \<open>\<Gamma>; c_u_add a b \<Turnstile>\<^sub>F c_u_add_contract a b\<close>
by (crush_boot f: c_u_add_def contract: c_u_add_contract_def) (crush_base simp add: c_unsigned_add_def)
micro_c_translate \<open>
unsigned int u_max(unsigned int a, unsigned int b) {
if (a > b)
return a;
else
return b;
}
\<close>
thm c_u_max_def
definition c_u_max_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_u_max_contract a b \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = (if b < a then a else b)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_u_max_contract
lemma c_u_max_spec [crush_specs]:
shows \<open>\<Gamma>; c_u_max a b \<Turnstile>\<^sub>F c_u_max_contract a b\<close>
by (crush_boot f: c_u_max_def contract: c_u_max_contract_def) (crush_base simp add: c_unsigned_less_def)
subsection \<open>Comma operator\<close>
micro_c_translate \<open>
unsigned int comma_test(unsigned int a, unsigned int b) {
unsigned int x = (a, b);
return x;
}
\<close>
definition c_comma_test_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_comma_test_contract a b \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = b\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_comma_test_contract
lemma c_comma_test_spec [crush_specs]:
shows \<open>\<Gamma>; c_comma_test a b \<Turnstile>\<^sub>F c_comma_test_contract a b\<close>
by (crush_boot f: c_comma_test_def contract: c_comma_test_contract_def) crush_base
subsection \<open>Multiple Declarations\<close>
micro_c_translate \<open>
unsigned int multi_decl_add(unsigned int a, unsigned int b) {
unsigned int x = a, y = b;
return x + y;
}
\<close>
definition c_multi_decl_add_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_multi_decl_add_contract a b \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = a + b\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_multi_decl_add_contract
lemma c_multi_decl_add_spec [crush_specs]:
shows \<open>\<Gamma>; c_multi_decl_add a b \<Turnstile>\<^sub>F c_multi_decl_add_contract a b\<close>
by (crush_boot f: c_multi_decl_add_def contract: c_multi_decl_add_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Pre-increment\<close>
micro_c_translate \<open>
unsigned int pre_inc_test(unsigned int init) {
unsigned int x = init;
unsigned int r = ++x;
return r;
}
\<close>
definition c_pre_inc_test_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_pre_inc_test_contract init \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = init + 1\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_pre_inc_test_contract
lemma c_pre_inc_test_spec [crush_specs]:
shows \<open>\<Gamma>; c_pre_inc_test init \<Turnstile>\<^sub>F c_pre_inc_test_contract init\<close>
by (crush_boot f: c_pre_inc_test_def contract: c_pre_inc_test_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Post-Increment\<close>
micro_c_translate \<open>
unsigned int post_inc_test(unsigned int init) {
unsigned int x = init;
unsigned int r = x++;
return r;
}
\<close>
definition c_post_inc_test_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_post_inc_test_contract init \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star> \<langle>r = init\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_post_inc_test_contract
lemma c_post_inc_test_spec [crush_specs]:
shows \<open>\<Gamma>; c_post_inc_test init \<Turnstile>\<^sub>F c_post_inc_test_contract init\<close>
by (crush_boot f: c_post_inc_test_def contract: c_post_inc_test_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Post-Decrement\<close>
micro_c_translate \<open>
unsigned int post_dec_test(unsigned int init) {
unsigned int x = init;
unsigned int r = x--;
return r;
}
\<close>
definition c_post_dec_test_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_post_dec_test_contract init \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star> \<langle>r = init\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_post_dec_test_contract
lemma c_post_dec_test_spec [crush_specs]:
shows \<open>\<Gamma>; c_post_dec_test init \<Turnstile>\<^sub>F c_post_dec_test_contract init\<close>
by (crush_boot f: c_post_dec_test_def contract: c_post_dec_test_contract_def)
(crush_base simp add: c_unsigned_sub_def)
subsection \<open>Not-Equal Operator\<close>
micro_c_translate \<open>
unsigned int neq_test(unsigned int a, unsigned int b) {
if (a != b)
return 1;
else
return 0;
}
\<close>
definition c_neq_test_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_neq_test_contract a b \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = (if a \<noteq> b then 1 else 0)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_neq_test_contract
lemma c_neq_test_spec [crush_specs]:
shows \<open>\<Gamma>; c_neq_test a b \<Turnstile>\<^sub>F c_neq_test_contract a b\<close>
by (crush_boot f: c_neq_test_def contract: c_neq_test_contract_def)
(crush_base simp add: c_unsigned_neq_def)
subsection \<open>Logical NOT\<close>
micro_c_translate \<open>
unsigned int is_zero(unsigned int x) {
if (!x)
return 1;
else
return 0;
}
\<close>
definition c_is_zero_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_is_zero_contract x \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = (if x = 0 then 1 else 0)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_is_zero_contract
lemma c_is_zero_spec [crush_specs]:
shows \<open>\<Gamma>; c_is_zero x \<Turnstile>\<^sub>F c_is_zero_contract x\<close>
by (crush_boot f: c_is_zero_def contract: c_is_zero_contract_def)
(crush_base simp add: c_unsigned_eq_def)
subsection \<open>Unary plus\<close>
micro_c_translate \<open>
unsigned int uplus(unsigned int x) {
return +x;
}
\<close>
definition c_uplus_contract ::
\<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_uplus_contract x \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = x\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_uplus_contract
lemma c_uplus_spec [crush_specs]:
shows \<open>\<Gamma>; c_uplus x \<Turnstile>\<^sub>F c_uplus_contract x\<close>
by (crush_boot f: c_uplus_def contract: c_uplus_contract_def) crush_base
subsection \<open>Ternary operator\<close>
micro_c_translate \<open>
unsigned int ternary_max(unsigned int a, unsigned int b) {
return (a > b) ? a : b;
}
\<close>
definition c_ternary_max_contract ::
\<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_ternary_max_contract a b \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = (if b < a then a else b)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_ternary_max_contract
lemma c_ternary_max_spec [crush_specs]:
shows \<open>\<Gamma>; c_ternary_max a b \<Turnstile>\<^sub>F c_ternary_max_contract a b\<close>
by (crush_boot f: c_ternary_max_def contract: c_ternary_max_contract_def)
(crush_base simp add: c_unsigned_less_def)
subsection \<open>Compound assignment\<close>
micro_c_translate \<open>
unsigned int add_assign(unsigned int a, unsigned int b) {
unsigned int x = a;
x += b;
return x;
}
\<close>
definition c_add_assign_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow>
('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_add_assign_contract a b \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = a + b\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_add_assign_contract
lemma c_add_assign_spec [crush_specs]:
shows \<open>\<Gamma>; c_add_assign a b \<Turnstile>\<^sub>F c_add_assign_contract a b\<close>
by (crush_boot f: c_add_assign_def contract: c_add_assign_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Cast: widen unsigned char to unsigned int\<close>
micro_c_translate \<open>
unsigned int widen_char(unsigned char x) {
return (unsigned int)x;
}
\<close>
thm c_widen_char_def
definition c_widen_char_contract :: \<open>c_char \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_widen_char_contract x \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = ucast x\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_widen_char_contract
lemma c_widen_char_spec [crush_specs]:
shows \<open>\<Gamma>; c_widen_char x \<Turnstile>\<^sub>F c_widen_char_contract x\<close>
by (crush_boot f: c_widen_char_def contract: c_widen_char_contract_def) (crush_base simp add: c_ucast_def)
subsection \<open>Integer literal suffix\<close>
micro_c_translate \<open>
unsigned int suffix_add(unsigned int x) {
return x + 1U;
}
\<close>
thm c_suffix_add_def
definition c_suffix_add_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_suffix_add_contract x \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = x + 1\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_suffix_add_contract
lemma c_suffix_add_spec [crush_specs]:
shows \<open>\<Gamma>; c_suffix_add x \<Turnstile>\<^sub>F c_suffix_add_contract x\<close>
by (crush_boot f: c_suffix_add_def contract: c_suffix_add_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Assignment to parameter\<close>
micro_c_translate \<open>
unsigned int double_val(unsigned int x) {
x = x + x;
return x;
}
\<close>
thm c_double_val_def
definition c_double_val_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_double_val_contract x \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = x + x\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_double_val_contract
lemma c_double_val_spec [crush_specs]:
shows \<open>\<Gamma>; c_double_val x \<Turnstile>\<^sub>F c_double_val_contract x\<close>
by (crush_boot f: c_double_val_def contract: c_double_val_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Mutable parameter: compound assignment and increment\<close>
text \<open>
Test that compound assignment and pre/post increment on parameters are
correctly detected by \<^text>\<open>find_assigned_vars\<close> and promoted to locals.
\<close>
micro_c_translate \<open>
unsigned int param_compound(unsigned int x, unsigned int y) {
x += y;
return x;
}
\<close>
thm c_param_compound_def
definition c_param_compound_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow>
('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_param_compound_contract x y \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = x + y\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_param_compound_contract
lemma c_param_compound_spec [crush_specs]:
shows \<open>\<Gamma>; c_param_compound x y \<Turnstile>\<^sub>F c_param_compound_contract x y\<close>
by (crush_boot f: c_param_compound_def contract: c_param_compound_contract_def)
(crush_base simp add: c_unsigned_add_def)
micro_c_translate \<open>
unsigned int param_inc(unsigned int x) {
x++;
return x;
}
\<close>
thm c_param_inc_def
definition c_param_inc_contract :: \<open>c_uint \<Rightarrow>
('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_param_inc_contract x \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = x + 1\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_param_inc_contract
lemma c_param_inc_spec [crush_specs]:
shows \<open>\<Gamma>; c_param_inc x \<Turnstile>\<^sub>F c_param_inc_contract x\<close>
by (crush_boot f: c_param_inc_def contract: c_param_inc_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Compound pointer dereference\<close>
micro_c_translate \<open>
unsigned int inc_ptr(unsigned int *p) {
*p += 1;
return *p;
}
\<close>
thm c_inc_ptr_def
definition c_inc_ptr_contract :: \<open>('addr, 'gv, c_uint) Global_Store.ref \<Rightarrow>
'gv \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_inc_ptr_contract p pg val \<equiv>
let pre = p \<mapsto>\<langle>\<top>\<rangle> pg\<down>val;
post = \<lambda>r. p \<mapsto>\<langle>\<top>\<rangle> (\<lambda>_. val + 1) \<sqdot> (pg\<down>val) \<star> \<langle>r = val + 1\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_inc_ptr_contract
lemma c_inc_ptr_spec [crush_specs]:
shows \<open>\<Gamma>; c_inc_ptr p \<Turnstile>\<^sub>F c_inc_ptr_contract p pg val\<close>
by (crush_boot f: c_inc_ptr_def contract: c_inc_ptr_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Sizeof\<close>
micro_c_translate \<open>
unsigned int size_of_int(void) {
return sizeof(int);
}
\<close>
thm c_size_of_int_def
subsection \<open>Switch statement\<close>
micro_c_translate \<open>
unsigned int classify(unsigned int x) {
unsigned int result;
switch (x) {
case 0:
result = 10;
break;
case 1:
result = 20;
break;
default:
result = 30;
break;
}
return result;
}
\<close>
thm c_classify_def
definition c_classify_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_classify_contract x \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star> \<langle>r = (if x = 0 then 10 else if x = 1 then 20 else 30)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_classify_contract
lemma c_classify_spec [crush_specs]:
shows \<open>\<Gamma>; c_classify x \<Turnstile>\<^sub>F c_classify_contract x\<close>
by (crush_boot f: c_classify_def contract: c_classify_contract_def) crush_base
subsection \<open>Address-of\<close>
text \<open>
Test address-of: @{text "&x"} on a local variable returns the ref itself.
The parameter @{text x} is auto-promoted to a local ref because @{text "&x"} appears.
\<close>
micro_c_translate \<open>
unsigned int inc_via_addr(void) {
unsigned int x = 5;
unsigned int *p = &x;
*p = *p + 1;
return x;
}
\<close>
thm c_inc_via_addr_def
definition c_inc_via_addr_contract :: \<open>('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_inc_via_addr_contract \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = 6\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_inc_via_addr_contract
lemma c_inc_via_addr_spec [crush_specs]:
shows \<open>\<Gamma>; c_inc_via_addr \<Turnstile>\<^sub>F c_inc_via_addr_contract\<close>
by (crush_boot f: c_inc_via_addr_def contract: c_inc_via_addr_contract_def)
(crush_base simp add: c_unsigned_add_def)
subsection \<open>Pointer arithmetic\<close>
text \<open>
Test pointer arithmetic: @{text "*(arr + idx)"} reads through the
pointer model by shifting the base reference and dereferencing the result.
\<close>
micro_c_translate \<open>
unsigned int ptr_add_read(unsigned int *arr, unsigned int idx) {
return *(arr + idx);
}
\<close>
thm c_ptr_add_read_def
definition c_ptr_add_read_contract :: \<open>('addr, 'gv, c_uint) Global_Store.ref \<Rightarrow> 'gv \<Rightarrow>
c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_ptr_add_read_contract arr ag v idx \<equiv>
let elem_ref = make_focused
(c_ptr_add (unwrap_focused arr) (c_idx_to_nat idx) (c_sizeof TYPE(c_uint)))
(get_focus arr);
pre = elem_ref \<mapsto>\<langle>\<top>\<rangle> ag\<down>v;
post = \<lambda>r. elem_ref \<mapsto>\<langle>\<top>\<rangle> ag\<down>v \<star> \<langle>r = v\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_ptr_add_read_contract
lemma c_ptr_add_read_spec [crush_specs]:
shows \<open>\<Gamma>; c_ptr_add_read arr idx \<Turnstile>\<^sub>F c_ptr_add_read_contract arr ag v idx\<close>
by (crush_boot f: c_ptr_add_read_def contract: c_ptr_add_read_contract_def) crush_base
subsection \<open>Forward-only goto\<close>
text \<open>
Test forward-only goto: @{text "goto done"} skips @{text "result = a + b"}
when @{text "b == 0"}, using a per-label flag mechanism.
\<close>
micro_c_translate \<open>
unsigned int skip_add(unsigned int a, unsigned int b) {
unsigned int result = a;
if (b == 0)
goto done;
result = a + b;
done:
return result;
}
\<close>
thm c_skip_add_def
definition c_skip_add_contract :: \<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_skip_add_contract a b \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star>
\<langle>r = (if b = 0 then a else a + b)\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_skip_add_contract
lemma c_skip_add_spec [crush_specs]:
shows \<open>\<Gamma>; c_skip_add a b \<Turnstile>\<^sub>F c_skip_add_contract a b\<close>
by (crush_boot f: c_skip_add_def contract: c_skip_add_contract_def)
(crush_base simp add: c_unsigned_eq_def c_unsigned_add_def)
subsection \<open>Unsigned Division (with Division-by-Zero Precondition)\<close>
text \<open>
Exercises unsigned division end-to-end. The precondition ensures
the divisor is non-zero (division by zero aborts with @{const DivisionByZero}).
Unsigned division has no overflow — the result is always representable.
\<close>
micro_c_translate \<open>
unsigned int u_div(unsigned int a, unsigned int b) {
return a / b;
}
\<close>
definition c_u_div_contract ::
\<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, c_abort) function_contract\<close> where
[crush_contracts]: \<open>c_u_div_contract a b \<equiv>
let pre = \<langle>b \<noteq> 0\<rangle>;
post = \<lambda>r. \<langle>r = a div b\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_u_div_contract
lemma c_u_div_spec [crush_specs]:
shows \<open>\<Gamma>; c_u_div a b \<Turnstile>\<^sub>F c_u_div_contract a b\<close>
by (crush_boot f: c_u_div_def contract: c_u_div_contract_def)
(crush_base simp add: c_unsigned_div_def c_division_by_zero_def c_abort_def)
subsection \<open>Division by Zero UB Detection\<close>
text \<open>
When the divisor is zero, unsigned division correctly aborts with
@{const DivisionByZero}. The function never returns normally.
\<close>
definition c_u_div_zero_contract ::
\<open>c_uint \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, c_abort) function_contract\<close> where
[crush_contracts]: \<open>c_u_div_zero_contract a b \<equiv>
let pre = \<langle>b = 0\<rangle>;
post = \<lambda>_. \<bottom>;
abort_post = \<lambda>ab. \<langle>ab = CustomAbort DivisionByZero\<rangle>
in make_function_contract_with_abort pre post abort_post\<close>
ucincl_auto c_u_div_zero_contract
lemma c_u_div_zero_spec:
shows \<open>\<Gamma>; c_u_div a b \<Turnstile>\<^sub>F c_u_div_zero_contract a b\<close>
by (crush_boot f: c_u_div_def contract: c_u_div_zero_contract_def)
(crush_base simp add: c_unsigned_div_def c_division_by_zero_def c_abort_def)
subsection \<open>NULL pointer literal\<close>
text \<open>
Test null pointer comparison: @{text "p == (void*)0"} checks whether a
pointer is null via @{text "gref_address"}.
\<close>
micro_c_translate \<open>
unsigned int is_null(unsigned int *p) {
if (p == (void*)0)
return 1;
return 0;
}
\<close>
thm c_is_null_def
definition c_is_null_contract :: \<open>('addr, 'gv, c_uint) Global_Store.ref \<Rightarrow>
'gv \<Rightarrow> c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_is_null_contract p pg val \<equiv>
let pre = p \<mapsto>\<langle>\<top>\<rangle> pg\<down>val \<star> \<langle>c_ptr_to_uintptr (\<flat> p) \<noteq> 0\<rangle>;
post = \<lambda>r. p \<mapsto>\<langle>\<top>\<rangle> pg\<down>val \<star> \<langle>r = 0\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_is_null_contract
lemma c_is_null_spec [crush_specs]:
shows \<open>\<Gamma>; c_is_null p \<Turnstile>\<^sub>F c_is_null_contract p pg val\<close>
by (crush_boot f: c_is_null_def contract: c_is_null_contract_def)
crush_base
micro_c_translate \<open>
unsigned int ptr_eq(unsigned int *p, unsigned int *q) {
if (p != q)
return 0;
return 1;
}
\<close>
thm c_ptr_eq_def
subsection \<open>Arbitrary loop bound\<close>
text \<open>
Test that for-loop bounds can be arbitrary unsigned expressions,
not just literals or parameters. The bound @{text "n + 1"} is evaluated
monadically and its @{text "unat"} value used as the loop range.
\<close>
micro_c_translate \<open>
unsigned int noop_loop(unsigned int n) {
for (unsigned int i = 0; i < n + 1; i++) {
}
return 0;
}
\<close>
thm c_noop_loop_def
definition c_noop_loop_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_noop_loop_contract n \<equiv>
let pre = \<langle>True\<rangle>;
post = \<lambda>r. \<langle>r = 0\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_noop_loop_contract
lemma c_noop_loop_spec [crush_specs]:
shows \<open>\<Gamma>; c_noop_loop n \<Turnstile>\<^sub>F c_noop_loop_contract n\<close>
apply (crush_boot f: c_noop_loop_def contract: c_noop_loop_contract_def)
apply crush_base
apply (rule wp_raw_for_loop_framedI'[where INV=\<open>\<lambda>_ _. \<langle>True\<rangle>\<close> and \<tau>=\<open>\<lambda>_. \<bottom>\<close>])
apply crush_base
done
subsection \<open>Backward goto\<close>
text \<open>
Test backward goto: a label-based retry loop. The label @{text "start"}
is a backward goto target, wrapped in @{text "bounded_while"} with
fuel. The goto sets the flag, guards skip remaining code, and the
while re-enters.
\<close>
micro_c_translate \<open>
unsigned int count_down(unsigned int n) {
unsigned int i = n;
start:
if (i == 0) goto done;
i = i - 1;
goto start;
done:
return i;
}
\<close>
thm c_count_down_def
definition c_count_down_contract :: \<open>c_uint \<Rightarrow> ('s::{sepalg}, c_uint, 'b) function_contract\<close> where
[crush_contracts]: \<open>c_count_down_contract n \<equiv>
let pre = can_alloc_reference;
post = \<lambda>r. can_alloc_reference \<star> \<langle>r = 0\<rangle>
in make_function_contract pre post\<close>
ucincl_auto c_count_down_contract
lemma c_count_down_spec: