char *getcwd(char *buf, size_t size) { static int n_calls = 0; int r; n_calls++; if (__exe_fs.max_failures && *__exe_fs.getcwd_fail == n_calls) { __exe_fs.max_failures--; errno = ERANGE; return NULL; } if (!buf) { if (!size) size = 1024; buf = malloc(size); } buf = __concretize_ptr(buf); size = __concretize_size(size); /* XXX In terms of looking for bugs we really should do this check before concretization, at least once the routine has been fixed to properly work with symbolics. */ klee_check_memory_access(buf, size); r = syscall(__NR_getcwd, buf, size); if (r == -1) return NULL; return buf; }
int main() { char buf[4]; klee_check_memory_access(&buf, 1); printf("good\n"); if (klee_range(0, 2, "range1")) { klee_check_memory_access(0, 1); printf("null pointer deref: bad\n"); } if (klee_range(0, 2, "range2")) { klee_check_memory_access(buf, 5); printf("oversize access: bad\n"); } return 0; }
ssize_t write(int fd, const void *buf, size_t count) { static int n_calls = 0; exe_file_t *f; n_calls++; f = __get_file(fd); if (!f) { errno = EBADF; return -1; } if (__exe_fs.max_failures && *__exe_fs.write_fail == n_calls) { __exe_fs.max_failures--; errno = EIO; return -1; } if (!f->dfile) { int r; buf = __concretize_ptr(buf); count = __concretize_size(count); /* XXX In terms of looking for bugs we really should do this check before concretization, at least once the routine has been fixed to properly work with symbolics. */ klee_check_memory_access(buf, count); if (f->fd == 1 || f->fd == 2) r = syscall(__NR_write, f->fd, buf, count); else r = syscall(__NR_pwrite64, f->fd, buf, count, (off64_t) f->off); if (r == -1) return -1; assert(r >= 0); if (f->fd != 1 && f->fd != 2) f->off += r; return r; } else { /* symbolic file */ size_t actual_count = 0; if (f->off + count <= f->dfile->size) actual_count = count; else { if (__exe_env.save_all_writes) assert(0); else { if (f->off < (off64_t) f->dfile->size) actual_count = f->dfile->size - f->off; } } if (actual_count) memcpy(f->dfile->contents + f->off, buf, actual_count); if (count != actual_count) klee_warning("write() ignores bytes.\n"); if (f->dfile == __exe_fs.sym_stdout) __exe_fs.stdout_writes += actual_count; f->off += count; return count; } }
ssize_t read(int fd, void *buf, size_t count) { static int n_calls = 0; exe_file_t *f; n_calls++; if (count == 0) return 0; if (buf == NULL) { errno = EFAULT; return -1; } f = __get_file(fd); if (!f) { errno = EBADF; return -1; } if (__exe_fs.max_failures && *__exe_fs.read_fail == n_calls) { __exe_fs.max_failures--; errno = EIO; return -1; } if (!f->dfile) { /* concrete file */ int r; buf = __concretize_ptr(buf); count = __concretize_size(count); /* XXX In terms of looking for bugs we really should do this check before concretization, at least once the routine has been fixed to properly work with symbolics. */ klee_check_memory_access(buf, count); if (f->fd == 0) r = syscall(__NR_read, f->fd, buf, count); else r = syscall(__NR_pread64, f->fd, buf, count, (off64_t) f->off); if (r == -1) return -1; if (f->fd != 0) f->off += r; return r; } else { assert(f->off >= 0); if (((off64_t)f->dfile->size) < f->off) return 0; /* symbolic file */ if (f->off + count > f->dfile->size) { count = f->dfile->size - f->off; } memcpy(buf, f->dfile->contents + f->off, count); f->off += count; return count; } }