任务1:测试整数中点计算函数
程序运行输入输出:
❯ ./midpoint_test.out0 00❯ ./midpoint_test.out0 10❯ ./midpoint_test.out1 2147483647-1073741824❯ ./midpoint_test.out2147483647 2147483647-1已运行:
| No. | low | high | midpoint | output |
|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 |
| 3 | 1 | 2147483647 | 1073741824 | -1073741824 |
| 4 | 2147483647 | 2147483647 | 2147483647 | -1 |
未运行:
| No. | low | high | midpoint | output |
|---|---|---|---|---|
| 5 | 29 | 47 | 38 | / |
| 6 | 350 | 7701 | 4025 | / |
| 7 | 1073741824 | 1073741824 | 1073741824 | / |
测试结论:当前测试结果能够支持 low + high 较小的情形;
对于 low + high 较大的情况,程序会发生溢出,导致得到错误的结果。
当前测试结果可以支持测试点 5 与测试点 6 ,无法支持测试点 7 。
当前测试结果可以说明程序在 low + high 较小的情形下大致运行良好,在 low + high 较大的情形下可能产生错误的输出
不能说明对于所有的合法输入,程序都可以按照预期运行。
任务2:使用 CBMC 检查整数溢出
程序运行输入输出:
❯ cbmc midpoint_cbmc.c --signed-overflow-check --all-properties --traceCBMC version 6.11.0 (640889b) 64-bit x86_64 linuxType-checking midpoint_cbmcGenerating GOTO ProgramAdding CPROVER library (x86_64)Removal of function pointers and virtual functionsGeneric Property Instrumentation108 collapsed lines
Starting Bounded Model CheckingPassing problem to propositional reductionconverting SSARunning propositional reductionSAT checker: instance is SATISFIABLEBuilding error trace
** Results:midpoint_cbmc.c function main[main.assertion.1] line 10 midpoint is inside the interval: FAILURE
midpoint_cbmc.c function midpoint[midpoint.overflow.1] line 3 arithmetic overflow on signed + in low + high: FAILURE
Trace for main.assertion.1:
State 13 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- return_value_nondet_int=177393664 (00001010 10010010 11010000 00000000)
State 14 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- low=177393664 (00001010 10010010 11010000 00000000)
State 17 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- return_value_nondet_int$0=1981235200 (01110110 00010111 01000000 00000000)
State 18 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- high=1981235200 (01110110 00010111 01000000 00000000)
Assumption: file midpoint_cbmc.c line 8 function main 0 <= low && low <= high
State 24 file midpoint_cbmc.c function main line 9 thread 0---------------------------------------------------- low=177393664 (00001010 10010010 11010000 00000000)
State 25 file midpoint_cbmc.c function main line 9 thread 0---------------------------------------------------- high=1981235200 (01110110 00010111 01000000 00000000)
Violated property: file midpoint_cbmc.c function midpoint line 3 thread 0 arithmetic overflow on signed + in low + high !overflow("+", signed int, low, high)
State 27 file midpoint_cbmc.c function midpoint line 3 thread 0---------------------------------------------------- goto_symex$$return_value$$midpoint=-1068169216 (11000000 01010101 00001000 00000000)misskeyState 29 file midpoint_cbmc.c function main line 9 thread 0---------------------------------------------------- return_value_midpoint=-1068169216 (11000000 01010101 00001000 00000000)
State 30 file midpoint_cbmc.c function main line 9 thread 0---------------------------------------------------- mid=-1068169216 (11000000 01010101 00001000 00000000)
Violated property: file midpoint_cbmc.c function main line 10 thread 0 midpoint is inside the interval low <= mid && mid <= high
Trace for midpoint.overflow.1:
State 13 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- return_value_nondet_int=177393664 (00001010 10010010 11010000 00000000)
State 14 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- low=177393664 (00001010 10010010 11010000 00000000)
State 17 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- return_value_nondet_int$0=1981235200 (01110110 00010111 01000000 00000000)
State 18 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- high=1981235200 (01110110 00010111 01000000 00000000)
Assumption: file midpoint_cbmc.c line 8 function main 0 <= low && low <= high
State 24 file midpoint_cbmc.c function main line 9 thread 0---------------------------------------------------- low=177393664 (00001010 10010010 11010000 00000000)
State 25 file midpoint_cbmc.c function main line 9 thread 0---------------------------------------------------- high=1981235200 (01110110 00010111 01000000 00000000)
Violated property: file midpoint_cbmc.c function midpoint line 3 thread 0 arithmetic overflow on signed + in low + high !overflow("+", signed int, low, high)
** 2 of 2 failed (2 iterations)VERIFICATION FAILED从下列代码片段中可知 low + high 的有符号整数溢出性质
Violated property: file midpoint_cbmc.c function midpoint line 3 thread 0 arithmetic overflow on signed + in low + high !overflow("+", signed int, low, high)反例为low = 177393664; high = 1981235200; mid = -1068169216, 满足 的输入假设。
由数学计算知其和较小中点为 1079314432 ,仍在 int 表示范围内。
但根据函数 midpoint 的定义:
int midpoint(int low, int high) { return (low + high) / 2;}程序执行过程中会先计算 (low + high) ,该过程中发生有符号整数溢出。
将反例作为任务 1 程序的输入,实际运行结果如下:
❯ ./midpoint_test.out177393664 1981235200-1068169216运行结果与 CBMC 运行输出相符
任务3:分别检查计算安全和功能要求
midpoint_test 输入输出:
❯ g++ midpoint_test.c -o midpoint_test.out❯ ./midpoint_test.out0 00❯ ./midpoint_test.out0 10❯ ./midpoint_test.out1 21474836471073741824❯ ./midpoint_test.out2147483647 21474836472147483647❯ ./midpoint_test.out29 4738❯ ./midpoint_test.out350 77014025❯ ./midpoint_test.out1073741824 10737418241073741824测试用例:
| No. | low | high | midpoint | output |
|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 |
| 3 | 1 | 2147483647 | 1073741824 | 1073741824 |
| 4 | 2147483647 | 2147483647 | 2147483647 | 2147483647 |
| 5 | 29 | 47 | 38 | 38 |
| 6 | 350 | 7701 | 4025 | 4025 |
| 7 | 1073741824 | 1073741824 | 1073741824 | 1073741824 |
midpoint_cbmc 输入输出:
❯ cbmc midpoint_cbmc.c --signed-overflow-check --all-properties --traceCBMC version 6.11.0 (640889b) 64-bit x86_64 linuxType-checking midpoint_cbmcGenerating GOTO ProgramAdding CPROVER library (x86_64)Removal of function pointers and virtual functionsGeneric Property Instrumentation19 collapsed lines
Starting Bounded Model CheckingPassing problem to propositional reductionconverting SSARunning propositional reductionSAT checker: instance is UNSATISFIABLE
** Results:midpoint_cbmc.c function main[main.assertion.1] line 13 midpoint is inside the interval: SUCCESS[main.assertion.2] line 15 midpoint has the expected offset: SUCCESS[main.overflow.1] line 15 arithmetic overflow on signed - in mid - low: SUCCESS[main.overflow.2] line 15 arithmetic overflow on signed - in high - low: SUCCESS
midpoint_cbmc.c function midpoint[midpoint.overflow.1] line 3 arithmetic overflow on signed - in high - low: SUCCESS[midpoint.overflow.2] line 3 arithmetic overflow on signed + in low + (high - low) / 2: SUCCESS
** 0 of 6 failed (1 iterations)VERIFICATION SUCCESSFULlow 和 high 可以取任意 int 范围内整数,输入假设排除了 的情形。
第一个断言检查结果是否仍在原区间中;第二个断言检查结果与 low 的距离是否等于区间长度的一半:
实际覆盖的输入条件为 low 与 high 均为 int 范围内整数且满足 ,具有避免有符号整数溢出的性质。
将 midpoint 修改为下面版本
int midpoint(int low, int high) { return low / 2 + high / 2;}CBMC 运行结果如下:
❯ cbmc midpoint_cbmc.c --signed-overflow-check --all-properties --traceCBMC version 6.11.0 (640889b) 64-bit x86_64 linuxType-checking midpoint_cbmcGenerating GOTO ProgramAdding CPROVER library (x86_64)Removal of function pointers and virtual functionsGeneric Property Instrumentation122 collapsed lines
Starting Bounded Model CheckingPassing problem to propositional reductionconverting SSARunning propositional reductionSAT checker: instance is SATISFIABLEBuilding error traceRunning propositional reductionSAT checker: instance is SATISFIABLEBuilding error traceRunning propositional reductionSAT checker: instance is UNSATISFIABLE
** Results:midpoint_cbmc.c function main[main.assertion.1] line 13 midpoint is inside the interval: FAILURE[main.assertion.2] line 15 midpoint has the expected offset: FAILURE[main.overflow.1] line 15 arithmetic overflow on signed - in mid - low: SUCCESS[main.overflow.2] line 15 arithmetic overflow on signed - in high - low: SUCCESS
midpoint_cbmc.c function midpoint[midpoint.overflow.1] line 3 arithmetic overflow on signed + in low / 2 + high / 2: SUCCESS
Trace for main.assertion.1:
State 13 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- return_value_nondet_int=1 (00000000 00000000 00000000 00000001)
State 14 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- low=1 (00000000 00000000 00000000 00000001)
State 17 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- return_value_nondet_int$0=1 (00000000 00000000 00000000 00000001)
State 18 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- high=1 (00000000 00000000 00000000 00000001)
Assumption: file midpoint_cbmc.c line 9 function main 0 <= low && low <= high
State 24 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- low=1 (00000000 00000000 00000000 00000001)
State 25 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- high=1 (00000000 00000000 00000000 00000001)
State 27 file midpoint_cbmc.c function midpoint line 3 thread 0---------------------------------------------------- goto_symex$$return_value$$midpoint=0 (00000000 00000000 00000000 00000000)
State 29 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- return_value_midpoint=0 (00000000 00000000 00000000 00000000)
State 30 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- mid=0 (00000000 00000000 00000000 00000000)
Violated property: file midpoint_cbmc.c function main line 13 thread 0 midpoint is inside the interval low <= mid && mid <= high
Trace for main.assertion.2:
State 13 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- return_value_nondet_int=1 (00000000 00000000 00000000 00000001)
State 14 file midpoint_cbmc.c function main line 6 thread 0---------------------------------------------------- low=1 (00000000 00000000 00000000 00000001)
State 17 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- return_value_nondet_int$0=3 (00000000 00000000 00000000 00000011)
State 18 file midpoint_cbmc.c function main line 7 thread 0---------------------------------------------------- high=3 (00000000 00000000 00000000 00000011)
Assumption: file midpoint_cbmc.c line 9 function main 0 <= low && low <= high
State 24 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- low=1 (00000000 00000000 00000000 00000001)
State 25 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- high=3 (00000000 00000000 00000000 00000011)
State 27 file midpoint_cbmc.c function midpoint line 3 thread 0---------------------------------------------------- goto_symex$$return_value$$midpoint=1 (00000000 00000000 00000000 00000001)
State 29 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- return_value_midpoint=1 (00000000 00000000 00000000 00000001)
State 30 file midpoint_cbmc.c function main line 11 thread 0---------------------------------------------------- mid=1 (00000000 00000000 00000000 00000001)
Violated property: file midpoint_cbmc.c function main line 15 thread 0 midpoint has the expected offset mid - low == (high - low) / 2
** 2 of 5 failed (3 iterations)VERIFICATION FAILED从断言中可知一组失败的值为 low = 1; high = 1; mid = 0,此时有 low / 2 = 0; high / 2 = 0,二者之和为 0 ,而正确的较小中点为 1 。产生该结果的原因是计算整数除法时产生舍入误差。
任务4:比较软件测试与形式化验证
-
任务 1 中
low = 0; high = 0; mid = 0通过测试,而任务 2 中low = 177393664; high = 1981235200; mid = -1068169216产生了溢出,两组数据都满足 的条件。前一组输入通过只能说明程序在该用例上的正确性,不能排除其他输入可能产生的错误。 -
修正后的结果:
Terminal window ❯ ./midpoint_test.out177393664 19812352001079314432该条测试可以防止
low + high产生有符号整数溢出的错误出现。 -
验证结论:
- 适用的输入条件:
- 使用的整数类型:
int - 已经检查的溢出性质:
low + high产生有符号整数溢出 - 功能性质:结果仍在原区间中;结果与
low的距离等于区间长度的一半 - 没有检查的输入与程序行为:没有检查整数类型为其他类型的行为;没有检查输入值超过
int类型范围的情况
-
软件测试可以发现特定情形下的问题,软件验证覆盖更广泛,但相应实现难度更高。要根据具体场景选择使用。