diff --git a/share/dune b/share/dune index 098d41e97818127a223d5a9a46b21a30fc9acd30..6ae783ccbd6e00b9138922d1e83c90b462fa28b1 100644 --- a/share/dune +++ b/share/dune @@ -236,6 +236,7 @@ (libc/sys/sendfile.h as libc/sys/sendfile.h) (libc/sys/shm.h as libc/sys/shm.h) (libc/sys/signal.h as libc/sys/signal.h) +(libc/sys/socket.c as libc/sys/socket.c) (libc/sys/socket.h as libc/sys/socket.h) (libc/sys/stat.h as libc/sys/stat.h) (libc/sys/statvfs.h as libc/sys/statvfs.h) diff --git a/share/libc/__fc_runtime.c b/share/libc/__fc_runtime.c index 2852dae1905cdc8f89ba1ff63494e8e396590076..e266ed9e0f44b3b747f56ccb0fd83adfbbb733c8 100644 --- a/share/libc/__fc_runtime.c +++ b/share/libc/__fc_runtime.c @@ -35,6 +35,7 @@ #include "netinet/in.c" #include "pwd.c" #include "signal.c" +#include "sys/socket.c" #include "stdatomic.c" #include "stdio.c" #include "stdlib.c" diff --git a/share/libc/getopt.c b/share/libc/getopt.c index 741109e43a762820608e1fd503ea7c91b35ddc1e..472a8c9455e0aa36897a083bf3451f9580ff81af 100644 --- a/share/libc/getopt.c +++ b/share/libc/getopt.c @@ -23,6 +23,6 @@ #include "getopt.h" __PUSH_FC_STDLIB -int optind = 1; +//int optind = 1; __POP_FC_STDLIB diff --git a/share/libc/sys/socket.c b/share/libc/sys/socket.c new file mode 100644 index 0000000000000000000000000000000000000000..ca4cf1c5b5590b5e399d550e9c14fc4d493d2ed7 --- /dev/null +++ b/share/libc/sys/socket.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* This file is part of Frama-C. */ +/* */ +/* Copyright (C) 2007-2023 */ +/* CEA (Commissariat à l'énergie atomique et aux énergies */ +/* alternatives) */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 2.1. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 2.1 */ +/* for more details (enclosed in the file licenses/LGPLv2.1). */ +/* */ +/**************************************************************************/ + +#include "socket.h" +#include "../__fc_builtin.h" +__PUSH_FC_STDLIB + +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *address, socklen_t address_len) { + // assuming preconditions already checked + if (Frama_C_nondet(0, 1)) { + // error + int possible_errors[] = { + EACCES, + EAFNOSUPPORT, + EAGAIN, + EBADF, + ECONNRESET, + EDESTADDRREQ, + EHOSTUNREACH, + EINTR, + EINVAL, + EIO, + EISCONN, + ELOOP, + EMSGSIZE, + ENAMETOOLONG, + ENETDOWN, + ENETUNREACH, + ENOBUFS, + ENOENT, + ENOMEM, + ENOTCONN, + ENOTDIR, + ENOTSOCK, + EOPNOTSUPP, + EPIPE, + EWOULDBLOCK, + }; + errno = possible_errors[Frama_C_interval(0, sizeof(possible_errors)/sizeof(int)-1)]; + return -1; + } else { + // non-error + return Frama_C_long_interval(0, len); + } +} + +ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *addrbuf, socklen_t *addrbuf_len) { + // assuming preconditions already checked + if (Frama_C_nondet(0, 1)) { + // error + int possible_errors[] = { + EAGAIN, + EBADF, + ECONNRESET, + EINTR, + EINVAL, + EIO, + ENOBUFS, + ENOMEM, + ENOTCONN, + ENOTSOCK, + EOPNOTSUPP, + ETIMEDOUT, + EWOULDBLOCK, + }; + errno = possible_errors[Frama_C_interval(0, sizeof(possible_errors)/sizeof(int)-1)]; + return -1; + } else { + // non-error + ((char*)buf)[Frama_C_interval(0, len-1)] = Frama_C_interval(0, 255); + if (addrbuf) { + // simulate writing source address + socklen_t addrlen = *addrbuf_len > sizeof(struct sockaddr) ? *addrbuf_len : sizeof(struct sockaddr); + Frama_C_make_unknown((char*)addrbuf, addrlen); + /* From the "Linux Programmer's Manual: + "Upon return, 'addrbuf_len' is updated to contain the actual size of + the source address. The returned address is truncated if the buffer + provided is too small; in this case, 'addrbuf_len' will return a value + greater than was supplied to the call. */ + *addrbuf_len = addrlen; + } + return Frama_C_long_interval(0, len); + } + +} + +__POP_FC_STDLIB diff --git a/share/libc/unistd.c b/share/libc/unistd.c index 00793690ace93fb32c4a1a51feb76c062f131739..ab6770c0ad8fba00e7f5fda3897ce0639105ef6a 100644 --- a/share/libc/unistd.c +++ b/share/libc/unistd.c @@ -22,7 +22,22 @@ #include "unistd.h" #include "__fc_builtin.h" +#include "string.h" __PUSH_FC_STDLIB volatile char __fc_ttyname[TTY_NAME_MAX]; + +int optind = 1; +char *optarg; +int opterr = 1; // initial value is not zero (zero silences error messages) + +int getopt(int argc, char * const argv[], const char *optstring) { + if (argc == 0) { + return -1; + } + optind = Frama_C_interval(1, argc - 1); + optarg = Frama_C_nondet_ptr(0, &argv[optind][Frama_C_interval(0, strlen(argv[optind])-1)]); + return Frama_C_nondet(-1, Frama_C_char_interval(CHAR_MIN, CHAR_MAX)); +} + __POP_FC_STDLIB diff --git a/tests/libc/unistd_c.c b/tests/libc/unistd_c.c new file mode 100644 index 0000000000000000000000000000000000000000..0bb8b52e1d9b9374e3f1ea3538bc92f363f21301 --- /dev/null +++ b/tests/libc/unistd_c.c @@ -0,0 +1,8 @@ +#include "unistd.c" + +int main() { + int argc = 4; + char *argv[] = {"program_name", "-this", "is a", "Test0"}; + int r = getopt(argc, argv, "tes:"); + return 0; +}