Skip to content

Commit c864ba9

Browse files
authored
Merge pull request #7916 from tautschnig/bugfixes/getopt-model
C library: fix and test getopt model
2 parents d3b4475 + 2a3f8d1 commit c864ba9

File tree

4 files changed

+98
-37
lines changed

4 files changed

+98
-37
lines changed
Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,34 @@
11
#include <assert.h>
2-
#include <getopt.h>
2+
#ifndef _WIN32
3+
# include <getopt.h>
4+
#else
5+
extern char *optarg;
6+
extern int optind;
7+
int getopt(int argc, char *const argv[], const char *optstring);
8+
#endif
9+
#include <stdlib.h>
310

411
int main()
512
{
6-
getopt();
7-
assert(0);
13+
int argc = 3;
14+
char *argv[] = {"my_program", "-t", "10", NULL};
15+
16+
int opt;
17+
int nsecs = 0;
18+
19+
while((opt = getopt(argc, argv, "t:")) != -1)
20+
{
21+
switch(opt)
22+
{
23+
case 't':
24+
nsecs = atoi(optarg);
25+
break;
26+
default: /* '?' */
27+
return 1;
28+
}
29+
}
30+
31+
assert(nsecs == 10);
32+
833
return 0;
934
}

regression/cbmc-library/getopt-01/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
KNOWNBUG
1+
CORE
22
main.c
3-
--pointer-check --bounds-check
3+
--pointer-check --bounds-check --unwind 3 --unwinding-assertions
44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$

src/ansi-c/library/getopt.c

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,94 @@
1-
/* FUNCTION: getopt */
2-
3-
extern char *optarg;
4-
extern int optind;
1+
/* FUNCTION: _getopt */
52

63
#ifndef __CPROVER_STRING_H_INCLUDED
74
#include <string.h>
85
#define __CPROVER_STRING_H_INCLUDED
96
#endif
107

8+
char *optarg = NULL;
9+
int optind = 1;
10+
1111
__CPROVER_bool __VERIFIER_nondet___CPROVER_bool(void);
1212
size_t __VERIFIER_nondet_size_t(void);
1313

14-
int getopt(int argc, char *const argv[], const char *optstring)
14+
int _getopt(int argc, char *const argv[], const char *optstring)
1515
{
16-
__CPROVER_HIDE:;
17-
int result=-1;
18-
19-
if(optind==0)
20-
optind=1;
16+
__CPROVER_HIDE:;
17+
// re-init requested by environment, we just reset optind
18+
if(optind == 0)
19+
optind = 1;
2120

22-
if(optind>=argc || argv[optind][0]!='-')
21+
// test whether all arguments have been processed
22+
if(optind >= argc)
23+
return -1;
24+
char *const arg = argv[optind];
25+
if(arg[0] != '-' || arg[1] == '\0' || (arg[1] == '-' && arg[2] == '\0'))
2326
return -1;
2427

25-
size_t result_index=__VERIFIER_nondet_size_t();
28+
// test whether the option is in optstring at all
29+
size_t optstring_len = strlen(optstring);
30+
// gcc doesn't know __CPROVER_forall
31+
#ifndef LIBRARY_CHECK
32+
__CPROVER_bool not_found = __CPROVER_forall
33+
{
34+
size_t i;
35+
i<optstring_len ==> optstring[i] != arg[1]
36+
};
37+
if(not_found)
38+
return '?';
39+
#endif
40+
41+
// option is in optstring, find the exact index
42+
size_t result_index = __VERIFIER_nondet_size_t();
2643
__CPROVER_assume(
27-
result_index<strlen(optstring) && optstring[result_index]!=':');
28-
#ifdef __CPROVER_STRING_ABSTRACTION
29-
__CPROVER_assert(__CPROVER_is_zero_string(optstring),
44+
result_index < optstring_len && optstring[result_index] == arg[1]);
45+
#ifdef __CPROVER_STRING_ABSTRACTION
46+
__CPROVER_assert(
47+
__CPROVER_is_zero_string(optstring),
3048
"getopt zero-termination of 3rd argument");
31-
#endif
49+
#endif
3250

33-
__CPROVER_bool found=__VERIFIER_nondet___CPROVER_bool();
34-
if(found)
51+
// is an argument required?
52+
if(result_index + 1 == optstring_len || optstring[result_index + 1] != ':')
3553
{
36-
result=optstring[result_index];
37-
__CPROVER_bool skipped=__VERIFIER_nondet___CPROVER_bool();
38-
if(skipped)
39-
++optind;
54+
optarg = NULL;
55+
return arg[1];
4056
}
4157

42-
if(result!=-1 && optind<argc && optstring[result_index+1]==':')
58+
// test whether a required argument can be found
59+
if(arg[2] != '\0')
60+
{
61+
optarg = &arg[2];
62+
return arg[1];
63+
}
64+
else if(optind + 1 < argc)
4365
{
44-
__CPROVER_bool has_no_arg=__VERIFIER_nondet___CPROVER_bool();
45-
if(has_no_arg)
46-
{
47-
optarg=argv[optind];
48-
++optind;
49-
}
50-
else
51-
optarg=NULL;
66+
optarg = argv[optind + 1];
67+
++optind;
68+
return arg[1];
5269
}
70+
else
71+
{
72+
optarg = NULL;
73+
return optstring[0] == ':' ? ':' : '?';
74+
}
75+
}
76+
77+
/* FUNCTION: getopt */
78+
79+
int _getopt(int argc, char *const argv[], const char *optstring);
5380

54-
return result;
81+
int getopt(int argc, char *const argv[], const char *optstring)
82+
{
83+
__CPROVER_HIDE:;
84+
return _getopt(argc, argv, optstring);
5585
}
5686

5787
/* FUNCTION: getopt_long */
5888

89+
#ifndef _WIN32
90+
// MSVC doesn't provide getopt.h, which we need for struct option
91+
5992
#ifndef __CPROVER_GETOPT_H_INCLUDED
6093
#include <getopt.h>
6194
#define __CPROVER_GETOPT_H_INCLUDED
@@ -77,3 +110,5 @@ int getopt_long(
77110

78111
return getopt(argc, argv, optstring);
79112
}
113+
114+
#endif

src/ansi-c/library_check.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ perl -p -i -e 's/^__CPROVER_contracts_library\n//' __functions
3232
# Some functions are implicitly covered by running on different operating
3333
# systems:
3434
perl -p -i -e 's/^_fopen\n//' __functions # fopen, macOS
35+
perl -p -i -e 's/^_getopt\n//' __functions # getopt, macOS
3536
perl -p -i -e 's/^_mmap\n//' __functions # mmap, macOS
3637
perl -p -i -e 's/^_munmap\n//' __functions # mumap, macOS
3738
perl -p -i -e 's/^_pipe\n//' __functions # pipe, macOS

0 commit comments

Comments
 (0)