Skip to content

Commit bb1f597

Browse files
Saveliy Grigoryevladisgin
Saveliy Grigoryev
authored andcommitted
Add support stdin/stdout with interactive mode
Implement getc, fgetc, fread, fgets, getchar, gets, putc, fputc, fwrite, fputs, putchar, puts
1 parent 73701e2 commit bb1f597

20 files changed

+556
-8
lines changed

Diff for: include/klee/klee.h

+4
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,8 @@ long double klee_rintl(long double d);
209209
}
210210
#endif
211211

212+
//UTBot uses these functions to wrap user functions which work with stdin/stdout
213+
void klee_init_env(int *argcPtr, char ***argvPtr);
214+
void check_stdin_read();
215+
212216
#endif /* KLEE_H */

Diff for: lib/Runner/run_klee.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ cl::opt<std::string>
147147
cl::desc("Function in which to start execution (default=main)"),
148148
cl::init("main"), cl::cat(StartCat));
149149

150+
cl::opt<bool> UTBotMode("utbot", cl::desc("Klee was launched by utbot"),
151+
cl::init(false), cl::cat(StartCat));
152+
150153
cl::opt<bool> InteractiveMode("interactive",
151154
cl::desc("Launch klee in interactive mode."),
152155
cl::init(false), cl::cat(StartCat));
@@ -1761,8 +1764,21 @@ int run_klee(int argc, char **argv, char **envp) {
17611764
klee_error("error loading POSIX support '%s': %s", Path.c_str(),
17621765
errorMsg.c_str());
17631766

1764-
std::string libcPrefix = (Libc == LibcType::UcLibc ? "__user_" : "");
1765-
preparePOSIX(loadedModules, libcPrefix);
1767+
if (Libc != LibcType::UcLibc) {
1768+
SmallString<128> Path_io(Opts.LibraryDir);
1769+
llvm::sys::path::append(Path_io, "libkleeRuntimeIO_C" + opt_suffix + ".bca");
1770+
klee_message("NOTE: using klee versions of input/output functions: %s",
1771+
Path_io.c_str());
1772+
if (!klee::loadFile(Path_io.c_str(), mainModule->getContext(), loadedModules,
1773+
errorMsg))
1774+
klee_error("error loading POSIX_IO support '%s': %s", Path_io.c_str(),
1775+
errorMsg.c_str());
1776+
}
1777+
1778+
if (!UTBotMode) {
1779+
std::string libcPrefix = (Libc == LibcType::UcLibc ? "__user_" : "");
1780+
preparePOSIX(loadedModules, libcPrefix);
1781+
}
17661782
}
17671783

17681784
if (WithFPRuntime) {

Diff for: runtime/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ if (ENABLE_KLEE_EH_CXX)
108108
endif ()
109109

110110
if (ENABLE_POSIX_RUNTIME)
111-
list(APPEND RUNTIME_LIBRARIES RuntimePOSIX)
111+
list(APPEND RUNTIME_LIBRARIES "RuntimePOSIX;RuntimeIO_C")
112112
add_subdirectory(POSIX)
113113
endif ()
114114

Diff for: runtime/POSIX/CMakeLists.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ set(SRC_FILES
2323
# Build it
2424
include("${CMAKE_SOURCE_DIR}/cmake/compile_bitcode_library.cmake")
2525
prefix_with_path("${SRC_FILES}" "${CMAKE_CURRENT_SOURCE_DIR}/" prefixed_files)
26-
add_bitcode_library_targets("${LIB_PREFIX}" "${prefixed_files}" "-std=gnu89" "")
26+
add_bitcode_library_targets("${LIB_PREFIX}" "${prefixed_files}" "-std=gnu89" "")
27+
28+
prefix_with_path(input_output.c "${CMAKE_CURRENT_SOURCE_DIR}/" io_file)
29+
add_bitcode_library_targets("RuntimeIO_C" "${io_file}" "-std=gnu89" "")

Diff for: runtime/POSIX/fd.c

-2
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,6 @@ ssize_t read(int fd, void *buf, size_t count) {
408408
}
409409
}
410410

411-
412411
ssize_t write(int fd, const void *buf, size_t count) {
413412
static int n_calls = 0;
414413
exe_file_t *f;
@@ -481,7 +480,6 @@ ssize_t write(int fd, const void *buf, size_t count) {
481480
}
482481
}
483482

484-
485483
off64_t __fd_lseek(int fd, off64_t offset, int whence) {
486484
off64_t new_off;
487485
exe_file_t *f = __get_file(fd);

Diff for: runtime/POSIX/input_output.c

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#include <stdio.h>
2+
3+
int fgetc(FILE *stream) {
4+
int fd = fileno(stream);
5+
unsigned char buf;
6+
ssize_t read_byte = read(fd, &buf, 1);
7+
if (read_byte == 1) {
8+
return buf;
9+
} else {
10+
return EOF;
11+
}
12+
}
13+
14+
int getc(FILE *stream) {
15+
int fd = fileno(stream);
16+
unsigned char buf;
17+
ssize_t read_byte = read(fd, &buf, 1);
18+
if (read_byte == 1) {
19+
return buf;
20+
} else {
21+
return EOF;
22+
}
23+
}
24+
25+
size_t fread(void *buffer, size_t size, size_t count, FILE *stream) {
26+
int fd = fileno(stream);
27+
ssize_t read_byte = read(fd, buffer, size * count);
28+
if (read_byte == -1) {
29+
return 0;
30+
}
31+
return read_byte / size;
32+
}
33+
34+
char* fgets(char *s, int n, FILE *stream)
35+
{
36+
char *p = s;
37+
if (s == NULL || n <= 0 || ferror(stream) || feof(stream)) {
38+
return NULL;
39+
}
40+
41+
int c = 0;
42+
while (--n > 0 && (c = getc(stream)) != EOF) {
43+
if ((*p++ = c) == '\n') {
44+
break;
45+
}
46+
}
47+
if (ferror(stream) || (c == EOF && p == s)) {
48+
return NULL;
49+
}
50+
*p = '\0';
51+
return s;
52+
}
53+
54+
int getchar(void) {
55+
return getc(stdin);
56+
}
57+
58+
char* gets(char *s)
59+
{
60+
char *p = s;
61+
if (s == NULL || ferror(stdin) || feof(stdin)) {
62+
return NULL;
63+
}
64+
65+
int c = 0;
66+
while ((c = getchar()) != EOF) {
67+
if (c == '\n') {
68+
break;
69+
}
70+
*p++ = c;
71+
}
72+
if (ferror(stdin) || (c == EOF && p == s)) {
73+
return NULL;
74+
}
75+
*p = '\0';
76+
return s;
77+
}
78+
79+
int fputc(int c, FILE *stream) {
80+
int fd = fileno(stream);
81+
unsigned char symb = c;
82+
int write_byte = write(fd, &symb, 1);
83+
if (write_byte == 1) {
84+
return c;
85+
} else {
86+
return EOF;
87+
}
88+
}
89+
90+
int putc(int c, FILE *stream) {
91+
int fd = fileno(stream);
92+
unsigned char symb = c;
93+
int write_byte = write(fd, &symb, 1);
94+
if (write_byte == 1) {
95+
return c;
96+
} else {
97+
return EOF;
98+
}
99+
}
100+
101+
size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream) {
102+
int fd = fileno(stream);
103+
void *cop_buf = buffer;
104+
int write_byte = write(fd, cop_buf, size * count);
105+
if (write == -1) {
106+
return 0;
107+
}
108+
return write_byte / size;
109+
}
110+
111+
int fputs(const char *str, FILE *stream) {
112+
if (str == NULL) {
113+
return EOF;
114+
}
115+
116+
while (*str != '\0') {
117+
unsigned char c = *str;
118+
fputc(c, stream);
119+
str++;
120+
}
121+
122+
return 1;
123+
}
124+
125+
int putchar(int c) {
126+
return putc(c, stdout);
127+
}
128+
129+
int puts(const char *str) {
130+
int write_code = fputs(str, stdout);
131+
if (write_code == EOF) {
132+
return EOF;
133+
}
134+
write_code = putchar('\n');
135+
if (write_code == EOF) {
136+
return EOF;
137+
}
138+
return 1;
139+
}

Diff for: runtime/POSIX/klee_init_env.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,14 @@ usage: (klee_init_env) [options] [program arguments]\n\
239239
* and is renamed during POSIX setup */
240240
int __klee_posix_wrapped_main(int argc, char **argv, char **envp);
241241

242+
void check_stdin_read() {
243+
klee_assume(__exe_env.stdin_off == __exe_env.max_off);
244+
}
245+
242246
/* This wrapper gets called instead of main if POSIX setup is used */
243247
int __klee_posix_wrapper(int argcPtr, char **argvPtr, char** envp) {
244248
klee_init_env(&argcPtr, &argvPtr);
245249
int res = __klee_posix_wrapped_main(argcPtr, argvPtr, envp);
246-
klee_assume(__exe_env.stdin_off == __exe_env.max_off);
250+
check_stdin_read();
247251
return res;
248252
}

Diff for: runtime/klee-libc/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ set(SRC_FILES
1919
htonl.c
2020
memchr.c
2121
mempcpy.c
22-
putchar.c
22+
# putchar.c
2323
stpcpy.c
2424
strcat.c
2525
strchr.c

Diff for: test/Runtime/POSIX/fgetc_example.c

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %clang %s -emit-llvm -g %O0opt -c -o %t.bc
2+
// RUN: rm -rf %t.klee-out
3+
// RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-stdin 64
4+
// RUN: test -f %t.klee-out/test000001.ktestjson
5+
// RUN: test -f %t.klee-out/test000002.ktestjson
6+
// RUN: test -f %t.klee-out/test000003.ktestjson
7+
// RUN: test -f %t.klee-out/test000004.ktestjson
8+
// RUN: test -f %t.klee-out/test000005.ktestjson
9+
// RUN: test -f %t.klee-out/test000006.ktestjson
10+
// RUN: test -f %t.klee-out/test000007.ktestjson
11+
// RUN: test -f %t.klee-out/test000008.ktestjson
12+
// RUN: test -f %t.klee-out/test000009.ktestjson
13+
// RUN: test -f %t.klee-out/test000010.ktestjson
14+
// RUN: test -f %t.klee-out/test000011.ktestjson
15+
// RUN: test -f %t.klee-out/test000012.ktestjson
16+
// RUN: test -f %t.klee-out/test000013.ktestjson
17+
// RUN: not test -f %t.klee-out/test000014.ktestjson
18+
19+
#include <stdio.h>
20+
21+
int main() {
22+
unsigned char x = fgetc(stdin);
23+
if (x >= '0' && x <= '9') {
24+
unsigned char a = fgetc(stdin);
25+
if (a >= 'a' && a <= 'z') {
26+
return 1;
27+
} else {
28+
return 2;
29+
}
30+
} else {
31+
unsigned char a = fgetc(stdin);
32+
unsigned char b = fgetc(stdin);
33+
if (a >= 'a' && a <= 'z') {
34+
if (b >= '0' && b <= '9') {
35+
return 3;
36+
} else {
37+
return 4;
38+
}
39+
} else {
40+
return 5;
41+
}
42+
}
43+
}

Diff for: test/Runtime/POSIX/fgets_example.c

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clang %s -emit-llvm -g %O0opt -c -o %t.bc
2+
// RUN: rm -rf %t.klee-out
3+
// RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-stdin 64
4+
// RUN: test -f %t.klee-out/test000001.ktestjson
5+
// RUN: test -f %t.klee-out/test000002.ktestjson
6+
// RUN: test -f %t.klee-out/test000003.ktestjson
7+
// RUN: test -f %t.klee-out/test000004.ktestjson
8+
// RUN: test -f %t.klee-out/test000005.ktestjson
9+
// RUN: test -f %t.klee-out/test000006.ktestjson
10+
// RUN: test -f %t.klee-out/test000007.ktestjson
11+
// RUN: test -f %t.klee-out/test000008.ktestjson
12+
// RUN: test -f %t.klee-out/test000009.ktestjson
13+
// RUN: test -f %t.klee-out/test000010.ktestjson
14+
// RUN: test -f %t.klee-out/test000011.ktestjson
15+
// RUN: test -f %t.klee-out/test000012.ktestjson
16+
// RUN: test -f %t.klee-out/test000013.ktestjson
17+
// RUN: test -f %t.klee-out/test000014.ktestjson
18+
// RUN: test -f %t.klee-out/test000015.ktestjson
19+
// RUN: test -f %t.klee-out/test000016.ktestjson
20+
// RUN: test -f %t.klee-out/test000017.ktestjson
21+
// RUN: test -f %t.klee-out/test000018.ktestjson
22+
// RUN: test -f %t.klee-out/test000019.ktestjson
23+
// RUN: test -f %t.klee-out/test000020.ktestjson
24+
// RUN: test -f %t.klee-out/test000021.ktestjson
25+
// RUN: not test -f %t.klee-out/test000022.ktestjson
26+
27+
#include <stdio.h>
28+
29+
int main() {
30+
char a[8];
31+
fgets(a, 6, stdin);
32+
if (a[0] == 'u' && a[1] == 't' && a[2] == 'b' && a[3] == 'o' && a[4] == 't') {
33+
return 1;
34+
}
35+
return 0;
36+
}

Diff for: test/Runtime/POSIX/fputc_example.c

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %clang %s -emit-llvm -g %O0opt -c -o %t.bc
2+
// RUN: rm -rf %t.klee-out
3+
// RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-stdin 64
4+
// RUN: test -f %t.klee-out/test000001.ktestjson
5+
// RUN: test -f %t.klee-out/test000002.ktestjson
6+
// RUN: test -f %t.klee-out/test000003.ktestjson
7+
// RUN: not test -f %t.klee-out/test000004.ktestjson
8+
9+
#include "klee/klee.h"
10+
#include <stdio.h>
11+
12+
char simple_fputc(int x, int y) {
13+
if (x < y) {
14+
fputc('<', stdout);
15+
return '<';
16+
} else if (x > y) {
17+
fputc('>', stdout);
18+
return '>';
19+
} else {
20+
fputc('=', stdout);
21+
return '=';
22+
}
23+
}
24+
25+
int main() {
26+
int x, y;
27+
klee_make_symbolic(&x, sizeof(int), "x");
28+
klee_make_symbolic(&y, sizeof(int), "y");
29+
char c = simple_fputc(x, y);
30+
return 0;
31+
}

Diff for: test/Runtime/POSIX/fputs_example.c

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang %s -emit-llvm -g %O0opt -c -o %t.bc
2+
// RUN: rm -rf %t.klee-out
3+
// RUN: %klee --output-dir=%t.klee-out --posix-runtime %t.bc --sym-stdin 64
4+
// RUN: test -f %t.klee-out/test000001.ktestjson
5+
// RUN: test -f %t.klee-out/test000002.ktestjson
6+
// RUN: test -f %t.klee-out/test000003.ktestjson
7+
// RUN: test -f %t.klee-out/test000004.ktestjson
8+
// RUN: test -f %t.klee-out/test000005.ktestjson
9+
// RUN: test -f %t.klee-out/test000006.ktestjson
10+
// RUN: not test -f %t.klee-out/test000007.ktestjson
11+
12+
#include "klee/klee.h"
13+
#include <stdio.h>
14+
15+
char simple_fputs(char c) {
16+
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
17+
char a[] = "Vowel";
18+
fputs("Vowel", stdout);
19+
return 'V';
20+
} else {
21+
char a[] = "Consonant";
22+
fputs("Consonant", stdout);
23+
return 'C';
24+
}
25+
}
26+
27+
int main() {
28+
char c;
29+
klee_make_symbolic(&c, sizeof(char), "c");
30+
char d = simple_fputs(c);
31+
return 0;
32+
}

0 commit comments

Comments
 (0)