Skip to content

Commit

Permalink
Merge pull request #29 from JuliaLang/gb/msan-port
Browse files Browse the repository at this point in the history
  • Loading branch information
gbaraldi authored Nov 8, 2022
2 parents e6f0e49 + 71a1a26 commit a9b8cea
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 33 deletions.
30 changes: 21 additions & 9 deletions .github/workflows/sanitizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,33 @@ on:

jobs:
sanitizers:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Setup
run: |
sudo apt-get install ninja-build
- name: Envinfo
run: npx envinfo

- name: ASAN Build
run: |
mkdir build-asan
(cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug)
cmake --build build-asan
- name: ASAN Test
run: |
./build-asan/uv_run_tests_a
- name: MSAN Build
run: |
mkdir build-msan
(cd build-msan && cmake .. -G Ninja -DBUILD_TESTING=ON -DMSAN=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang)
cmake --build build-msan
- name: MSAN Test
run: |
./build-msan/uv_run_tests_a
- name: TSAN Build
run: |
mkdir build-tsan
Expand All @@ -31,11 +50,4 @@ jobs:
continue-on-error: true # currently permit failures
run: |
./build-tsan/uv_run_tests_a
- name: ASAN Build
run: |
mkdir build-asan
(cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug)
cmake --build build-asan
- name: ASAN Test
run: |
./build-asan/uv_run_tests_a
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,34 @@ if(QEMU)
add_definitions(-D__QEMU__=1)
endif()

# Note: these are mutually exclusive.
option(ASAN "Enable AddressSanitizer (ASan)" OFF)
option(MSAN "Enable MemorySanitizer (MSan)" OFF)
option(TSAN "Enable ThreadSanitizer (TSan)" OFF)

if((ASAN OR TSAN) AND NOT (CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang"))
message(SEND_ERROR "Sanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.")
endif()


if(MSAN AND NOT CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang")
message(SEND_ERROR "MemorySanitizer requires clang. Try again with -DCMAKE_C_COMPILER=clang")
endif()

if(ASAN)
add_definitions(-D__ASAN__=1)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address")
endif()

if(MSAN)
add_definitions(-D__MSAN__=1)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=memory")
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=memory")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=memory")
endif()

if(TSAN)
add_definitions(-D__TSAN__=1)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=thread")
Expand Down
4 changes: 2 additions & 2 deletions src/unix/aix.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) {
static int uv__path_is_a_directory(char* filename) {
struct stat statbuf;

if (stat(filename, &statbuf) < 0)
if (uv__stat(filename, &statbuf) < 0)
return -1; /* failed: not a directory, assume it is a file */

if (statbuf.st_type == VDIR)
Expand Down Expand Up @@ -888,7 +888,7 @@ char** uv_setup_args(int argc, char** argv) {
size = sizeof(exepath);
if (uv__search_path(argv[0], exepath, &size) == 0) {
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_lock(&process_title_mutex);
uv_mutex_lock(&process_title_mutex);
original_exepath = uv__strdup(exepath);
uv_mutex_unlock(&process_title_mutex);
}
Expand Down
14 changes: 7 additions & 7 deletions src/unix/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
if (result == -1 && errno == EOPNOTSUPP) {
struct stat buf;
ssize_t rc;
rc = fstat(req->file, &buf);
rc = uv__fstat(req->file, &buf);
if (rc == 0 && S_ISDIR(buf.st_mode)) {
errno = EISDIR;
}
Expand Down Expand Up @@ -768,7 +768,7 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
/* We may not have a real PATH_MAX. Read size of link. */
struct stat st;
int ret;
ret = lstat(req->path, &st);
ret = uv__lstat(req->path, &st);
if (ret != 0)
return -1;
if (!S_ISLNK(st.st_mode)) {
Expand Down Expand Up @@ -1349,7 +1349,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
srcfd = fs_req.result;

/* Get the source file's mode. */
if (fstat(srcfd, &src_statsbuf)) {
if (uv__fstat(srcfd, &src_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
Expand Down Expand Up @@ -1378,7 +1378,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
destination are not the same file. If they are the same, bail out early. */
if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) {
/* Get the destination file's mode. */
if (fstat(dstfd, &dst_statsbuf)) {
if (uv__fstat(dstfd, &dst_statsbuf)) {
err = UV__ERR(errno);
goto out;
}
Expand Down Expand Up @@ -1657,7 +1657,7 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) {
if (ret != UV_ENOSYS)
return ret;

ret = stat(path, &pbuf);
ret = uv__stat(path, &pbuf);
if (ret == 0)
uv__to_stat(&pbuf, buf);

Expand All @@ -1673,7 +1673,7 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
if (ret != UV_ENOSYS)
return ret;

ret = lstat(path, &pbuf);
ret = uv__lstat(path, &pbuf);
if (ret == 0)
uv__to_stat(&pbuf, buf);

Expand All @@ -1689,7 +1689,7 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
if (ret != UV_ENOSYS)
return ret;

ret = fstat(fd, &pbuf);
ret = uv__fstat(fd, &pbuf);
if (ret == 0)
uv__to_stat(&pbuf, buf);

Expand Down
47 changes: 47 additions & 0 deletions src/unix/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@
#include <errno.h>
#include <sys/socket.h>

#include <sys/stat.h>
#include <sys/types.h>

#define uv__msan_unpoison(p, n) \
do { \
(void) (p); \
(void) (n); \
} while (0)

#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# include <sanitizer/msan_interface.h>
# undef uv__msan_unpoison
# define uv__msan_unpoison __msan_unpoison
# endif
#endif

#if defined(__linux__)
# include "linux-syscalls.h"
#endif /* __linux__ */
Expand Down Expand Up @@ -310,6 +327,36 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) {
return s + 1;
}

UV_UNUSED(static int uv__fstat(int fd, struct stat* s)) {
int rc;

rc = fstat(fd, s);
if (rc >= 0)
uv__msan_unpoison(s, sizeof(*s));

return rc;
}

UV_UNUSED(static int uv__lstat(const char* path, struct stat* s)) {
int rc;

rc = lstat(path, s);
if (rc >= 0)
uv__msan_unpoison(s, sizeof(*s));

return rc;
}

UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) {
int rc;

rc = stat(path, s);
if (rc >= 0)
uv__msan_unpoison(s, sizeof(*s));

return rc;
}

typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);

int uv__getsockpeername(const uv_handle_t* handle,
Expand Down
2 changes: 1 addition & 1 deletion src/unix/kqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
handle->realpath_len = 0;
handle->cf_flags = flags;

if (fstat(fd, &statbuf))
if (uv__fstat(fd, &statbuf))
goto fallback;
/* FSEvents works only with directories */
if (!(statbuf.st_mode & S_IFDIR))
Expand Down
59 changes: 55 additions & 4 deletions src/unix/linux-syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
*/

#include "linux-syscalls.h"
#include "internal.h"
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>


#if defined(__arm__)
# if defined(__thumb__) || defined(__ARM_EABI__)
Expand Down Expand Up @@ -167,6 +171,35 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
}


static void uv__recvmmsg_unpoison(struct uv__mmsghdr* mmsg, int rc) {
struct uv__mmsghdr* m;
struct msghdr* h;
struct iovec* v;
size_t j;
int i;

for (i = 0; i < rc; i++) {
m = mmsg + i;
uv__msan_unpoison(m, sizeof(*m));

h = &m->msg_hdr;
if (h->msg_name != NULL)
uv__msan_unpoison(h->msg_name, h->msg_namelen);

if (h->msg_iov != NULL)
uv__msan_unpoison(h->msg_iov, h->msg_iovlen * sizeof(*h->msg_iov));

for (j = 0; j < h->msg_iovlen; j++) {
v = h->msg_iov + j;
uv__msan_unpoison(v->iov_base, v->iov_len);
}

if (h->msg_control != NULL)
uv__msan_unpoison(h->msg_control, h->msg_controllen);
}
}


int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
#if defined(__i386__)
unsigned long args[5];
Expand All @@ -180,13 +213,19 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {

/* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */
rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args);
uv__recvmmsg_unpoison(mmsg, rc);
if (rc == -1)
if (errno == EINVAL)
errno = ENOSYS;

return rc;
#elif defined(__NR_recvmmsg)
return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0);
int rc;

rc = syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0);
uv__recvmmsg_unpoison(mmsg, rc);

return rc;
#else
return errno = ENOSYS, -1;
#endif
Expand Down Expand Up @@ -250,15 +289,27 @@ int uv__statx(int dirfd,
#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30
return errno = ENOSYS, -1;
#else
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
int rc;

rc = syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
if (rc >= 0)
uv__msan_unpoison(statxbuf, sizeof(*statxbuf));

return rc;
#endif
}


ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28
return errno = ENOSYS, -1;
#else
return syscall(__NR_getrandom, buf, buflen, flags);
ssize_t rc;

rc = syscall(__NR_getrandom, buf, buflen, flags);
if (rc >= 0)
uv__msan_unpoison(buf, buflen);

return rc;
#endif
}
1 change: 1 addition & 0 deletions src/unix/linux-syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <sys/time.h>
#include <sys/socket.h>


struct uv__statx_timestamp {
int64_t tv_sec;
uint32_t tv_nsec;
Expand Down
4 changes: 2 additions & 2 deletions src/unix/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ void uv_pipe_connect(uv_connect_t* req,
size_t name_len;

name_len = strlen(name);

if (name_len > sizeof(saddr.sun_path) - 1) {
err = -ENAMETOOLONG;
goto out;
Expand Down Expand Up @@ -371,7 +371,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
}

/* stat must be used as fstat has a bug on Darwin */
if (stat(name_buffer, &pipe_stat) == -1) {
if (uv__stat(name_buffer, &pipe_stat) == -1) {
uv__free(name_buffer);
return -errno;
}
Expand Down
2 changes: 1 addition & 1 deletion src/unix/random-devurandom.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ int uv__random_readpath(const char* path, void* buf, size_t buflen) {
if (fd < 0)
return fd;

if (fstat(fd, &s)) {
if (uv__fstat(fd, &s)) {
uv__close(fd);
return UV__ERR(errno);
}
Expand Down
6 changes: 3 additions & 3 deletions src/unix/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
*/
static int isreallyatty(int file) {
int rc;

rc = !ioctl(file, TXISATTY + 0x81, NULL);
if (!rc && errno != EBADF)
errno = ENOTTY;
Expand Down Expand Up @@ -113,7 +113,7 @@ static int uv__tty_is_slave(const int fd) {
}

/* Lookup stat structure behind the file descriptor. */
if (fstat(fd, &sb) != 0)
if (uv__fstat(fd, &sb) != 0)
abort();

/* Assert character device. */
Expand Down Expand Up @@ -360,7 +360,7 @@ uv_handle_type uv_guess_handle(uv_os_fd_t file) {
if (isatty(file))
return UV_TTY;

if (fstat(file, &s)) {
if (uv__fstat(file, &s)) {
#if defined(__PASE__)
/* On ibmi receiving RST from TCP instead of FIN immediately puts fd into
* an error state. fstat will return EINVAL, getsockname will also return
Expand Down
Loading

0 comments on commit a9b8cea

Please sign in to comment.