aboutsummaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2018-04-03 19:36:00 +0000
committerCy Schubert <cy@FreeBSD.org>2018-04-03 19:36:00 +0000
commitb0e4d68d5124581ae353493d69bea352de4cff8a (patch)
tree43300ec43e83eccd367fd76fdfdefba2dcd7d8f4 /src/util
parent33a9b234e7087f573ef08cd7318c6497ba08b439 (diff)
downloadsrc-vendor/krb5.tar.gz
src-vendor/krb5.zip
Import MIT KRB5 1.16.vendor/krb5/1.16vendor/krb5
Notes
Notes: svn path=/vendor-crypto/krb5/dist/; revision=331939 svn path=/vendor-crypto/krb5/1.16/; revision=331941; tag=vendor/krb5/1.16
Diffstat (limited to 'src/util')
-rwxr-xr-xsrc/util/depfix.pl2
-rw-r--r--src/util/k5test.py37
-rw-r--r--src/util/profile/prof_parse.c6
-rw-r--r--src/util/profile/profile_tcl.c2
-rw-r--r--src/util/ss/data.c3
-rw-r--r--src/util/support/Makefile.in10
-rw-r--r--src/util/support/cache-addrinfo.h12
-rw-r--r--src/util/support/deps6
-rw-r--r--src/util/support/fake-addrinfo.c16
-rw-r--r--src/util/support/gmt_mktime.c17
-rw-r--r--src/util/support/libkrb5support-fixed.exports5
-rw-r--r--src/util/support/plugins.c5
-rw-r--r--src/util/support/t_utf16.c117
-rw-r--r--src/util/support/threads.c6
-rw-r--r--src/util/support/utf8.c2
-rw-r--r--src/util/support/utf8_conv.c475
-rw-r--r--src/util/verto/README2
-rw-r--r--src/util/verto/libverto.exports1
-rw-r--r--src/util/verto/verto-k5ev.c24
-rw-r--r--src/util/verto/verto-libev.c5
-rw-r--r--src/util/verto/verto.c131
-rw-r--r--src/util/verto/verto.h20
22 files changed, 446 insertions, 458 deletions
diff --git a/src/util/depfix.pl b/src/util/depfix.pl
index c8df54cbb29d..9982fa0d84ea 100755
--- a/src/util/depfix.pl
+++ b/src/util/depfix.pl
@@ -147,7 +147,7 @@ sub do_subs_2 {
s;com_err.h ;\$(COM_ERR_DEPS) ;g;
}
if ($thisdir eq "lib/krb5/ccache") {
- # These files are only used (and kcmrpc.h only generated) on OS X.
+ # These files are only used (and kcmrpc.h only generated) on macOS.
# There are conditional dependencies in Makefile.in.
s;kcmrpc.h ;;g;
s;kcmrpc_types.h ;;g;
diff --git a/src/util/k5test.py b/src/util/k5test.py
index c3d0263773be..4d30baf40454 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -223,8 +223,11 @@ Scripts may use the following realm methods and attributes:
command-line debugging options. Fail if the command does not return
0. Log the command output appropriately, and return it as a single
multi-line string. Keyword arguments can contain input='string' to
- send an input string to the command, and expected_code=N to expect a
- return code other than 0.
+ send an input string to the command, expected_code=N to expect a
+ return code other than 0, expected_msg=MSG to expect a substring in
+ the command output, and expected_trace=('a', 'b', ...) to expect an
+ ordered series of line substrings in the command's KRB5_TRACE
+ output.
* realm.kprop_port(): Returns a port number based on realm.portbase
intended for use by kprop and kpropd.
@@ -647,10 +650,31 @@ def _stop_or_shell(stop, shell, env, ind):
subprocess.call(os.getenv('SHELL'), env=env)
-def _run_cmd(args, env, input=None, expected_code=0):
+# Read tracefile and look for the expected strings in successive lines.
+def _check_trace(tracefile, expected):
+ output('*** Trace output for previous command:\n')
+ i = 0
+ with open(tracefile, 'r') as f:
+ for line in f:
+ output(line)
+ if i < len(expected) and expected[i] in line:
+ i += 1
+ if i < len(expected):
+ fail('Expected string not found in trace output: ' + expected[i])
+
+
+def _run_cmd(args, env, input=None, expected_code=0, expected_msg=None,
+ expected_trace=None):
global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug
global _stop_before, _stop_after, _shell_before, _shell_after
+ if expected_trace is not None:
+ tracefile = 'testtrace'
+ if os.path.exists(tracefile):
+ os.remove(tracefile)
+ env = env.copy()
+ env['KRB5_TRACE'] = tracefile
+
if (_match_cmdnum(_debug, _cmd_index)):
return _debug_cmd(args, env, input)
@@ -679,6 +703,13 @@ def _run_cmd(args, env, input=None, expected_code=0):
# Check the return code and return the output.
if code != expected_code:
fail('%s failed with code %d.' % (args[0], code))
+
+ if expected_msg is not None and expected_msg not in outdata:
+ fail('Expected string not found in command output: ' + expected_msg)
+
+ if expected_trace is not None:
+ _check_trace(tracefile, expected_trace)
+
return outdata
diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c
index e7c1f65aa09f..1baceea9e8a9 100644
--- a/src/util/profile/prof_parse.c
+++ b/src/util/profile/prof_parse.c
@@ -222,12 +222,16 @@ static errcode_t parse_include_file(const char *filename,
}
/* Return non-zero if filename contains only alphanumeric characters, dashes,
- * and underscores, or if the filename ends in ".conf". */
+ * and underscores, or if the filename ends in ".conf" and is not a dotfile. */
static int valid_name(const char *filename)
{
const char *p;
size_t len = strlen(filename);
+ /* Ignore dotfiles, which might be editor or filesystem artifacts. */
+ if (*filename == '.')
+ return 0;
+
if (len >= 5 && !strcmp(filename + len - 5, ".conf"))
return 1;
diff --git a/src/util/profile/profile_tcl.c b/src/util/profile/profile_tcl.c
index cac46270bf43..4f7a86a57218 100644
--- a/src/util/profile/profile_tcl.c
+++ b/src/util/profile/profile_tcl.c
@@ -3102,8 +3102,6 @@ SWIG_InitializeModule(void *clientdata) {
swig_module_info *module_head, *iter;
int found, init;
- clientdata = clientdata;
-
/* check to see if the circular list has been setup, if not, set it up */
if (swig_module.next==0) {
/* Initialize the swig_module */
diff --git a/src/util/ss/data.c b/src/util/ss/data.c
index 1a56dc76f99f..e0b09959724e 100644
--- a/src/util/ss/data.c
+++ b/src/util/ss/data.c
@@ -10,8 +10,5 @@
#include "ss_internal.h"
#include "copyright.h"
-const static char copyright[] =
- "Copyright 1987, 1988, 1989 by the Massachusetts Institute of Technology";
-
ss_data **_ss_table = (ss_data **)NULL;
char *_ss_pager_name = (char *)NULL;
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
index 6239e41761ee..0bf0b7a87277 100644
--- a/src/util/support/Makefile.in
+++ b/src/util/support/Makefile.in
@@ -143,6 +143,7 @@ SRCS=\
$(srcdir)/bcmp.c \
$(srcdir)/strerror_r.c \
$(srcdir)/t_utf8.c \
+ $(srcdir)/t_utf16.c \
$(srcdir)/getopt.c \
$(srcdir)/getopt_long.c
@@ -220,7 +221,12 @@ t_unal: t_unal.o
t_utf8: t_utf8.o utf8.o
$(CC_LINK) -o t_utf8 t_utf8.o utf8.o
-TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_unal t_utf8
+T_UTF16_OBJS= t_utf16.o utf8_conv.o utf8.o k5buf.o $(PRINTF_ST_OBJ)
+
+t_utf16: $(T_UTF16_OBJS)
+ $(CC_LINK) -o $@ $(T_UTF16_OBJS)
+
+TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_unal t_utf8 t_utf16
check-unix: $(TEST_PROGS)
./t_k5buf
@@ -230,11 +236,13 @@ check-unix: $(TEST_PROGS)
./t_json
./t_unal
./t_utf8
+ ./t_utf16
clean:
$(RM) t_k5buf.o t_k5buf t_unal.o t_unal path_win.o path_win
$(RM) t_path_win.o t_path_win t_path.o t_path t_base64.o t_base64
$(RM) t_json.o t_json libkrb5support.exports t_utf8.o t_utf8
+ $(RM) t_utf16.o t_utf16
@lib_frag@
@libobj_frag@
diff --git a/src/util/support/cache-addrinfo.h b/src/util/support/cache-addrinfo.h
index a1b7fb28becb..40752ab5f4a7 100644
--- a/src/util/support/cache-addrinfo.h
+++ b/src/util/support/cache-addrinfo.h
@@ -52,12 +52,12 @@
* the data structures and flag values locally.
*
*
- * On Mac OS X, getaddrinfo results aren't cached (though
- * gethostbyname results are), so we need to build a cache here. Now
- * things are getting really messy. Because the cache is in use, we
- * use getservbyname, and throw away thread safety. (Not that the
- * cache is thread safe, but when we get locking support, that'll be
- * dealt with.) This code needs tearing down and rebuilding, soon.
+ * On macOS, getaddrinfo results aren't cached (though gethostbyname
+ * results are), so we need to build a cache here. Now things are
+ * getting really messy. Because the cache is in use, we use
+ * getservbyname, and throw away thread safety. (Not that the cache
+ * is thread safe, but when we get locking support, that'll be dealt
+ * with.) This code needs tearing down and rebuilding, soon.
*
*
* Note that recent Windows developers' code has an interesting hack:
diff --git a/src/util/support/deps b/src/util/support/deps
index 4dff014f463b..34d8a884b330 100644
--- a/src/util/support/deps
+++ b/src/util/support/deps
@@ -33,7 +33,8 @@ utf8.so utf8.po $(OUTPRE)utf8.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
$(top_srcdir)/include/k5-utf8.h supp-int.h utf8.c
utf8_conv.so utf8_conv.po $(OUTPRE)utf8_conv.$(OBJEXT): \
- $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-platform.h \
+ $(BUILDTOP)/include/autoconf.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-input.h $(top_srcdir)/include/k5-platform.h \
$(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-utf8.h \
supp-int.h utf8_conv.c
gettimeofday.so gettimeofday.po $(OUTPRE)gettimeofday.$(OBJEXT): \
@@ -84,6 +85,9 @@ strerror_r.so strerror_r.po $(OUTPRE)strerror_r.$(OBJEXT): \
t_utf8.so t_utf8.po $(OUTPRE)t_utf8.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
$(top_srcdir)/include/k5-utf8.h t_utf8.c
+t_utf16.so t_utf16.po $(OUTPRE)t_utf16.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-utf8.h t_utf16.c
getopt.so getopt.po $(OUTPRE)getopt.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
getopt.c
diff --git a/src/util/support/fake-addrinfo.c b/src/util/support/fake-addrinfo.c
index df1cc1dec558..3ee162e0d28b 100644
--- a/src/util/support/fake-addrinfo.c
+++ b/src/util/support/fake-addrinfo.c
@@ -52,7 +52,7 @@
* the data structures and flag values locally.
*
*
- * On Mac OS X, getaddrinfo results aren't cached (though
+ * On macOS, getaddrinfo results aren't cached (though
* gethostbyname results are), so we need to build a cache here. Now
* things are getting really messy. Because the cache is in use, we
* use getservbyname, and throw away thread safety. (Not that the
@@ -331,18 +331,6 @@ system_freeaddrinfo (struct addrinfo *ai)
freeaddrinfo(ai);
}
-/* Note: Implementations written to RFC 2133 use size_t, while RFC
- 2553 implementations use socklen_t, for the second parameter.
-
- Mac OS X (10.2) and AIX 4.3.3 appear to be in the RFC 2133 camp,
- but we don't have an autoconf test for that right now. */
-static inline int
-system_getnameinfo (const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen, char *serv, size_t servlen,
- int flags)
-{
- return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
-}
#endif
#if !defined (HAVE_GETADDRINFO) || defined(WRAP_GETADDRINFO) || defined(FAI_CACHE)
@@ -697,7 +685,7 @@ static inline int fai_add_hosts_by_name (const char *name,
sometimes associates it with the specified service,
sometimes not.
- But on Mac OS X (10.3, 10.4) they've "extended" getaddrinfo
+ But on macOS (10.3, 10.4) they've "extended" getaddrinfo
to make SRV RR queries. (Please, somebody, show me
something in the specs that actually supports this? RFC
3493 says nothing about it, but it does say getaddrinfo is
diff --git a/src/util/support/gmt_mktime.c b/src/util/support/gmt_mktime.c
index 32fef4386cd4..ac7752fefed0 100644
--- a/src/util/support/gmt_mktime.c
+++ b/src/util/support/gmt_mktime.c
@@ -78,21 +78,20 @@ static const int days_in_month[12] = {
static time_t
gmt_mktime(struct tm *t)
{
- time_t accum;
+ uint32_t accum;
#define assert_time(cnd) if(!(cnd)) return (time_t) -1
/*
- * For 32-bit signed time_t centered on 1/1/1970, the range is:
- * time 0x80000000 -> Fri Dec 13 16:45:52 1901
- * time 0x7fffffff -> Mon Jan 18 22:14:07 2038
+ * For 32-bit unsigned time values starting on 1/1/1970, the range is:
+ * time 0x00000000 -> Thu Jan 1 00:00:00 1970
+ * time 0xffffffff -> Sun Feb 7 06:28:15 2106
*
- * So years 1901 and 2038 are allowable, but we can't encode all
- * dates in those years, and we're not doing overflow/underflow
- * checking for such cases.
+ * We can't encode all dates in 2106, and we're not doing overflow checking
+ * for such cases.
*/
- assert_time(t->tm_year>=1);
- assert_time(t->tm_year<=138);
+ assert_time(t->tm_year>=70);
+ assert_time(t->tm_year<=206);
assert_time(t->tm_mon>=0);
assert_time(t->tm_mon<=11);
diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
index d5d4177b72dc..fd74a1897ebb 100644
--- a/src/util/support/libkrb5support-fixed.exports
+++ b/src/util/support/libkrb5support-fixed.exports
@@ -52,6 +52,8 @@ k5_path_isabs
k5_path_join
k5_path_split
k5_strerror_r
+k5_utf8_to_utf16le
+k5_utf16le_to_utf8
krb5int_key_register
krb5int_key_delete
krb5int_getspecific
@@ -77,9 +79,6 @@ krb5int_mutex_free
krb5int_mutex_lock
krb5int_mutex_unlock
krb5int_gmt_mktime
-krb5int_utf8cs_to_ucs2les
-krb5int_utf8s_to_ucs2les
-krb5int_ucs2lecs_to_utf8s
krb5int_ucs4_to_utf8
krb5int_utf8_to_ucs4
krb5int_utf8_lentab
diff --git a/src/util/support/plugins.c b/src/util/support/plugins.c
index b0bb2ada8755..47368be9d49b 100644
--- a/src/util/support/plugins.c
+++ b/src/util/support/plugins.c
@@ -592,9 +592,10 @@ krb5int_open_plugin_dirs (const char * const *dirnames,
}
}
- if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
+ if (!err && krb5int_open_plugin(filepath, &handle, ep) == 0) {
err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
- if (!err) { handle = NULL; } /* h takes ownership */
+ if (!err)
+ handle = NULL; /* h takes ownership */
}
free(filepath);
diff --git a/src/util/support/t_utf16.c b/src/util/support/t_utf16.c
new file mode 100644
index 000000000000..bc3390a415cd
--- /dev/null
+++ b/src/util/support/t_utf16.c
@@ -0,0 +1,117 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* util/support/t_utf16.c - test UTF-16 conversion functions */
+/*
+ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program tests conversions between UTF-8 and little-endian UTF-16, with
+ * an eye mainly towards covering UTF-16 edge cases and UTF-8 decoding results
+ * which we detect as invalid in utf8_conv.c. t_utf8.c covers more UTF-8 edge
+ * cases.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "k5-platform.h"
+#include "k5-utf8.h"
+
+struct test {
+ const char *utf8;
+ const char *utf16;
+ size_t utf16len;
+} tests[] = {
+ { "", "", 0 },
+ { "abcd", "a\0b\0c\0d\0", 8 },
+ /* From RFC 2781 (tests code point 0x12345 and some ASCII) */
+ { "\xF0\x92\x8D\x85=Ra", "\x08\xD8\x45\xDF=\0R\0a\0", 10 },
+ /* Lowest and highest Supplementary Plane code points */
+ { "\xF0\x90\x80\x80 \xF4\x8F\xBF\xBF",
+ "\x00\xD8\x00\xDC \0\xFF\xDB\xFF\xDF", 10 },
+ /* Basic Multilingual Plane code points near and above surrogate range */
+ { "\xED\x9F\xBF", "\xFF\xD7", 2 },
+ { "\xEE\x80\x80 \xEE\xBF\xBF", "\x00\xE0 \0\xFF\xEF", 6 },
+ /* Invalid UTF-8: decodes to value in surrogate pair range */
+ { "\xED\xA0\x80", NULL, 0 }, /* 0xD800 */
+ { "\xED\xAF\xBF", NULL, 0 }, /* 0xDBFF */
+ { "\xED\xB0\x80", NULL, 0 }, /* 0xDC00 */
+ { "\xED\xBF\xBF", NULL, 0 }, /* 0xDFFF */
+ /* Invalid UTF-8: decodes to value above Unicode range */
+ { "\xF4\x90\x80\x80", NULL, 0 },
+ { "\xF4\xBF\xBF\xBF", NULL, 0 },
+ { "\xF5\x80\x80\x80", NULL, 0 }, /* thrown out early due to first byte */
+ /* Invalid UTF-16: odd numbers of UTF-16 bytes */
+ { NULL, "\x00", 1 },
+ { NULL, "\x01\x00\x02", 3 },
+ /* Invalid UTF-16: high surrogate without a following low surrogate */
+ { NULL, "\x00\xD8\x00\x00", 4 },
+ { NULL, "\x00\xD8\xFF\xDB", 4 },
+ { NULL, "\xFF\xDB", 2 },
+ /* Invalid UTF-16: low surrogate without a preceding high surrogate */
+ { NULL, "\x61\x00\x00\xDC", 4 },
+ { NULL, "\xFF\xDF\xFF\xDB", 4 },
+};
+
+int
+main(int argc, char **argv)
+{
+ int ret;
+ struct test *t;
+ size_t i, utf16len;
+ uint8_t *utf16;
+ char *utf8;
+
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ t = &tests[i];
+ if (t->utf8 != NULL) {
+ ret = k5_utf8_to_utf16le(t->utf8, &utf16, &utf16len);
+ if (t->utf16 == NULL) {
+ assert(ret == EINVAL);
+ } else {
+ assert(ret == 0);
+ assert(t->utf16len == utf16len);
+ assert(memcmp(t->utf16, utf16, utf16len) == 0);
+ free(utf16);
+ }
+ }
+
+ if (t->utf16 != NULL) {
+ ret = k5_utf16le_to_utf8((uint8_t *)t->utf16, t->utf16len, &utf8);
+ if (t->utf8 == NULL) {
+ assert(ret == EINVAL);
+ } else {
+ assert(ret == 0);
+ assert(strcmp(t->utf8, utf8) == 0);
+ free(utf8);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/util/support/threads.c b/src/util/support/threads.c
index bb8e287ecf75..be7e4c2e3f92 100644
--- a/src/util/support/threads.c
+++ b/src/util/support/threads.c
@@ -237,7 +237,6 @@ void *k5_getspecific (k5_key_t keynum)
if (err)
return NULL;
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
assert(destructors_set[keynum] == 1);
#ifndef ENABLE_THREADS
@@ -271,7 +270,6 @@ int k5_setspecific (k5_key_t keynum, void *value)
if (err)
return err;
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
assert(destructors_set[keynum] == 1);
#ifndef ENABLE_THREADS
@@ -334,8 +332,6 @@ int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
if (err)
return err;
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
-
#ifndef ENABLE_THREADS
assert(destructors_set[keynum] == 0);
@@ -365,8 +361,6 @@ int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
int k5_key_delete (k5_key_t keynum)
{
- assert(keynum >= 0 && keynum < K5_KEY_MAX);
-
#ifndef ENABLE_THREADS
assert(destructors_set[keynum] == 1);
diff --git a/src/util/support/utf8.c b/src/util/support/utf8.c
index e42c0c7dc82b..34e2b6adb059 100644
--- a/src/util/support/utf8.c
+++ b/src/util/support/utf8.c
@@ -205,7 +205,7 @@ int krb5int_utf8_to_ucs2(const char *p, krb5_ucs2 *out)
return 0;
}
-/* conv UCS-2 to UTF-8, not used */
+/* conv UCS-4 to UTF-8 */
size_t krb5int_ucs4_to_utf8(krb5_ucs4 c, char *buf)
{
size_t len = 0;
diff --git a/src/util/support/utf8_conv.c b/src/util/support/utf8_conv.c
index 80ca90b139e7..5cfc2c512b86 100644
--- a/src/util/support/utf8_conv.c
+++ b/src/util/support/utf8_conv.c
@@ -1,7 +1,7 @@
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* util/support/utf8_conv.c */
/*
- * Copyright 2008 by the Massachusetts Institute of Technology.
+ * Copyright 2008, 2017 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -47,411 +47,156 @@
* THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
*/
-/* This work is part of OpenLDAP Software <http://www.openldap.org/>. */
+/* This work is based on OpenLDAP Software <http://www.openldap.org/>. */
/*
- * UTF-8 Conversion Routines
- *
- * These routines convert between Wide Character and UTF-8,
- * or between MultiByte and UTF-8 encodings.
- *
- * Both single character and string versions of the functions are provided.
- * All functions return -1 if the character or string cannot be converted.
+ * These routines convert between UTF-16 and UTF-8. UTF-16 encodes a Unicode
+ * character in either two or four bytes. Characters in the Basic Multilingual
+ * Plane (hex 0..D7FF and E000..FFFF) are encoded as-is in two bytes.
+ * Characters in the Supplementary Planes (10000..10FFFF) are split into a high
+ * surrogate and a low surrogate, each containing ten bits of the character
+ * value, and encoded in four bytes.
*/
#include "k5-platform.h"
#include "k5-utf8.h"
+#include "k5-buf.h"
+#include "k5-input.h"
#include "supp-int.h"
static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
-static ssize_t
-k5_utf8s_to_ucs2s(krb5_ucs2 *ucs2str,
- const char *utf8str,
- size_t count,
- int little_endian)
-{
- size_t ucs2len = 0;
- size_t utflen, i;
- krb5_ucs2 ch;
-
- /* If input ptr is NULL or empty... */
- if (utf8str == NULL || *utf8str == '\0') {
- if (ucs2str != NULL)
- *ucs2str = 0;
-
- return 0;
- }
-
- /* Examine next UTF-8 character. */
- while (ucs2len < count && *utf8str != '\0') {
- /* Get UTF-8 sequence length from 1st byte */
- utflen = KRB5_UTF8_CHARLEN2(utf8str, utflen);
-
- if (utflen == 0 || utflen > KRB5_MAX_UTF8_LEN)
- return -1;
-
- /* First byte minus length tag */
- ch = (krb5_ucs2)(utf8str[0] & mask[utflen]);
-
- for (i = 1; i < utflen; i++) {
- /* Subsequent bytes must start with 10 */
- if ((utf8str[i] & 0xc0) != 0x80)
- return -1;
-
- ch <<= 6; /* 6 bits of data in each subsequent byte */
- ch |= (krb5_ucs2)(utf8str[i] & 0x3f);
- }
-
- if (ucs2str != NULL) {
-#ifdef K5_BE
-#ifndef SWAP16
-#define SWAP16(X) ((((X) << 8) | ((X) >> 8)) & 0xFFFF)
-#endif
- if (little_endian)
- ucs2str[ucs2len] = SWAP16(ch);
- else
-#endif
- ucs2str[ucs2len] = ch;
- }
-
- utf8str += utflen; /* Move to next UTF-8 character */
- ucs2len++; /* Count number of wide chars stored/required */
- }
-
- if (ucs2str != NULL && ucs2len < count) {
- /* Add null terminator if there's room in the buffer. */
- ucs2str[ucs2len] = 0;
- }
-
- return ucs2len;
-}
-
-int
-krb5int_utf8s_to_ucs2s(const char *utf8s,
- krb5_ucs2 **ucs2s,
- size_t *ucs2chars)
-{
- ssize_t len;
- size_t chars;
+/* A high surrogate is ten bits masked with 0xD800. */
+#define IS_HIGH_SURROGATE(c) ((c) >= 0xD800 && (c) <= 0xDBFF)
- chars = krb5int_utf8_chars(utf8s);
- *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2));
- if (*ucs2s == NULL) {
- return ENOMEM;
- }
+/* A low surrogate is ten bits masked with 0xDC00. */
+#define IS_LOW_SURROGATE(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
- len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars + 1, 0);
- if (len < 0) {
- free(*ucs2s);
- *ucs2s = NULL;
- return EINVAL;
- }
+/* A valid Unicode code point is in the range 0..10FFFF and is not a surrogate
+ * value. */
+#define IS_SURROGATE(c) ((c) >= 0xD800 && (c) <= 0xDFFF)
+#define IS_VALID_UNICODE(c) ((c) <= 0x10FFFF && !IS_SURROGATE(c))
- if (ucs2chars != NULL) {
- *ucs2chars = chars;
- }
+/* A Basic Multilingual Plane character is in the range 0..FFFF and is not a
+ * surrogate value. */
+#define IS_BMP(c) ((c) <= 0xFFFF && !IS_SURROGATE(c))
- return 0;
-}
+/* Characters in the Supplementary Planes have a base value subtracted from
+ * their code points to form a 20-bit value; ten bits go in each surrogate. */
+#define BASE 0x10000
+#define HIGH_SURROGATE(c) (0xD800 | (((c) - BASE) >> 10))
+#define LOW_SURROGATE(c) (0xDC00 | (((c) - BASE) & 0x3FF))
+#define COMPOSE(c1, c2) (BASE + ((((c1) & 0x3FF) << 10) | ((c2) & 0x3FF)))
int
-krb5int_utf8cs_to_ucs2s(const char *utf8s,
- size_t utf8slen,
- krb5_ucs2 **ucs2s,
- size_t *ucs2chars)
+k5_utf8_to_utf16le(const char *utf8, uint8_t **utf16_out, size_t *nbytes_out)
{
- ssize_t len;
- size_t chars;
-
- chars = krb5int_utf8c_chars(utf8s, utf8slen);
- *ucs2s = (krb5_ucs2 *)malloc((chars + 1) * sizeof(krb5_ucs2));
- if (*ucs2s == NULL) {
- return ENOMEM;
- }
-
- len = k5_utf8s_to_ucs2s(*ucs2s, utf8s, chars, 0);
- if (len < 0) {
- free(*ucs2s);
- *ucs2s = NULL;
- return EINVAL;
- }
- (*ucs2s)[chars] = 0;
-
- if (ucs2chars != NULL) {
- *ucs2chars = chars;
- }
-
- return 0;
-}
-
-int
-krb5int_utf8s_to_ucs2les(const char *utf8s,
- unsigned char **ucs2les,
- size_t *ucs2leslen)
-{
- ssize_t len;
- size_t chars;
-
- chars = krb5int_utf8_chars(utf8s);
-
- *ucs2les = (unsigned char *)malloc((chars + 1) * sizeof(krb5_ucs2));
- if (*ucs2les == NULL) {
- return ENOMEM;
- }
-
- len = k5_utf8s_to_ucs2s((krb5_ucs2 *)*ucs2les, utf8s, chars + 1, 1);
- if (len < 0) {
- free(*ucs2les);
- *ucs2les = NULL;
- return EINVAL;
- }
-
- if (ucs2leslen != NULL) {
- *ucs2leslen = chars * sizeof(krb5_ucs2);
- }
-
- return 0;
-}
-
-int
-krb5int_utf8cs_to_ucs2les(const char *utf8s,
- size_t utf8slen,
- unsigned char **ucs2les,
- size_t *ucs2leslen)
-{
- ssize_t len;
- size_t chars;
- krb5_ucs2 *ucs2s;
-
- *ucs2les = NULL;
-
- chars = krb5int_utf8c_chars(utf8s, utf8slen);
- ucs2s = malloc((chars + 1) * sizeof(krb5_ucs2));
- if (ucs2s == NULL)
- return ENOMEM;
-
- len = k5_utf8s_to_ucs2s(ucs2s, utf8s, chars, 1);
- if (len < 0) {
- free(ucs2s);
- return EINVAL;
- }
- ucs2s[chars] = 0;
-
- *ucs2les = (unsigned char *)ucs2s;
- if (ucs2leslen != NULL) {
- *ucs2leslen = chars * sizeof(krb5_ucs2);
- }
+ struct k5buf buf;
+ krb5_ucs4 ch;
+ size_t chlen, i;
+ uint8_t *p;
- return 0;
-}
+ *utf16_out = NULL;
+ *nbytes_out = 0;
-/*-----------------------------------------------------------------------------
- Convert a wide char string to a UTF-8 string.
- No more than 'count' bytes will be written to the output buffer.
- Return the # of bytes written to the output buffer, excl null terminator.
+ k5_buf_init_dynamic(&buf);
- ucs2len is -1 if the UCS-2 string is NUL terminated, otherwise it is the
- length of the UCS-2 string in characters
-*/
-static ssize_t
-k5_ucs2s_to_utf8s(char *utf8str, const krb5_ucs2 *ucs2str,
- size_t count, ssize_t ucs2len, int little_endian)
-{
- int len = 0;
- int n;
- char *p = utf8str;
- krb5_ucs2 empty = 0, ch;
+ /* Examine next UTF-8 character. */
+ while (*utf8 != '\0') {
+ /* Get UTF-8 sequence length from first byte. */
+ chlen = KRB5_UTF8_CHARLEN2(utf8, chlen);
+ if (chlen == 0)
+ goto invalid;
- if (ucs2str == NULL) /* Treat input ptr NULL as an empty string */
- ucs2str = &empty;
+ /* First byte minus length tag */
+ ch = (krb5_ucs4)(utf8[0] & mask[chlen]);
- if (utf8str == NULL) /* Just compute size of output, excl null */
- {
- while (ucs2len == -1 ? *ucs2str : --ucs2len >= 0) {
- /* Get UTF-8 size of next wide char */
- ch = *ucs2str++;
-#ifdef K5_BE
- if (little_endian)
- ch = SWAP16(ch);
-#endif
+ for (i = 1; i < chlen; i++) {
+ /* Subsequent bytes must start with 10. */
+ if ((utf8[i] & 0xc0) != 0x80)
+ goto invalid;
- n = krb5int_ucs2_to_utf8(ch, NULL);
- if (n < 1 || n > INT_MAX - len)
- return -1;
- len += n;
+ /* 6 bits of data in each subsequent byte */
+ ch <<= 6;
+ ch |= (krb5_ucs4)(utf8[i] & 0x3f);
+ }
+ if (!IS_VALID_UNICODE(ch))
+ goto invalid;
+
+ /* Characters in the basic multilingual plane are encoded using two
+ * bytes; other characters are encoded using four bytes. */
+ p = k5_buf_get_space(&buf, IS_BMP(ch) ? 2 : 4);
+ if (p == NULL)
+ return ENOMEM;
+ if (IS_BMP(ch)) {
+ store_16_le(ch, p);
+ } else {
+ /* 0x10000 is subtracted from ch; then the high ten bits plus
+ * 0xD800 and the low ten bits plus 0xDC00 are the surrogates. */
+ store_16_le(HIGH_SURROGATE(ch), p);
+ store_16_le(LOW_SURROGATE(ch), p + 2);
}
- return len;
- }
-
- /* Do the actual conversion. */
-
- n = 1; /* In case of empty ucs2str */
- while (ucs2len == -1 ? *ucs2str != 0 : --ucs2len >= 0) {
- ch = *ucs2str++;
-#ifdef K5_BE
- if (little_endian)
- ch = SWAP16(ch);
-#endif
-
- n = krb5int_ucs2_to_utf8(ch, p);
-
- if (n < 1)
- break;
-
- p += n;
- count -= n; /* Space left in output buffer */
- }
-
- /* If not enough room for last character, pad remainder with null
- so that return value = original count, indicating buffer full. */
- if (n == 0) {
- while (count--)
- *p++ = 0;
- }
- /* Add a null terminator if there's room. */
- else if (count)
- *p = 0;
-
- if (n == -1) /* Conversion encountered invalid wide char. */
- return -1;
-
- /* Return the number of bytes written to output buffer, excl null. */
- return (p - utf8str);
-}
-
-int
-krb5int_ucs2s_to_utf8s(const krb5_ucs2 *ucs2s,
- char **utf8s,
- size_t *utf8slen)
-{
- ssize_t len;
-
- len = k5_ucs2s_to_utf8s(NULL, ucs2s, 0, -1, 0);
- if (len < 0) {
- return EINVAL;
- }
-
- *utf8s = (char *)malloc((size_t)len + 1);
- if (*utf8s == NULL) {
- return ENOMEM;
- }
-
- len = k5_ucs2s_to_utf8s(*utf8s, ucs2s, (size_t)len + 1, -1, 0);
- if (len < 0) {
- free(*utf8s);
- *utf8s = NULL;
- return EINVAL;
- }
-
- if (utf8slen != NULL) {
- *utf8slen = len;
+ /* Move to next UTF-8 character. */
+ utf8 += chlen;
}
+ *utf16_out = buf.data;
+ *nbytes_out = buf.len;
return 0;
-}
-int
-krb5int_ucs2les_to_utf8s(const unsigned char *ucs2les,
- char **utf8s,
- size_t *utf8slen)
-{
- ssize_t len;
-
- len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0, -1, 1);
- if (len < 0)
- return EINVAL;
-
- *utf8s = (char *)malloc((size_t)len + 1);
- if (*utf8s == NULL) {
- return ENOMEM;
- }
-
- len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, (size_t)len + 1, -1, 1);
- if (len < 0) {
- free(*utf8s);
- *utf8s = NULL;
- return EINVAL;
- }
-
- if (utf8slen != NULL) {
- *utf8slen = len;
- }
-
- return 0;
+invalid:
+ k5_buf_free(&buf);
+ return EINVAL;
}
int
-krb5int_ucs2cs_to_utf8s(const krb5_ucs2 *ucs2s,
- size_t ucs2slen,
- char **utf8s,
- size_t *utf8slen)
+k5_utf16le_to_utf8(const uint8_t *utf16bytes, size_t nbytes, char **utf8_out)
{
- ssize_t len;
+ struct k5buf buf;
+ struct k5input in;
+ uint16_t ch1, ch2;
+ krb5_ucs4 ch;
+ size_t chlen;
+ void *p;
- if (ucs2slen > SSIZE_MAX)
- return ERANGE;
+ *utf8_out = NULL;
- len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2s, 0,
- (ssize_t)ucs2slen, 0);
- if (len < 0)
+ if (nbytes % 2 != 0)
return EINVAL;
- *utf8s = (char *)malloc((size_t)len + 1);
- if (*utf8s == NULL) {
- return ENOMEM;
- }
+ k5_buf_init_dynamic(&buf);
+ k5_input_init(&in, utf16bytes, nbytes);
+ while (!in.status && in.len > 0) {
+ /* Get the next character or high surrogate. A low surrogate without a
+ * preceding high surrogate is invalid. */
+ ch1 = k5_input_get_uint16_le(&in);
+ if (IS_LOW_SURROGATE(ch1))
+ goto invalid;
+ if (IS_HIGH_SURROGATE(ch1)) {
+ /* Get the low surrogate and combine the pair. */
+ ch2 = k5_input_get_uint16_le(&in);
+ if (!IS_LOW_SURROGATE(ch2))
+ goto invalid;
+ ch = COMPOSE(ch1, ch2);
+ } else {
+ ch = ch1;
+ }
- len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2s, (size_t)len,
- (ssize_t)ucs2slen, 0);
- if (len < 0) {
- free(*utf8s);
- *utf8s = NULL;
- return EINVAL;
+ chlen = krb5int_ucs4_to_utf8(ch, NULL);
+ p = k5_buf_get_space(&buf, chlen);
+ if (p == NULL)
+ return ENOMEM;
+ (void)krb5int_ucs4_to_utf8(ch, p);
}
- (*utf8s)[len] = '\0';
- if (utf8slen != NULL) {
- *utf8slen = len;
- }
+ if (in.status)
+ goto invalid;
+ *utf8_out = buf.data;
return 0;
-}
-
-int
-krb5int_ucs2lecs_to_utf8s(const unsigned char *ucs2les,
- size_t ucs2leslen,
- char **utf8s,
- size_t *utf8slen)
-{
- ssize_t len;
- if (ucs2leslen > SSIZE_MAX)
- return ERANGE;
-
- len = k5_ucs2s_to_utf8s(NULL, (krb5_ucs2 *)ucs2les, 0,
- (ssize_t)ucs2leslen, 1);
- if (len < 0)
- return EINVAL;
-
- *utf8s = (char *)malloc((size_t)len + 1);
- if (*utf8s == NULL) {
- return ENOMEM;
- }
-
- len = k5_ucs2s_to_utf8s(*utf8s, (krb5_ucs2 *)ucs2les, (size_t)len,
- (ssize_t)ucs2leslen, 1);
- if (len < 0) {
- free(*utf8s);
- *utf8s = NULL;
- return EINVAL;
- }
- (*utf8s)[len] = '\0';
-
- if (utf8slen != NULL) {
- *utf8slen = len;
- }
-
- return 0;
+invalid:
+ k5_buf_free(&buf);
+ return EINVAL;
}
diff --git a/src/util/verto/README b/src/util/verto/README
index 6de645f6fb15..a3dab834d89d 100644
--- a/src/util/verto/README
+++ b/src/util/verto/README
@@ -36,5 +36,5 @@ BUILTIN_MODULE define.
The libverto and libev upstream project pages are at:
- https://fedorahosted.org/libverto/
+ https://github.com/latchset/libverto/
http://software.schmorp.de/pkg/libev.html
diff --git a/src/util/verto/libverto.exports b/src/util/verto/libverto.exports
index ecba76ad9d7c..3745d5014653 100644
--- a/src/util/verto/libverto.exports
+++ b/src/util/verto/libverto.exports
@@ -4,6 +4,7 @@ verto_add_io
verto_add_signal
verto_add_timeout
verto_break
+verto_cleanup
verto_convert_module
verto_default
verto_del
diff --git a/src/util/verto/verto-k5ev.c b/src/util/verto/verto-k5ev.c
index 74fa368a83b3..a390af716616 100644
--- a/src/util/verto/verto-k5ev.c
+++ b/src/util/verto/verto-k5ev.c
@@ -36,12 +36,29 @@
#include <verto.h>
#include <verto-module.h>
#include "rename.h"
+
+/* Ignore some warnings generated by the libev code, which the libev maintainer
+ * isn't interested in avoiding. */
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wunused-value"
+#pragma GCC diagnostic ignored "-Wcomment"
+#pragma GCC diagnostic ignored "-Wunused-result"
+#ifdef __clang__
+#pragma GCC diagnostic ignored "-Wbitwise-op-parentheses"
+#endif
+#endif
+
#define EV_API_STATIC 1
#define EV_STANDALONE 1
/* Avoid using clock_gettime, which would create a dependency on librt. */
#define EV_USE_MONOTONIC 0
#define EV_USE_REALTIME 0
-#define EV_FEATURES 0x5f /* Everything but back ends */
+#define EV_FEATURES 0x4f /* No back ends or optional watchers */
+/* Enable the optional watcher types we use. */
+#define EV_IDLE_ENABLE 1
+#define EV_SIGNAL_ENABLE 1
+#define EV_CHILD_ENABLE 1
+/* Enable the back ends we want. */
#ifdef HAVE_POLL_H
#define EV_USE_POLL 1
#endif
@@ -97,6 +114,11 @@ libev_callback(EV_P_ ev_watcher *w, int revents)
{
verto_ev_flag state = VERTO_EV_FLAG_NONE;
+#if EV_MULTIPLICITY
+ /* Match the check in ev.h, which doesn't mark this unused */
+ (void) EV_A;
+#endif
+
if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD)
verto_set_proc_status(w->data, ((ev_child*) w)->rstatus);
diff --git a/src/util/verto/verto-libev.c b/src/util/verto/verto-libev.c
index 9c7c32449c72..99256a2fc75c 100644
--- a/src/util/verto/verto-libev.c
+++ b/src/util/verto/verto-libev.c
@@ -80,6 +80,11 @@ libev_callback(EV_P_ ev_watcher *w, int revents)
{
verto_ev_flag state = VERTO_EV_FLAG_NONE;
+#if EV_MULTIPLICITY
+ /* Match the check in ev.h, which doesn't mark this unused */
+ (void) EV_A;
+#endif
+
if (verto_get_type(w->data)== VERTO_EV_TYPE_CHILD)
verto_set_proc_status(w->data, ((ev_child*) w)->rstatus);
diff --git a/src/util/verto/verto.c b/src/util/verto/verto.c
index 44ea4373fcf3..71eaffa080de 100644
--- a/src/util/verto/verto.c
+++ b/src/util/verto/verto.c
@@ -22,8 +22,6 @@
* SOFTWARE.
*/
-#define _GNU_SOURCE /* For asprintf() */
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -45,6 +43,8 @@
#define _str(s) # s
#define __str(s) _str(s)
+#define MUTABLE(flags) (flags & _VERTO_EV_FLAG_MUTABLE_MASK)
+
/* Remove flags we can emulate */
#define make_actual(flags) ((flags) & ~(VERTO_EV_FLAG_PERSIST|VERTO_EV_FLAG_IO_CLOSE_FD))
@@ -103,7 +103,7 @@ struct module_record {
/*
* This symbol can be used when embedding verto.c in a library along with a
* built-in private module, to preload the module instead of dynamically
- * linking it in later. Define to verto_module_table_<modulename>.
+ * linking it in later. Define to <modulename>.
*/
extern verto_module MODTABLE(BUILTIN_MODULE);
static module_record builtin_record = {
@@ -119,12 +119,43 @@ static int resize_cb_hierarchical;
#ifdef HAVE_PTHREAD
static pthread_mutex_t loaded_modules_mutex = PTHREAD_MUTEX_INITIALIZER;
-#define mutex_lock(x) pthread_mutex_lock(x)
-#define mutex_unlock(x) pthread_mutex_unlock(x)
-#else
+
+#ifndef NDEBUG
+#define mutex_lock(x) { \
+ int c = pthread_mutex_lock(x); \
+ if (c != 0) { \
+ fprintf(stderr, "pthread_mutex_lock returned %d (%s) in %s", \
+ c, strerror(c), __FUNCTION__); \
+ } \
+ assert(c == 0); \
+ }
+#define mutex_unlock(x) { \
+ int c = pthread_mutex_unlock(x); \
+ if (c != 0) { \
+ fprintf(stderr, "pthread_mutex_unlock returned %d (%s) in %s", \
+ c, strerror(c), __FUNCTION__); \
+ } \
+ assert(c == 0); \
+ }
+#define mutex_destroy(x) { \
+ int c = pthread_mutex_destroy(x); \
+ if (c != 0) { \
+ fprintf(stderr, "pthread_mutex_destroy returned %d (%s) in %s", \
+ c, strerror(c), __FUNCTION__); \
+ } \
+ assert(c == 0); \
+ }
+#else /* NDEBUG */
+#define mutex_lock pthread_mutex_lock
+#define mutex_unlock pthread_mutex_unlock
+#define mutex_destroy pthread_mutex_destroy
+#endif /* NDEBUG */
+
+#else /* HAVE_PTHREAD */
#define mutex_lock(x)
#define mutex_unlock(x)
-#endif
+#define mutex_destroy(x)
+#endif /* HAVE_PTHREAD */
#define vfree(mem) vresize(mem, 0)
static void *
@@ -132,34 +163,35 @@ vresize(void *mem, size_t size)
{
if (!resize_cb)
resize_cb = &realloc;
+ if (size == 0 && resize_cb == &realloc) {
+ /* Avoid memleak as realloc(X, 0) can return a free-able pointer. */
+ free(mem);
+ return NULL;
+ }
return (*resize_cb)(mem, size);
}
#ifndef BUILTIN_MODULE
-static int
-int_vasprintf(char **strp, const char *fmt, va_list ap) {
- va_list apc;
- int size = 0;
-
- va_copy(apc, ap);
- size = vsnprintf(NULL, 0, fmt, apc);
- va_end(apc);
+static char *
+string_aconcat(const char *first, const char *second, const char *third) {
+ char *ret;
+ size_t len;
- if (size <= 0 || !(*strp = malloc(size + 1)))
- return -1;
+ len = strlen(first) + strlen(second);
+ if (third)
+ len += strlen(third);
- return vsnprintf(*strp, size + 1, fmt, ap);
-}
+ ret = malloc(len + 1);
+ if (!ret)
+ return NULL;
-static int
-int_asprintf(char **strp, const char *fmt, ...) {
- va_list ap;
- int size = 0;
+ strncpy(ret, first, strlen(first));
+ strncpy(ret + strlen(first), second, strlen(second));
+ if (third)
+ strncpy(ret + strlen(first) + strlen(second), third, strlen(third));
- va_start(ap, fmt);
- size = int_vasprintf(strp, fmt, ap);
- va_end(ap);
- return size;
+ ret[len] = '\0';
+ return ret;
}
static char *
@@ -185,8 +217,7 @@ int_get_table_name_from_filename(const char *filename)
if (tmp) {
if (strchr(tmp+1, '.')) {
*strchr(tmp+1, '.') = '\0';
- if (int_asprintf(&tmp, "%s%s", __str(VERTO_MODULE_TABLE()), tmp + 1) < 0)
- tmp = NULL;
+ tmp = string_aconcat(__str(VERTO_MODULE_TABLE()), tmp + 1, NULL);
} else
tmp = NULL;
}
@@ -217,7 +248,7 @@ shouldload(void *symb, void *misc, char **err)
if (table->symb && data->reqsym
&& !module_symbol_is_present(NULL, table->symb)) {
if (err)
- int_asprintf(err, "Symbol not found: %s!", table->symb);
+ *err = string_aconcat("Symbol not found: ", table->symb, "!");
return 0;
}
@@ -265,6 +296,7 @@ do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,
tblname = int_get_table_name_from_filename(filename);
if (!tblname) {
free(tblname);
+ free(tmp->filename);
vfree(tmp);
return 0;
}
@@ -278,6 +310,7 @@ do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,
free(error);
module_close(tmp->dll);
free(tblname);
+ free(tmp->filename);
vfree(tmp);
return 0;
}
@@ -324,7 +357,8 @@ do_load_dir(const char *dirname, const char *prefix, const char *suffix,
if (flen < slen || strcmp(ent->d_name + flen - slen, suffix))
continue;
- if (int_asprintf(&tmp, "%s/%s", dirname, ent->d_name) < 0)
+ tmp = string_aconcat(dirname, "/", ent->d_name);
+ if (!tmp)
continue;
success = do_load_file(tmp, reqsym, reqtypes, record);
@@ -401,8 +435,8 @@ load_module(const char *impl, verto_ev_type reqtypes, module_record **record)
success = do_load_file(impl, 0, reqtypes, record);
if (!success) {
/* Try to do a load by the name */
- tmp = NULL;
- if (int_asprintf(&tmp, "%s%s%s", prefix, impl, suffix) > 0) {
+ tmp = string_aconcat(prefix, impl, suffix);
+ if (tmp) {
success = do_load_file(tmp, 0, reqtypes, record);
free(tmp);
}
@@ -494,6 +528,8 @@ remove_ev(verto_ev **origin, verto_ev *item)
static void
signal_ignore(verto_ctx *ctx, verto_ev *ev)
{
+ (void) ctx;
+ (void) ev;
}
verto_ctx *
@@ -566,6 +602,25 @@ verto_free(verto_ctx *ctx)
}
void
+verto_cleanup(void)
+{
+ module_record *record;
+
+ mutex_lock(&loaded_modules_mutex);
+
+ for (record = loaded_modules; record; record = record->next) {
+ module_close(record->dll);
+ free(record->filename);
+ }
+
+ vfree(loaded_modules);
+ loaded_modules = NULL;
+
+ mutex_unlock(&loaded_modules_mutex);
+ mutex_destroy(&loaded_modules_mutex);
+}
+
+void
verto_run(verto_ctx *ctx)
{
if (!ctx)
@@ -752,8 +807,12 @@ verto_set_flags(verto_ev *ev, verto_ev_flag flags)
if (!ev)
return;
+ /* No modification is needed, so do nothing. */
+ if (MUTABLE(ev->flags) == MUTABLE(flags))
+ return;
+
ev->flags &= ~_VERTO_EV_FLAG_MUTABLE_MASK;
- ev->flags |= flags & _VERTO_EV_FLAG_MUTABLE_MASK;
+ ev->flags |= MUTABLE(flags);
/* If setting flags isn't supported, just rebuild the event */
if (!ev->ctx->module->funcs->ctx_set_flags) {
@@ -765,7 +824,7 @@ verto_set_flags(verto_ev *ev, verto_ev_flag flags)
}
ev->actual &= ~_VERTO_EV_FLAG_MUTABLE_MASK;
- ev->actual |= flags & _VERTO_EV_FLAG_MUTABLE_MASK;
+ ev->actual |= MUTABLE(flags);
ev->ctx->module->funcs->ctx_set_flags(ev->ctx->ctx, ev, ev->ev);
}
@@ -861,7 +920,7 @@ verto_convert_module(const verto_module *module, int deflt, verto_mod_ctx *mctx)
module_record *mr;
if (!module)
- goto error;
+ return NULL;
if (deflt) {
mutex_lock(&loaded_modules_mutex);
diff --git a/src/util/verto/verto.h b/src/util/verto/verto.h
index 554036771722..55c583616215 100644
--- a/src/util/verto/verto.h
+++ b/src/util/verto/verto.h
@@ -33,6 +33,7 @@
typedef HANDLE verto_proc;
typedef DWORD verto_proc_status;
#else
+#include <sys/types.h>
typedef pid_t verto_proc;
typedef int verto_proc_status;
#endif
@@ -195,7 +196,8 @@ verto_set_default(const char *impl, verto_ev_type reqtypes);
* @see verto_add_idle()
* @see verto_add_signal()
* @see verto_add_child()
- * @param resize The allocator to use (behaves like realloc())
+ * @param resize The allocator to use (behaves like realloc();
+ * resize(ptr, 0) must free memory at ptr.)
* @param hierarchical Zero if the allocator is not hierarchical
*/
int
@@ -216,6 +218,19 @@ void
verto_free(verto_ctx *ctx);
/**
+ * Frees global state.
+ *
+ * Remove and free all allocated global state. Call only when no further
+ * contexts exist and all threads have exited.
+ *
+ * @see verto_new()
+ * @see verto_free()
+ * @see verto_default()
+ */
+void
+verto_cleanup(void);
+
+/**
* Run the verto_ctx forever, or at least until verto_break() is called.
*
* @see verto_break()
@@ -444,7 +459,8 @@ verto_get_flags(const verto_ev *ev);
* Sets the flags associated with the given verto_ev.
*
* See _VERTO_EV_FLAG_MUTABLE_MASK for the flags that can be changed
- * with this function. All others will be ignored.
+ * with this function. All others will be ignored. If the flags specified
+ * are the same as the flags the event already has, this function is a no-op.
*
* @see verto_add_io()
* @see verto_add_timeout()