Module Name:    src
Committed By:   kamil
Date:           Wed May 31 00:45:59 UTC 2017

Modified Files:
        src/sys/sys: event.h

Log Message:
Convert EV_SET from macro to static __inline function

LLDB introduced support for kevent(2) and it contains the following function:

Status MainLoop::RunImpl::Poll() {
  in_events.resize(loop.m_read_fds.size());
  unsigned i = 0;
  for (auto &fd : loop.m_read_fds)
    EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
  num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
                      out_events, llvm::array_lengthof(out_events), nullptr);
  if (num_events < 0)
    return Status("kevent() failed with error %d\n", num_events);
  return Status();
}

It works on FreeBSD and MacOSX, however it broke on NetBSD.

Culrpit line:
   EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);

FreeBSD defined EV_SET() as a macro this way:
#define EV_SET(kevp_, a, b, c, d, e, f) do {    \
        struct kevent *kevp = (kevp_);          \
        (kevp)->ident = (a);                    \
        (kevp)->filter = (b);                   \
        (kevp)->flags = (c);                    \
        (kevp)->fflags = (d);                   \
        (kevp)->data = (e);                     \
        (kevp)->udata = (f);                    \
} while(0)

NetBSD version was different:
#define EV_SET(kevp, a, b, c, d, e, f)                                  \
do {                                                                    \
        (kevp)->ident = (a);                                            \
        (kevp)->filter = (b);                                           \
        (kevp)->flags = (c);                                            \
        (kevp)->fflags = (d);                                           \
        (kevp)->data = (e);                                             \
        (kevp)->udata = (f);                                            \
} while (/* CONSTCOND */ 0)

This resulted in heap damage, as keyp was incremented every time value was
assigned to (keyp)->.

As suggested by Joerg, convert this macro on NetBSD to static __inline
function.

Credit to <coypu> for asan+ubsan research wiki entry that helped to narrow
down the bug.
Credit to <joerg> for peer-review

Sponsored by <The NetBSD Foundation>


To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/sys/event.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/sys/event.h
diff -u src/sys/sys/event.h:1.26 src/sys/sys/event.h:1.27
--- src/sys/sys/event.h:1.26	Sun Jan 31 04:40:01 2016
+++ src/sys/sys/event.h	Wed May 31 00:45:59 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: event.h,v 1.26 2016/01/31 04:40:01 christos Exp $	*/
+/*	$NetBSD: event.h,v 1.27 2017/05/31 00:45:59 kamil Exp $	*/
 
 /*-
  * Copyright (c) 1999,2000,2001 Jonathan Lemon <jle...@freebsd.org>
@@ -45,17 +45,6 @@
 #define	EVFILT_TIMER		6U	/* arbitrary timer (in ms) */
 #define	EVFILT_SYSCOUNT		7U	/* number of filters */
 
-#define	EV_SET(kevp, a, b, c, d, e, f)					\
-do {									\
-	(kevp)->ident = (a);						\
-	(kevp)->filter = (b);						\
-	(kevp)->flags = (c);						\
-	(kevp)->fflags = (d);						\
-	(kevp)->data = (e);						\
-	(kevp)->udata = (f);						\
-} while (/* CONSTCOND */ 0)
-
-
 struct kevent {
 	uintptr_t	ident;		/* identifier for this event */
 	uint32_t	filter;		/* filter for event */
@@ -65,6 +54,18 @@ struct kevent {
 	intptr_t	udata;		/* opaque user data identifier */
 };
 
+static __inline void
+EV_SET(struct kevent *_kevp, uintptr_t _ident, uint32_t _filter,
+       uint32_t _flags, uint32_t _fflags, int64_t _data, intptr_t _udata)
+{
+	_kevp->ident = _ident;
+	_kevp->filter = _filter;
+	_kevp->flags = _flags;
+	_kevp->fflags = _fflags;
+	_kevp->data = _data;
+	_kevp->udata = _udata;
+}
+
 /* actions */
 #define	EV_ADD		0x0001U		/* add event to kq (implies ENABLE) */
 #define	EV_DELETE	0x0002U		/* delete event from kq */

Reply via email to