You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2018/09/10 20:19:44 UTC

[1/6] qpid-proton git commit: PROTON-1798: [cpp] add library destructors for main classes

Repository: qpid-proton
Updated Branches:
  refs/heads/master 407711aac -> 6c765bc66


PROTON-1798: [cpp] add library destructors for main classes

Add library destructors to anchor vtables and typeinfo for connection, session,
sender, recever and delivery.

Without them, the ubsan sanitizer reports mismatched types due to different
weak vtable symbols in scope at library and executable link time.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/7885bd3b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/7885bd3b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/7885bd3b

Branch: refs/heads/master
Commit: 7885bd3b558dcf801e92ea866090d1110cc36aa1
Parents: e5aac00
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Sep 5 14:12:20 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Sep 7 11:26:25 2018 -0400

----------------------------------------------------------------------
 cpp/include/proton/connection.hpp | 2 ++
 cpp/include/proton/delivery.hpp   | 2 ++
 cpp/include/proton/receiver.hpp   | 2 ++
 cpp/include/proton/sender.hpp     | 2 ++
 cpp/include/proton/session.hpp    | 2 ++
 cpp/src/connection.cpp            | 2 ++
 cpp/src/delivery.cpp              | 1 +
 cpp/src/receiver.cpp              | 2 ++
 cpp/src/sender.cpp                | 2 ++
 cpp/src/session.cpp               | 2 ++
 10 files changed, 19 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/include/proton/connection.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/connection.hpp b/cpp/include/proton/connection.hpp
index 77bf96d..de9c904 100644
--- a/cpp/include/proton/connection.hpp
+++ b/cpp/include/proton/connection.hpp
@@ -51,6 +51,8 @@ PN_CPP_CLASS_EXTERN connection : public internal::object<pn_connection_t>, publi
     /// Create an empty connection.
     connection() : internal::object<pn_connection_t>(0) {}
 
+    PN_CPP_EXTERN ~connection();
+
     PN_CPP_EXTERN bool uninitialized() const;
     PN_CPP_EXTERN bool active() const;
     PN_CPP_EXTERN bool closed() const;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/include/proton/delivery.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/delivery.hpp b/cpp/include/proton/delivery.hpp
index 61a2fbe..c1823d9 100644
--- a/cpp/include/proton/delivery.hpp
+++ b/cpp/include/proton/delivery.hpp
@@ -44,6 +44,8 @@ class delivery : public transfer {
   public:
     delivery() {}
 
+    PN_CPP_EXTERN ~delivery();
+
     /// Return the receiver for this delivery.
     PN_CPP_EXTERN class receiver receiver() const;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/include/proton/receiver.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/receiver.hpp b/cpp/include/proton/receiver.hpp
index 6c8137d..7f78401 100644
--- a/cpp/include/proton/receiver.hpp
+++ b/cpp/include/proton/receiver.hpp
@@ -47,6 +47,8 @@ PN_CPP_CLASS_EXTERN receiver : public link {
     /// Create an empty receiver.
     receiver() {}
 
+    PN_CPP_EXTERN ~receiver();
+
     /// Open the receiver.
     ///
     /// @see endpoint_lifecycle

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/include/proton/sender.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/sender.hpp b/cpp/include/proton/sender.hpp
index 840032c..5f7c7b5 100644
--- a/cpp/include/proton/sender.hpp
+++ b/cpp/include/proton/sender.hpp
@@ -46,6 +46,8 @@ PN_CPP_CLASS_EXTERN sender : public link {
     /// Create an empty sender.
     sender() {}
 
+    PN_CPP_EXTERN ~sender();
+
     /// Open the sender.
     ///
     /// @see endpoint_lifecycle

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/include/proton/session.hpp
----------------------------------------------------------------------
diff --git a/cpp/include/proton/session.hpp b/cpp/include/proton/session.hpp
index 78a1fd4..7f289f5 100644
--- a/cpp/include/proton/session.hpp
+++ b/cpp/include/proton/session.hpp
@@ -49,6 +49,8 @@ PN_CPP_CLASS_EXTERN session : public internal::object<pn_session_t>, public endp
     /// Create an empty session.
     session() : internal::object<pn_session_t>(0) {}
 
+    PN_CPP_EXTERN ~session();
+
     PN_CPP_EXTERN bool uninitialized() const;
     PN_CPP_EXTERN bool active() const;
     PN_CPP_EXTERN bool closed() const;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/src/connection.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/connection.cpp b/cpp/src/connection.cpp
index b2dadae..223bb0c 100644
--- a/cpp/src/connection.cpp
+++ b/cpp/src/connection.cpp
@@ -45,6 +45,8 @@
 
 namespace proton {
 
+connection::~connection() {}
+
 transport connection::transport() const {
     return make_wrapper(pn_connection_transport(pn_object()));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/src/delivery.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/delivery.cpp b/cpp/src/delivery.cpp
index 0562304..7baa475 100644
--- a/cpp/src/delivery.cpp
+++ b/cpp/src/delivery.cpp
@@ -40,6 +40,7 @@ namespace proton {
 
 delivery::delivery(pn_delivery_t* d): transfer(make_wrapper(d)) {}
 receiver delivery::receiver() const { return make_wrapper<class receiver>(pn_delivery_link(pn_object())); }
+delivery::~delivery() {}
 void delivery::accept() { settle_delivery(pn_object(), ACCEPTED); }
 void delivery::reject() { settle_delivery(pn_object(), REJECTED); }
 void delivery::release() { settle_delivery(pn_object(), RELEASED); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/src/receiver.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/receiver.cpp b/cpp/src/receiver.cpp
index b7239a5..4d24c6f 100644
--- a/cpp/src/receiver.cpp
+++ b/cpp/src/receiver.cpp
@@ -39,6 +39,8 @@ namespace proton {
 
 receiver::receiver(pn_link_t* r): link(make_wrapper(r)) {}
 
+receiver::~receiver() {}
+
 void receiver::open() {
     attach();
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/src/sender.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/sender.cpp b/cpp/src/sender.cpp
index 70e9fa6..003adf8 100644
--- a/cpp/src/sender.cpp
+++ b/cpp/src/sender.cpp
@@ -40,6 +40,8 @@ namespace proton {
 
 sender::sender(pn_link_t *l): link(make_wrapper(l)) {}
 
+sender::~sender() {}
+
 void sender::open() {
     attach();
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7885bd3b/cpp/src/session.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/session.cpp b/cpp/src/session.cpp
index a64e0ad..fb2e6b3 100644
--- a/cpp/src/session.cpp
+++ b/cpp/src/session.cpp
@@ -36,6 +36,8 @@
 
 namespace proton {
 
+session::~session() {}
+
 void session::open() {
     pn_session_open(pn_object());
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[5/6] qpid-proton git commit: PROTON-1930: [cpp] Fix race condition in container_test.cpp

Posted by ac...@apache.org.
PROTON-1930: [cpp] Fix race condition in container_test.cpp

Test was starting container, opening connection and then checking for
["start", "open"] sequence to be set by handlers.

Sometimes the sequence was instead ["open", "start"], which is legal since the
events are generated in different handler contexts.

Fixed by starting container, waiting for "start", opening connection, then
waiting for "open"


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d3c11354
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d3c11354
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d3c11354

Branch: refs/heads/master
Commit: d3c113548146b56cdd8b2a31c2d4dd7ba5dddbfd
Parents: 27edd9a
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Sep 10 12:35:52 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Sep 10 15:50:37 2018 -0400

----------------------------------------------------------------------
 cpp/src/container_test.cpp | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d3c11354/cpp/src/container_test.cpp
----------------------------------------------------------------------
diff --git a/cpp/src/container_test.cpp b/cpp/src/container_test.cpp
index 6f7caa4..0e74aaa 100644
--- a/cpp/src/container_test.cpp
+++ b/cpp/src/container_test.cpp
@@ -366,17 +366,18 @@ void test_container_mt_stop_empty() {
     c.auto_stop( false );
     container_runner runner(c);
     auto t = std::thread(runner);
-    // Must ensure that thread is joined or detached
+    // Must ensure that thread is joined
     try {
         ASSERT_EQUAL("start", th.wait());
         c.stop();
         t.join();
         ASSERT_EQUAL("", th.error().name());
-    } catch (...) {
-        // We don't join as we don't know if we'll be stuck waiting
-        if (t.joinable()) {
-            t.detach();
-        }
+    } catch (const std::exception &e) {
+        std::cerr << FAIL_MSG(e.what()) << std::endl;
+        // If join hangs, let the test die by timeout.  We cannot
+        // detach and continue: deleting the container while t is
+        // still alive will put the process in an undefined state.
+        t.join();
         throw;
     }
 }
@@ -387,19 +388,20 @@ void test_container_mt_stop() {
     c.auto_stop(false);
     container_runner runner(c);
     auto t = std::thread(runner);
-    // Must ensure that thread is joined or detached
+    // Must ensure that thread is joined
     try {
         test_listen_handler lh;
-        c.listen("//:0", lh);       //  Also opens a connection
         ASSERT_EQUAL("start", th.wait());
+        c.listen("//:0", lh);       //  Also opens a connection
         ASSERT_EQUAL("open", th.wait());
         c.stop();
         t.join();
-    } catch (...) {
-        // We don't join as we don't know if we'll be stuck waiting
-        if (t.joinable()) {
-            t.detach();
-        }
+    } catch (const std::exception& e) {
+        std::cerr << FAIL_MSG(e.what()) << std::endl;
+        // If join hangs, let the test die by timeout.  We cannot
+        // detach and continue: deleting the container while t is
+        // still alive will put the process in an undefined state.
+        t.join();
         throw;
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[2/6] qpid-proton git commit: PROTON-1798: [c] Fix benign race in broker.c example found by tsan

Posted by ac...@apache.org.
PROTON-1798: [c] Fix benign race in broker.c example found by tsan


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/c6db6358
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/c6db6358
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/c6db6358

Branch: refs/heads/master
Commit: c6db635838f0abb67eb37bf565d4072870e1fe9d
Parents: 407711a
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Sep 4 19:32:59 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Sep 7 11:26:25 2018 -0400

----------------------------------------------------------------------
 c/examples/broker.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c6db6358/c/examples/broker.c
----------------------------------------------------------------------
diff --git a/c/examples/broker.c b/c/examples/broker.c
index 69dc536..6ffe8ed 100644
--- a/c/examples/broker.c
+++ b/c/examples/broker.c
@@ -216,7 +216,6 @@ typedef struct broker_t {
   size_t threads;
   const char *container_id;     /* AMQP container-id */
   queues_t queues;
-  bool finished;
   pn_ssl_domain_t *ssl_domain;
 } broker_t;
 
@@ -276,14 +275,14 @@ static void session_unsub(broker_t *b, pn_session_t *ssn) {
 
 static void check_condition(pn_event_t *e, pn_condition_t *cond) {
   if (pn_condition_is_set(cond)) {
-    fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)),
-            pn_condition_get_name(cond), pn_condition_get_description(cond));
+    printf("%s: %s: %s\n", pn_event_type_name(pn_event_type(e)),
+           pn_condition_get_name(cond), pn_condition_get_description(cond));
   }
 }
 
 const int WINDOW=5; /* Very small incoming credit window, to show flow control in action */
 
-static void handle(broker_t* b, pn_event_t* e) {
+static bool handle(broker_t* b, pn_event_t* e) {
   pn_connection_t *c = pn_event_connection(e);
 
   switch (pn_event_type(e)) {
@@ -418,25 +417,26 @@ static void handle(broker_t* b, pn_event_t* e) {
     break;
 
    case PN_PROACTOR_INTERRUPT:
-    b->finished = true;
     pn_proactor_interrupt(b->proactor); /* Pass along the interrupt to the other threads */
-    break;
+    return false;
 
    default:
     break;
   }
+  return true;
 }
 
 static void* broker_thread(void *void_broker) {
   broker_t *b = (broker_t*)void_broker;
+  bool finished = false;
   do {
     pn_event_batch_t *events = pn_proactor_wait(b->proactor);
     pn_event_t *e;
     while ((e = pn_event_batch_next(events))) {
-      handle(b, e);
+        if (!handle(b, e)) finished = true;
     }
     pn_proactor_done(b->proactor, events);
-  } while(!b->finished);
+  } while(!finished);
   return NULL;
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[4/6] qpid-proton git commit: PROTON-1798: cmake runtime-check improvements

Posted by ac...@apache.org.
PROTON-1798: cmake runtime-check improvements

Usage notes:
- new CMake variable: RUNTIME_CHECK, choose from [memcheck helgrind asan tsan OFF]
- defaults to 'memcheck' if available, else OFF
- old ENABLE_ variables for valgrind/sanitizers are deprecated
- example_test scripts check for stderr output including from killed processes

Implementation details:

- moved all runtime-check setup code to seprate runtime-check.cmake
- tool-agnostic internal CMake variables for running tests
- removed all valgrind-specific code outside of runtime-check.cmake
- example_test.py check stderr as well as exit status to catch broker issues.

NOTE: asan,tsan not yet working for python/ruby bindings, they are disabled in
san builds. See tests/preload_asan.sh for current status of the work.

NOTE: Some python soak tests for obscure messenger features were removed, they
have faulty start-up timing logic and can fail under valgrind. We can restore
them if needed but we'll need to fix the -X feature of msgr-recv to report ready
only after connections are remote open.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/27edd9ac
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/27edd9ac
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/27edd9ac

Branch: refs/heads/master
Commit: 27edd9aca3b2b1078089ceaa2a387f0016ac6f0a
Parents: 7885bd3
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Sep 7 13:20:42 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Sep 10 15:41:24 2018 -0400

----------------------------------------------------------------------
 CMakeLists.txt                      |  71 +++------------
 c/examples/CMakeLists.txt           |   7 +-
 c/examples/example_test.py          |  58 +++++-------
 c/tests/CMakeLists.txt              |   4 +-
 c/tests/fuzz/CMakeLists.txt         |   2 +-
 c/tests/threaderciser.supp          |  18 ----
 c/tests/threaderciser.tsupp         |   5 -
 cpp/CMakeLists.txt                  |   2 +-
 cpp/examples/CMakeLists.txt         |  14 ++-
 cpp/examples/broker.cpp             |   4 +-
 cpp/examples/example_test.py        |  42 ++-------
 misc/config.sh.in                   |   6 --
 python/CMakeLists.txt               |   8 +-
 python/tests/proton_tests/common.py |  35 +------
 python/tests/proton_tests/soak.py   |  83 ++---------------
 python/tests/proton_tests/ssl.py    |  33 -------
 python/tox.ini.in                   |   2 +-
 ruby/CMakeLists.txt                 |   8 +-
 runtime_check.cmake                 | 123 +++++++++++++++++++++++++
 scripts/env.py                      |   5 -
 tests/preload_asan.sh               |  51 +++++++++++
 tests/py/test_subprocess.py         | 105 +++++++++++++++++++++
 tests/valgrind.supp                 | 151 +++++++++++++++++++++++++++++++
 23 files changed, 517 insertions(+), 320 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 560dc05..105f22e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,9 @@ find_package (CyrusSASL)
 
 enable_testing ()
 
+# Set up runtime checks (valgrind, sanitizers etc.)
+include(runtime_check.cmake)  
+
 ## Variables used across components
 
 set (PN_ENV_SCRIPT "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/env.py")
@@ -188,23 +191,6 @@ if (CMAKE_C_COMPILER_ID MATCHES "Clang")
   set (CXX_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-float-equal -Wno-padded -Wno-sign-conversion -Wno-switch-enum -Wno-weak-vtables -Wno-exit-time-destructors -Wno-global-constructors -Wno-shorten-64-to-32 -Wno-documentation -Wno-documentation-unknown-command -Wno-old-style-cast -Wno-missing-noreturn")
 endif()
 
-# Sanitizer flags apply to to both GNU and clang, C and C++
-if(ENABLE_SANITIZERS)
-  set(SANITIZE_FLAGS "-g -fno-omit-frame-pointer -fsanitize=address -fsanitize=leak -fsanitize=undefined")
-endif()
-if(ENABLE_TSAN)
-  set(SANITIZE_FLAGS "-g -fno-omit-frame-pointer -fsanitize=thread")
-endif()
-if (SANITIZE_FLAGS)
-  mark_as_advanced(SANITIZE_FLAGS)
-  if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}")
-  endif()
-  if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}")
-  endif()
-endif()
-
 if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   if (NOT CMAKE_OSX_ARCHITECTURES)
     set(CMAKE_OSX_ARCHITECTURES "x86_64")
@@ -300,41 +286,6 @@ endforeach()
 set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION})
 # End of variables used during install
 
-# Can't do valgrind and coverage at athe same time - coverage takes precedence
-if (CMAKE_BUILD_TYPE MATCHES "Coverage")
-  message(STATUS "Building for coverage analysis; no run-time error detection")
-else ()
-  find_program(VALGRIND_EXECUTABLE valgrind DOC "Location of the valgrind program")
-  mark_as_advanced (VALGRIND_EXECUTABLE)
-
-  option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON)
-  if (ENABLE_VALGRIND)
-    if (VALGRIND_EXECUTABLE)
-      set (VALGRIND_SUPPRESSIONS ${CMAKE_SOURCE_DIR}/c/tests/valgrind.supp CACHE STRING "Default valgrind suppressions")
-      set (VALGRIND_OPTIONS "--error-exitcode=42 --quiet --leak-check=full --trace-children=yes" CACHE STRING "Default valgrind options")
-      mark_as_advanced(VALGRIND_SUPPRESSIONS VALGRIND_OPTIONS)
-      set (VALGRIND_ENV "VALGRIND=${VALGRIND_EXECUTABLE}" "VALGRIND_ARGS=${VALGRIND_OPTIONS} --suppressions=${VALGRIND_SUPPRESSIONS}")
-      separate_arguments(VALGRIND_OPTIONS_LIST UNIX_COMMAND ${VALGRIND_OPTIONS})
-      set (memcheck-cmd ${VALGRIND_EXECUTABLE} ${VALGRIND_OPTIONS_LIST} "--suppressions=${VALGRIND_SUPPRESSIONS}")
-      set (racecheck-cmd ${VALGRIND_EXECUTABLE} --tool=helgrind --error-exitcode=42 --quiet)
-    else ()
-      message(STATUS "Can't locate the valgrind command; no run-time error detection")
-    endif ()
-  endif ()
-endif ()
-
-# Options to enable sanitizing compile flags. Compile flags are set in c/CMakeLists.txt
-option(ENABLE_SANITIZERS "Compile with sanitizers (ASan, UBSan, TSan); incompatible with Valgrind" OFF)
-option(ENABLE_TSAN "Compile with Thread Sanitizer (TSan); incompatible with Valgrind" OFF)
-if (ENABLE_SANITIZERS OR ENABLE_TSAN)
-  set(DISABLE ENABLE_VALGRIND ENABLE_UNDEFINED_ERROR BUILD_GO)
-  message(STATUS "Building with sanitizers; disables ${DISABLE}")
-  foreach(d ${DISABLE})
-    set(${d} OFF CACHE BOOL "Disabled to run sanitizers" FORCE)
-  endforeach()
-  unset(VALGRIND_ENV)
-endif()
-
 # Set result to a native search path - used by examples and binding tests.
 # args after result are directories or search paths.
 macro(set_search_path result)
@@ -379,11 +330,11 @@ endif()
 find_program(GO_EXE go)
 mark_as_advanced(GO_EXE)
 if (GO_EXE)
-  if(WIN32)
+  set (DEFAULT_GO ON)
+  if(WIN32 OR RUNTIME_CHECK)
     # Go on windows requires gcc tool chain
+    # Go does not work with C-based runtime checkers.
     set (DEFAULT_GO OFF)
-  else()
-    set (DEFAULT_GO ON)
   endif()
 endif (GO_EXE)
 
@@ -405,15 +356,17 @@ if(SWIG_FOUND)
 
   # Prerequisites for Python wrapper:
   find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT)
-  if (PYTHONLIBS_FOUND)
+  # TODO aconway 2018-09-07: get python binding tests working with sanitizers
+  if (PYTHONLIBS_FOUND AND NOT SANITIZE_FLAGS)
     set (DEFAULT_PYTHON ON)
-  endif (PYTHONLIBS_FOUND)
+  endif ()
 
   # Prerequisites for Ruby:
   find_package(Ruby)
-  if (RUBY_FOUND)
+  # TODO aconway 2018-09-07: get ruby binding tests working with sanitizers
+  if (RUBY_FOUND AND NOT SANITIZE_FLAGS)
     set (DEFAULT_RUBY ON)
-  endif (RUBY_FOUND)
+  endif ()
 endif()
 
 # To kick-start a build with just a few bindings enabled by default, e.g. ruby and go:

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/c/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c/examples/CMakeLists.txt b/c/examples/CMakeLists.txt
index 6128f62..b04e444 100644
--- a/c/examples/CMakeLists.txt
+++ b/c/examples/CMakeLists.txt
@@ -45,6 +45,9 @@ endif()
 
 add_test(
   NAME c-example-tests
-  COMMAND ${PN_ENV_SCRIPT} "PATH=${test_path}" ${VALGRIND_ENV} --
-          ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v
+  COMMAND ${PN_ENV_SCRIPT}
+  "PATH=${test_path}"
+  "PYTHONPATH=${CMAKE_SOURCE_DIR}/tests/py"
+  ${TEST_ENV} --
+  ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/c/examples/example_test.py
----------------------------------------------------------------------
diff --git a/c/examples/example_test.py b/c/examples/example_test.py
index 1834989..35a8993 100644
--- a/c/examples/example_test.py
+++ b/c/examples/example_test.py
@@ -20,31 +20,14 @@
 # Run the C examples and verify that they behave as expected.
 # Example executables must be in PATH
 
-import unittest, sys, time, re
+import unittest
 
-import subprocess
+from test_subprocess import Popen, TestProcessError, check_output
 
-class Server(subprocess.Popen):
+class Server(Popen):
     def __init__(self, *args, **kwargs):
-        self.kill_me = kwargs.pop('kill_me', False)
-        kwargs.update({'universal_newlines': True,
-                       'stdout': subprocess.PIPE})
         super(Server, self).__init__(*args, **kwargs)
-
-    def __enter__(self):
-        line = self.stdout.readline()
-        self.port = re.search("listening on ([0-9]+)$", line).group(1)
-        return self
-
-    def __exit__(self, *args):
-        if self.kill_me:
-            self.kill()
-            self.stdout.close() # Doesn't get closed if killed
-        self.wait()
-
-def check_output(*args, **kwargs):
-    kwargs.update({'universal_newlines': True})
-    return subprocess.check_output(*args, **kwargs)
+        self.port = self.expect("listening on ([0-9]+)$").group(1)
 
 MESSAGES=10
 
@@ -64,6 +47,10 @@ class ExampleTest(unittest.TestCase):
         """Run an example with standard arguments, return output"""
         return check_output([name, "", port, "xtest", str(messages)])
 
+    def startex(self, name, port, messages=MESSAGES):
+        """Start an example sub-process with standard arguments"""
+        return Popen([name, "", port, "xtest", str(messages)])
+
     def test_send_receive(self):
         """Send first then receive"""
         with Broker() as b:
@@ -73,20 +60,21 @@ class ExampleTest(unittest.TestCase):
     def test_receive_send(self):
         """Start receiving  first, then send."""
         with Broker() as b:
+            r = self.startex("receive", b.port)
             self.assertEqual(send_expect(), self.runex("send", b.port))
-            self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port))
+            self.assertMultiLineEqual(receive_expect(), r.communicate()[0])
 
     def test_send_direct(self):
         """Send to direct server"""
-        with Server(["direct", "", "0"]) as d:
-            self.assertEqual(send_expect(), self.runex("send", d.port))
-            self.assertMultiLineEqual(receive_expect(), d.communicate()[0])
+        d = Server(["direct", "", "0"])
+        self.assertEqual(send_expect(), self.runex("send", d.port))
+        self.assertMultiLineEqual(receive_expect(), d.communicate()[0])
 
     def test_receive_direct(self):
         """Receive from direct server"""
-        with Server(["direct", "", "0"]) as d:
-            self.assertMultiLineEqual(receive_expect(), self.runex("receive", d.port))
-            self.assertEqual("10 messages sent and acknowledged\n", d.communicate()[0])
+        d =  Server(["direct", "", "0"])
+        self.assertMultiLineEqual(receive_expect(), self.runex("receive", d.port))
+        self.assertEqual("10 messages sent and acknowledged\n", d.communicate()[0])
 
     def test_send_abort_broker(self):
         """Sending aborted messages to a broker"""
@@ -101,13 +89,13 @@ class ExampleTest(unittest.TestCase):
 
     def test_send_abort_direct(self):
         """Send aborted messages to the direct server"""
-        with Server(["direct", "", "0", "examples", "20"]) as d:
-            self.assertEqual(send_expect(), self.runex("send", d.port))
-            self.assertEqual(send_abort_expect(), self.runex("send-abort", d.port))
-            self.assertEqual(send_expect(), self.runex("send", d.port))
-            expect = receive_expect_messages() + "Message aborted\n"*MESSAGES + receive_expect_messages()+receive_expect_total(20)
-            self.maxDiff = None
-            self.assertMultiLineEqual(expect, d.communicate()[0])
+        d = Server(["direct", "", "0", "examples", "20"])
+        self.assertEqual(send_expect(), self.runex("send", d.port))
+        self.assertEqual(send_abort_expect(), self.runex("send-abort", d.port))
+        self.assertEqual(send_expect(), self.runex("send", d.port))
+        expect = receive_expect_messages() + "Message aborted\n"*MESSAGES + receive_expect_messages()+receive_expect_total(20)
+        self.maxDiff = None
+        self.assertMultiLineEqual(expect, d.communicate()[0])
 
     def test_send_ssl_receive(self):
         """Send with SSL, then receive"""

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/c/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c/tests/CMakeLists.txt b/c/tests/CMakeLists.txt
index 87dfdb6..a4bfb67 100644
--- a/c/tests/CMakeLists.txt
+++ b/c/tests/CMakeLists.txt
@@ -32,7 +32,7 @@ macro (pn_add_c_test_nolib test)
   if (BUILD_WITH_CXX)
     set_source_files_properties (${ARGN} PROPERTIES LANGUAGE CXX)
   endif (BUILD_WITH_CXX)
-  add_test(NAME ${test} COMMAND ${test_env} ${memcheck-cmd} $<TARGET_FILE:${test}>)
+  add_test(NAME ${test} COMMAND ${test_env} ${TEST_EXE_PREFIX_CMD} $<TARGET_FILE:${test}>)
 endmacro (pn_add_c_test_nolib)
 
 # Add test with qpid-proton-core linked
@@ -58,7 +58,7 @@ if(HAS_PROACTOR)
   pn_add_c_test (c-proactor-tests proactor.c)
   target_link_libraries (c-proactor-tests qpid-proton-proactor)
 
-  # TODO Enable by default when races are cleared up
+  # TODO Enable by default when races and xcode problems are cleared up
   option(THREADERCISER "Run the threaderciser concurrency tests" OFF)
   if (THREADERCISER)
     pn_add_c_test(c-threaderciser threaderciser.c)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/c/tests/fuzz/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c/tests/fuzz/CMakeLists.txt b/c/tests/fuzz/CMakeLists.txt
index 19825b6..5d4187d 100644
--- a/c/tests/fuzz/CMakeLists.txt
+++ b/c/tests/fuzz/CMakeLists.txt
@@ -37,7 +37,7 @@ macro (pn_add_fuzz_test test)
   if (FUZZ_REGRESSION_TESTS)
     # StandaloneFuzzTargetMain cannot walk directory trees
     file(GLOB_RECURSE files ${CMAKE_CURRENT_SOURCE_DIR}/${test}/*)
-    add_test (NAME ${test} COMMAND ${memcheck-cmd} $<TARGET_FILE:${test}> ${files})
+    add_test (NAME ${test} COMMAND ${TEST_EXE_PREFIX_CMD} $<TARGET_FILE:${test}> ${files})
   else ()
     add_test (NAME ${test} COMMAND $<TARGET_FILE:${test}> -runs=1 ${CMAKE_CURRENT_SOURCE_DIR}/${test}>)
   endif ()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/c/tests/threaderciser.supp
----------------------------------------------------------------------
diff --git a/c/tests/threaderciser.supp b/c/tests/threaderciser.supp
deleted file mode 100644
index d14ff61..0000000
--- a/c/tests/threaderciser.supp
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-   IGNORE: benign race in pni_log_enabled
-   Helgrind:Race
-   fun:pni_log_enabled
-}
-
-{
-   IGNORE: NSS library poking around in its own data segment upsets helgrind
-   Helgrind:Race
-   fun:strpbrk
-   fun:_nss_files_parse_servent
-}
-{
-   IGNORE: NSS library poking around in its own text segment upsets helgrind
-   Helgrind:Race
-   fun:*
-   fun:_nss_files_getservbyname_r
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/c/tests/threaderciser.tsupp
----------------------------------------------------------------------
diff --git a/c/tests/threaderciser.tsupp b/c/tests/threaderciser.tsupp
deleted file mode 100644
index 18ceb23..0000000
--- a/c/tests/threaderciser.tsupp
+++ /dev/null
@@ -1,5 +0,0 @@
-# TSAN suppressions for threaderciser
-
-# Benign race in pni_log_enabled
-race:pni_log_enabled
-

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 0dcede2..a06e67d 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -242,7 +242,7 @@ macro(add_cpp_test test)
       "PATH=$<TARGET_FILE_DIR:qpid-proton>"
       $<TARGET_FILE:${test}> ${ARGN})
   else ()
-    add_test (NAME cpp-${test} COMMAND ${memcheck-cmd} $<TARGET_FILE:${test}> ${ARGN})
+    add_test (NAME cpp-${test} COMMAND ${TEST_EXE_PREFIX_CMD} $<TARGET_FILE:${test}> ${ARGN})
   endif ()
 endmacro(add_cpp_test)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/cpp/examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt
index 18d922e..ba18d83 100644
--- a/cpp/examples/CMakeLists.txt
+++ b/cpp/examples/CMakeLists.txt
@@ -104,7 +104,7 @@ if(HAS_ENOUGH_CPP11)
 endif()
 
 # Add a test with the correct environment to find test executables and valgrind.
-macro(add_cpp_test name)
+macro(add_cpp_example_test name)
   if(WIN32)
     set(test_path "$<TARGET_FILE_DIR:broker>;$<TARGET_FILE_DIR:qpid-proton>;$<TARGET_FILE_DIR:qpid-proton-cpp>")
   else(WIN32)
@@ -112,13 +112,17 @@ macro(add_cpp_test name)
   endif(WIN32)
   add_test(
     NAME ${name}
-    COMMAND ${PN_ENV_SCRIPT} "PATH=${test_path}" ${VALGRIND_ENV}
-            "HAS_CPP11=$<$<BOOL:${HAS_ENOUGH_CPP11}>:1>" -- ${ARGN}
+    COMMAND ${PN_ENV_SCRIPT}
+    "PATH=${test_path}"
+    "PYTHONPATH=${CMAKE_SOURCE_DIR}/tests/py"
+    "HAS_CPP11=$<$<BOOL:${HAS_ENOUGH_CPP11}>:1>"
+    ${TEST_ENV} --
+    ${ARGN}
     )
 endmacro()
 
-add_cpp_test(cpp-example-container ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleTest)
+add_cpp_example_test(cpp-example-container ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleTest)
 
 if (NOT SSL_IMPL STREQUAL none)
-add_cpp_test(cpp-example-container-ssl ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleSSLTest)
+add_cpp_example_test(cpp-example-container-ssl ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleSSLTest)
 endif()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/cpp/examples/broker.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/broker.cpp b/cpp/examples/broker.cpp
index d45309e..b15ac39 100644
--- a/cpp/examples/broker.cpp
+++ b/cpp/examples/broker.cpp
@@ -355,7 +355,7 @@ public:
     }
 
     void on_error(const proton::error_condition& e) OVERRIDE {
-        std::cerr << "error: " << e.what() << std::endl;
+        std::cout << "protocol error: " << e.what() << std::endl;
     }
 
     // The container calls on_transport_close() last.
@@ -429,7 +429,7 @@ int main(int argc, char **argv) {
     } catch (const example::bad_option& e) {
         std::cout << opts << std::endl << e.what() << std::endl;
     } catch (const std::exception& e) {
-        std::cerr << "broker shutdown: " << e.what() << std::endl;
+        std::cout << "broker shutdown: " << e.what() << std::endl;
     }
     return 1;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/cpp/examples/example_test.py
----------------------------------------------------------------------
diff --git a/cpp/examples/example_test.py b/cpp/examples/example_test.py
index edcde27..38a9a6e 100644
--- a/cpp/examples/example_test.py
+++ b/cpp/examples/example_test.py
@@ -20,40 +20,21 @@
 # Run the C++ examples and verify that they behave as expected.
 # Example executables must be in PATH
 
-import unittest, sys, time, re, shutil, os
+import unittest, sys, shutil, os
+from test_subprocess import Popen, TestProcessError, check_output
 from os.path import dirname
 from string import Template
 
-import subprocess
-
-class Server(subprocess.Popen):
+class Server(Popen):
+    """A process that prints 'listening on <port>' to stdout"""
     def __init__(self, *args, **kwargs):
-        self.port = None
-        self.kill_me = kwargs.pop('kill_me', False)
-        kwargs.update({'universal_newlines': True,
-                       'stdout': subprocess.PIPE})
         super(Server, self).__init__(*args, **kwargs)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, *args):
-        if self.kill_me:
-            self.kill()
-            self.stdout.close() # Doesn't get closed if killed
-        self.wait()
+        self.port = self.expect("listening on ([0-9]+)$").group(1)
 
     @property
     def addr(self):
-        if not self.port:
-            line = self.stdout.readline()
-            self.port = re.search("listening on ([0-9]+)$", line).group(1)
         return ":%s/example" % self.port
 
-def check_output(*args, **kwargs):
-    kwargs.update({'universal_newlines': True})
-    return subprocess.check_output(*args, **kwargs)
-
 def _cyrusSetup(conf_dir):
   """Write out simple SASL config.tests
   """
@@ -77,12 +58,9 @@ mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
 # Globally initialize Cyrus SASL configuration
 _cyrusSetup('sasl-conf')
 
-def wait_listening(p):
-    return re.search(b"listening on ([0-9]+)$", p.stdout.readline()).group(1)
-
 class Broker(Server):
-  def __init__(self):
-    super(Broker, self).__init__(["broker", "-a", "//:0"], kill_me=True)
+    def __init__(self):
+        super(Broker, self).__init__(["broker", "-a", "//:0"], kill_me=True)
 
 CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES
 Did gire and gymble in the wabe. => DID GIRE AND GYMBLE IN THE WABE.
@@ -104,7 +82,7 @@ class ContainerExampleTest(unittest.TestCase):
         self.assertMultiLineEqual(recv_expect(), check_output(["simple_recv", "-a", Broker.addr]))
 
     def test_simple_recv_send(self):
-        recv = Server(["simple_recv", "-a", Broker.addr])
+        recv = Popen(["simple_recv", "-a", Broker.addr])
         self.assertMultiLineEqual("all messages confirmed\n", check_output(["simple_send", "-a", Broker.addr]))
         self.assertMultiLineEqual(recv_expect(), recv.communicate()[0])
 
@@ -119,8 +97,8 @@ class ContainerExampleTest(unittest.TestCase):
         self.assertMultiLineEqual("all messages confirmed\n", send.communicate()[0])
 
     def test_request_response(self):
-        with Server(["server", Broker.addr, "example"], kill_me=True) as server:
-            self.assertIn("connected to", server.stdout.readline())
+        with Popen(["server", Broker.addr, "example"], kill_me=True) as server:
+            server.expect("connected to %s" % Broker.addr)
             self.assertMultiLineEqual(CLIENT_EXPECT, check_output(["client", "-a", Broker.addr]))
 
     def test_request_response_direct(self):

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/misc/config.sh.in
----------------------------------------------------------------------
diff --git a/misc/config.sh.in b/misc/config.sh.in
index a61c757..dd23602 100755
--- a/misc/config.sh.in
+++ b/misc/config.sh.in
@@ -52,12 +52,6 @@ export LD_LIBRARY_PATH="$(merge_paths $PROTON_BUILD $LD_LIBRARY_PATH)"
 # Test applications
 export PATH="$(merge_paths $PATH $PROTON_BUILD/c/tools $PROTON_HOME/python/tests)"
 
-# Can the test harness use valgrind?
-if [[ -x "$(type -p valgrind)" && "@ENABLE_VALGRIND@" == "ON" ]] ; then
-    export VALGRIND=$(type -p valgrind)
-    export VALGRIND_ARGS="@VALGRIND_OPTIONS@"
-fi
-
 # Can the test harness use saslpasswd2?
 if [[ -x "$(type -p saslpasswd2)" ]] ; then
     export SASLPASSWD=$(type -p saslpasswd2)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/python/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index d63ab96..181128c 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -208,8 +208,8 @@ add_test (NAME python-test
   COMMAND ${PN_ENV_SCRIPT}
   "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}"
   "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
-  ${VALGRIND_ENV}
-  ${PYTHON_EXECUTABLE} -- ${python_coverage_options} "${py_tests}/proton-test")
+  ${TEST_ENV}
+  ${TEST_WRAP_PREFIX_CMD} ${PYTHON_EXECUTABLE} -- ${python_coverage_options} "${py_tests}/proton-test")
 set_tests_properties(python-test PROPERTIES PASS_REGULAR_EXPRESSION "Totals: .* 0 failed")
 
 check_python_module("tox" TOX_MODULE_FOUND)
@@ -237,8 +237,8 @@ else ()
         "PATH=${py_path}"
         "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
         "SWIG=${SWIG_EXECUTABLE}"
-        ${VALGRIND_ENV} --
-        ${PYTHON_EXECUTABLE} -m tox)
+        ${TEST_ENV} --
+        ${TEST_WRAP_PREFIX_CMD} ${PYTHON_EXECUTABLE} -m tox)
       set_tests_properties(python-tox-test
         PROPERTIES
         PASS_REGULAR_EXPRESSION "Totals: .* ignored, 0 failed"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/python/tests/proton_tests/common.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/common.py b/python/tests/proton_tests/common.py
index fd4decc..a56a2c0 100644
--- a/python/tests/proton_tests/common.py
+++ b/python/tests/proton_tests/common.py
@@ -281,7 +281,7 @@ class MessengerApp(object):
                 del cmd[0:1]
                 cmd.insert(0, foundfile)
                 cmd.insert(0, sys.executable)
-            self._process = Popen(cmd, stdout=PIPE, stderr=STDOUT,
+            self._process = Popen(cmd, stdout=PIPE,
                                   bufsize=4096, universal_newlines=True)
         except OSError:
             e = sys.exc_info()[1]
@@ -425,7 +425,8 @@ class MessengerReceiver(MessengerApp):
 
     # command string?
     def _build_command(self):
-        self._cmdline = self._command
+        self._cmdline = os.environ.get("TEST_EXE_PREFIX", "").split()
+        self._cmdline += self._command
         self._do_common_options()
         self._cmdline += ["-X", "READY"]
         assert self.subscriptions, "Missing subscriptions, required for receiver!"
@@ -468,47 +469,17 @@ class MessengerSenderC(MessengerSender):
         MessengerSender.__init__(self)
         self._command = ["msgr-send"]
 
-def setup_valgrind(self):
-    if "VALGRIND" not in os.environ:
-        raise Skipped("Skipping test - $VALGRIND not set.")
-    super(type(self), self).__init__()
-    self._command = [os.environ["VALGRIND"]] + os.environ["VALGRIND_ARGS"].split(' ') + self._command
-
-class MessengerSenderValgrind(MessengerSenderC):
-    """ Run the C sender under Valgrind
-    """
-    def __init__(self, suppressions=None):
-        setup_valgrind(self)
-
 class MessengerReceiverC(MessengerReceiver):
     def __init__(self):
         MessengerReceiver.__init__(self)
         self._command = ["msgr-recv"]
 
-class MessengerReceiverValgrind(MessengerReceiverC):
-    """ Run the C receiver under Valgrind
-    """
-    def __init__(self, suppressions=None):
-        setup_valgrind(self)
-
 class ReactorSenderC(MessengerSender):
     def __init__(self):
         MessengerSender.__init__(self)
         self._command = ["reactor-send"]
 
-class ReactorSenderValgrind(ReactorSenderC):
-    """ Run the C sender under Valgrind
-    """
-    def __init__(self, suppressions=None):
-        setup_valgrind(self)
-
 class ReactorReceiverC(MessengerReceiver):
     def __init__(self):
         MessengerReceiver.__init__(self)
         self._command = ["reactor-recv"]
-
-class ReactorReceiverValgrind(ReactorReceiverC):
-    """ Run the C receiver under Valgrind
-    """
-    def __init__(self, suppressions=None):
-        setup_valgrind(self)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/python/tests/proton_tests/soak.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/soak.py b/python/tests/proton_tests/soak.py
index 5e103fd..e015db5 100644
--- a/python/tests/proton_tests/soak.py
+++ b/python/tests/proton_tests/soak.py
@@ -24,9 +24,7 @@ import os
 
 from .common import Test, Skipped, free_tcp_ports, \
     MessengerReceiverC, MessengerSenderC, \
-    MessengerReceiverValgrind, MessengerSenderValgrind, \
     ReactorReceiverC, ReactorSenderC, \
-    ReactorReceiverValgrind, ReactorSenderValgrind, \
     isSSLPresent
 
 #
@@ -192,52 +190,14 @@ class MessengerTests(AppTests):
 
         self._do_test(iterations)
 
-    def _do_relay_test(self, receiver, relay, sender, domain="amqp"):
-        """ Send N messages to a receiver, which replies to each and forwards
-        each of them to different receiver.
-        Parameters:
-        iterations - repeat the senders this many times
-        target_count - # targets to send to
-        send_count = # messages sent to each target
-        send_batch - wait for replies after this many messages sent
-        forward_count - forward to this many targets
-        """
-        iterations = self.iterations
-        send_count = self.send_count
-        target_count = self.target_count
-        send_batch = self.send_batch
-        forward_count = self.forward_count
-
-        send_total = send_count * target_count
-        receive_total = send_total * iterations
-
-        port = free_tcp_ports()[0]
-
-        receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)]
-        receiver.receive_count = receive_total
-        receiver.send_reply = True
-        # forward to 'relay' - uses two links
-        # ## THIS FAILS:
-        # receiver.forwards = ["amqp://Relay/%d" % j for j in range(forward_count)]
-        receiver.forwards = ["%s://Relay" % domain]
-        receiver.timeout = MessengerTests._timeout
-        self.receivers.append( receiver )
-
-        relay.subscriptions = ["%s://0.0.0.0:%s" % (domain, port)]
-        relay.name = "Relay"
-        relay.receive_count = receive_total
-        relay.timeout = MessengerTests._timeout
-        self.receivers.append( relay )
-
-        # send to 'receiver'
-        sender.targets = ["%s://0.0.0.0:%s/X%dY" % (domain, port, j) for j in range(target_count)]
-        sender.send_count = send_total
-        sender.get_reply = True
-        sender.timeout = MessengerTests._timeout
-        self.senders.append( sender )
-
-        self._do_test(iterations)
-
+    # Removed messenger "relay" tests. The test start-up is faulty:
+    # msgr-recv prints it's -X ready message when it starts to open a
+    # connection but it does not wait for the remote open. The relay
+    # tests depends on mapping a container name from an incoming
+    # connection. They can fail under if the sender starts before the
+    # connection is complete (esp. valgrind with SSL connections) We
+    # could fix the tests but since messenger is deprecated it does
+    # not seem worthwhile.
 
     def _do_star_topology_test(self, r_factory, s_factory, domain="amqp"):
         """
@@ -291,10 +251,6 @@ class MessengerTests(AppTests):
         self._ssl_check()
         self._do_oneway_test(MessengerReceiverC(), MessengerSenderC(), "amqps")
 
-    def test_oneway_valgrind(self):
-        self.valgrind_test()
-        self._do_oneway_test(MessengerReceiverValgrind(), MessengerSenderValgrind())
-
     def test_echo_C(self):
         self._do_echo_test(MessengerReceiverC(), MessengerSenderC())
 
@@ -302,21 +258,6 @@ class MessengerTests(AppTests):
         self._ssl_check()
         self._do_echo_test(MessengerReceiverC(), MessengerSenderC(), "amqps")
 
-    def test_echo_valgrind(self):
-        self.valgrind_test()
-        self._do_echo_test(MessengerReceiverValgrind(), MessengerSenderValgrind())
-
-    def test_relay_C(self):
-        self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC())
-
-    def test_relay_C_SSL(self):
-        self._ssl_check()
-        self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC(), "amqps")
-
-    def test_relay_valgrind(self):
-        self.valgrind_test()
-        self._do_relay_test(MessengerReceiverValgrind(), MessengerReceiverValgrind(), MessengerSenderValgrind())
-
     def test_star_topology_C(self):
         self._do_star_topology_test( MessengerReceiverC, MessengerSenderC )
 
@@ -324,13 +265,5 @@ class MessengerTests(AppTests):
         self._ssl_check()
         self._do_star_topology_test( MessengerReceiverC, MessengerSenderC, "amqps" )
 
-    def test_star_topology_valgrind(self):
-        self.valgrind_test()
-        self._do_star_topology_test( MessengerReceiverValgrind, MessengerSenderValgrind )
-
     def test_oneway_reactor(self):
         self._do_oneway_test(ReactorReceiverC(), ReactorSenderC())
-
-    def test_oneway_reactor_valgrind(self):
-        self.valgrind_test()
-        self._do_oneway_test(ReactorReceiverValgrind(), ReactorSenderValgrind())

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/python/tests/proton_tests/ssl.py
----------------------------------------------------------------------
diff --git a/python/tests/proton_tests/ssl.py b/python/tests/proton_tests/ssl.py
index fcc3795..9419292 100644
--- a/python/tests/proton_tests/ssl.py
+++ b/python/tests/proton_tests/ssl.py
@@ -882,39 +882,6 @@ class SslTest(common.Test):
         receiver.wait()
         assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
 
-    def DISABLED_test_defaults_valgrind(self):
-        """ Run valgrind over a simple SSL connection (no certificates)
-        """
-        # the openssl libraries produce far too many valgrind errors to be
-        # useful.  AFAIK, there is no way to wriate a valgrind suppression
-        # expression that will ignore all errors from a given library.
-        # Until we can, skip this test.
-        port = common.free_tcp_ports()[0]
-
-        receiver = common.MessengerReceiverValgrind()
-        receiver.subscriptions = ["amqps://~127.0.0.1:%s" % port]
-        receiver.receive_count = 1
-        receiver.timeout = self.timeout
-        receiver.start()
-
-        sender = common.MessengerSenderValgrind()
-        sender.targets = ["amqps://127.0.0.1:%s/X" % port]
-        sender.send_count = 1
-        sender.timeout = self.timeout
-        sender.start()
-        sender.wait()
-        assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline())
-
-        receiver.wait()
-        assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline())
-
-        # self.server_domain.set_credentials(self._testpath("client-certificate.pem"),
-        #                                    self._testpath("client-private-key.pem"),
-        #                                    "client-password")
-
-        # self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
-        # self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER )
-
     def test_singleton(self):
         """Verify that only a single instance of SSL can exist per Transport"""
         transport = Transport()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/python/tox.ini.in
----------------------------------------------------------------------
diff --git a/python/tox.ini.in b/python/tox.ini.in
index c514078..ec4a77d 100644
--- a/python/tox.ini.in
+++ b/python/tox.ini.in
@@ -13,7 +13,7 @@ passenv =
     PKG_CONFIG_PATH
     CFLAGS
     SASLPASSWD
-    VALGRIND
+    TEST_EXE_PREFIX
 commands =
     @CMAKE_SOURCE_DIR@/python/tests/proton-test '{posargs:--ignore-file=@CMAKE_SOURCE_DIR@/python/tests/tox-blacklist}'
 deps =

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/ruby/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/ruby/CMakeLists.txt b/ruby/CMakeLists.txt
index e205250..eb99907 100644
--- a/ruby/CMakeLists.txt
+++ b/ruby/CMakeLists.txt
@@ -125,14 +125,18 @@ to_native_path("${bin};${c_lib_dir};$ENV{PATH}" PATH)
 execute_process(COMMAND ${RUBY_EXECUTABLE} -r minitest -e ""
   RESULT_VARIABLE result OUTPUT_QUIET ERROR_QUIET)
 if (result EQUAL 0)  # Have minitest
-  set(test_env ${PN_ENV_SCRIPT} -- "PATH=${PATH}" "RUBYLIB=${RUBYLIB}" "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}")
+  set(test_env ${PN_ENV_SCRIPT} --
+    "PATH=${PATH}"
+    "RUBYLIB=${RUBYLIB}"
+    "SASLPASSWD=${CyrusSASL_Saslpasswd_EXECUTABLE}"
+    ${TEST_ENV})
 
   macro(add_ruby_test script)
     get_filename_component(name ${script} NAME_WE)
     string(REPLACE "_" "-" name "ruby-${name}")
     add_test(
       NAME ${name}
-      COMMAND ${test_env} ${RUBY_EXECUTABLE} ${script} -v
+      COMMAND ${test_env} ${TEST_WRAP_PREFIX_CMD} ${RUBY_EXECUTABLE} ${script} -v
       ${ARGN})
 
   endmacro()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/runtime_check.cmake
----------------------------------------------------------------------
diff --git a/runtime_check.cmake b/runtime_check.cmake
new file mode 100644
index 0000000..e1d76c3
--- /dev/null
+++ b/runtime_check.cmake
@@ -0,0 +1,123 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Configuration for code analysis tools: runtime checking and coverage.
+
+# Any test that needs runtime checks should use TEST_EXE_PREFIX and TEST_ENV.
+# Normally they are set as a result of the RUNTIME_CHECK value,
+# but can be set directly for unsupported tools or unusual flags
+# e.g. -DTEST_EXE_PREFIX=rr or -DTEST_EXE_PREFIX="valgrind --tool=massif"
+
+set(TEST_EXE_PREFIX "" CACHE STRING "Prefix for test executable command line")
+set(TEST_WRAP_PREFIX "" CACHE STRING "Prefix for interpreter tests (e.g. python, ruby) that load proton as an extension")
+set(TEST_ENV "" CACHE STRING "Extra environment for tests: name1=value1;name2=value2")
+mark_as_advanced(TEST_EXE_PREFIX TEST_WRAP_PREFIX TEST_ENV)
+
+# Check for valgrind
+find_program(VALGRIND_EXECUTABLE valgrind DOC "location of valgrind program")
+set(VALGRIND_SUPPRESSIONS "${CMAKE_SOURCE_DIR}/tests/valgrind.supp" CACHE STRING "Suppressions file for valgrind")
+set(VALGRIND_COMMON_ARGS "--error-exitcode=42 --quiet --suppressions=${VALGRIND_SUPPRESSIONS}")
+mark_as_advanced(VALGRIND_EXECUTABLE VALGRIND_SUPPRESSIONS VALGRIND_COMMON_ARGS)
+
+# Check for compiler sanitizers
+if((CMAKE_C_COMPILER_ID MATCHES "GNU"
+      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.8)
+    OR (CMAKE_C_COMPILER_ID MATCHES "Clang"
+      AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.1))
+  set(HAS_SANITIZERS TRUE)
+endif()
+
+# Valid values for RUNTIME_CHECK
+set(runtime_checks OFF asan tsan memcheck helgrind)
+
+# Set the default
+if(NOT CMAKE_BUILD_TYPE MATCHES "Coverage" AND VALGRIND_EXECUTABLE)
+  set(RUNTIME_CHECK_DEFAULT "memcheck")
+endif()
+
+# Deprecated options to enable runtime checks
+macro(deprecated_enable_check old new doc)
+  option(${old} ${doc} OFF)
+  if (${old})
+    message("WARNING: option ${old} is deprecated, use RUNTIME_CHECK=${new} instead")
+    set(RUNTIME_CHECK_DEFAULT ${new})
+  endif()
+endmacro()
+deprecated_enable_check(ENABLE_VALGRIND memcheck "Use valgrind to detect run-time problems")
+deprecated_enable_check(ENABLE_SANITIZERS asan "Compile with memory sanitizers (asan, ubsan)")
+deprecated_enable_check(ENABLE_TSAN tsan "Compile with thread sanitizer (tsan)")
+
+set(RUNTIME_CHECK ${RUNTIME_CHECK_DEFAULT} CACHE string "Enable runtime checks. Valid values: ${runtime_checks}")
+
+if(CMAKE_BUILD_TYPE MATCHES "Coverage" AND RUNTIME_CHECK)
+  message(FATAL_ERROR "Cannot set RUNTIME_CHECK with CMAKE_BUILD_TYPE=Coverage")
+endif()
+
+macro(assert_has_sanitizers)
+  if(NOT HAS_SANITIZERS)
+    message(FATAL_ERROR "compiler sanitizers are not available")
+  endif()
+endmacro()
+
+macro(assert_has_valgrind)
+  if(NOT VALGRIND_EXECUTABLE)
+    message(FATAL_ERROR "valgrind is not available")
+  endif()
+endmacro()
+
+if(RUNTIME_CHECK STREQUAL "memcheck")
+  assert_has_valgrind()
+  message(STATUS "Runtime memory checker: valgrind memcheck")
+  set(TEST_EXE_PREFIX "${VALGRIND_EXECUTABLE} --tool=memcheck --leak-check=full ${VALGRIND_COMMON_ARGS}")
+  # FIXME aconway 2018-09-06: NO TEST_WRAP_PREFIX, need --trace-children + many suppressions
+
+elseif(RUNTIME_CHECK STREQUAL "helgrind")
+  assert_has_valgrind()
+  message(STATUS "Runtime race checker: valgrind helgrind")
+  set(TEST_EXE_PREFIX "${VALGRIND_EXECUTABLE} --tool=helgrind ${VALGRIND_COMMON_ARGS}")
+  # FIXME aconway 2018-09-06: NO TEST_WRAP_PREFIX, need --trace-children + many suppressions
+
+elseif(RUNTIME_CHECK STREQUAL "asan")
+  assert_has_sanitizers()
+  message(STATUS "Runtime memory checker: gcc/clang memory sanitizers")
+  set(SANITIZE_FLAGS "-g -fno-omit-frame-pointer -fsanitize=address,undefined")
+  set(TEST_WRAP_PREFIX "${CMAKE_SOURCE_DIR}/tests/preload_asan.sh $<TARGET_FILE:qpid-proton-core>")
+
+elseif(RUNTIME_CHECK STREQUAL "tsan")
+  assert_has_sanitizers()
+  message(STATUS "Runtime race checker: gcc/clang thread sanitizer")
+  set(SANITIZE_FLAGS "-g -fno-omit-frame-pointer -fsanitize=thread")
+
+elseif(RUNTIME_CHECK)
+  message(FATAL_ERROR "'RUNTIME_CHECK=${RUNTIME_CHECK}' is invalid, valid values: ${runtime_checks}")
+endif()
+
+if(SANITIZE_FLAGS)
+  set(ENABLE_UNDEFINED_ERROR OFF CACHE BOOL "Disabled for sanitizers" FORCE)
+  string(APPEND CMAKE_C_FLAGS " ${SANITIZE_FLAGS}")
+  string(APPEND CMAKE_CXX_FLAGS "${SANITIZE_FLAGS}")
+endif()
+
+if(TEST_EXE_PREFIX)
+  # Add TEST_EXE_PREFIX to TEST_ENV so test runner scripts can use it.
+  list(APPEND TEST_ENV "TEST_EXE_PREFIX=${TEST_EXE_PREFIX}")
+  # Make a CMake-list form of TEST_EXE_PREFIX for add_test() commands
+  separate_arguments(TEST_EXE_PREFIX_CMD UNIX_COMMAND "${TEST_EXE_PREFIX}")
+endif()
+separate_arguments(TEST_WRAP_PREFIX_CMD UNIX_COMMAND "${TEST_WRAP_PREFIX}")

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/scripts/env.py
----------------------------------------------------------------------
diff --git a/scripts/env.py b/scripts/env.py
index 04fa8bb..14df6d1 100644
--- a/scripts/env.py
+++ b/scripts/env.py
@@ -58,11 +58,6 @@ def main(argv=None):
     if len(args) == 0 or len(args[0]) == 0:
         raise Exception("Error: syntax error in command arguments")
 
-    if new_env.get("VALGRIND") and new_env.get("VALGRIND_ALL"):
-        # Python generates a lot of possibly-lost errors that are not errors, don't show them.
-        args = [new_env.get("VALGRIND"), "--show-reachable=no", "--show-possibly-lost=no",
-                "--error-exitcode=42"] + args
-
     p = subprocess.Popen(args, env=new_env)
     return p.wait()
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/tests/preload_asan.sh
----------------------------------------------------------------------
diff --git a/tests/preload_asan.sh b/tests/preload_asan.sh
new file mode 100755
index 0000000..e4928f9
--- /dev/null
+++ b/tests/preload_asan.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+if test $# -lt 2; then
+    echo <<EOF
+usage: $0 LIB EXE [args ...]
+Get the libasan linked to LIB and preload it to run `EXE args ...`
+EOF
+fi
+
+LIB=$1; shift
+EXE=$2
+
+case $EXE in
+    *ruby*|*.rb|*python*|*.py)
+        # ruby has spurious leaks and causes asan errors.
+        #
+        # python tests have many leaks that may be real, but need to be
+        # analysed & fixed or suppressed before turning this on
+
+        # Disable link order check to run with limited sanitizing
+        # Still seeing problems.
+        export ASAN_OPTIONS=verify_asan_link_order=0
+        ;;
+    *)
+        # Preload the asan library linked to LIB. Note we need to
+        # check the actual linkage, there may be multiple asan lib
+        # versions installed and we must use the same one.
+        libasan=$(ldd $LIB | awk "/(libasan\\.so[.0-9]*)/ { print \$1 }")
+        export LD_PRELOAD="$libasan:$LD_PRELOAD"
+        ;;
+esac
+
+exec "$@"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/tests/py/test_subprocess.py
----------------------------------------------------------------------
diff --git a/tests/py/test_subprocess.py b/tests/py/test_subprocess.py
new file mode 100644
index 0000000..1c7d2b9
--- /dev/null
+++ b/tests/py/test_subprocess.py
@@ -0,0 +1,105 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+# Extends the subprocess module to use runtime checkers, and report stderr output.
+
+import subprocess, re, os, tempfile
+
+from subprocess import PIPE
+
+class TestProcessError(Exception):
+    def __init__(self, proc, what, output=None):
+        self.output = output
+        sep = "\n%s stderr(%s) %s\n" %("_" * 32, proc.pid, "_" * 32)
+        error = sep + proc.error + sep if proc.error else ""
+        super(TestProcessError, self).__init__("%s pid=%s exit=%s: %s%s" % (
+            proc.cmd, proc.pid, proc.returncode, what, error))
+
+class Popen(subprocess.Popen):
+    """
+    Adds TEST_EXE_PREFIX to the command and checks stderr for runtime checker output.
+    In a 'with' statement it runs check_wait() on exit from the block, or
+    check_kill() if initialized with kill_me=True
+    """
+
+    def __init__(self, *args, **kwargs):
+        """
+        Takes all args and kwargs of subprocess.Popen except stdout, stderr, universal_newlines
+        kill_me=True runs check_kill() in __exit__() instead of check_wait()
+        """
+        self.cmd = args[0]
+        self.on_exit = self.check_kill if kwargs.pop('kill_me', False) else self.check_wait
+        self.errfile = tempfile.NamedTemporaryFile(delete=False)
+        kwargs.update({'universal_newlines': True, 'stdout': PIPE, 'stderr': self.errfile})
+        args = ((os.environ.get("TEST_EXE_PREFIX", "").split() + args[0]),) + args[1:]
+        super(Popen, self).__init__(*args, **kwargs)
+
+    def check_wait(self):
+        if self.wait() or self.error:
+            raise TestProcessError(self, "check_wait")
+
+    def communicate(self, *args, **kwargs):
+        result = super(Popen, self).communicate(*args, **kwargs)
+        if self.returncode or self.error:
+            raise TestProcessError(self, "check_communicate", result[0])
+        return result
+
+    def check_kill(self):
+        """Raise if process has already exited, kill and raise if self.error is not empty"""
+        if self.poll() is None:
+            self.kill()
+            self.wait()
+            self.stdout.close()     # Doesn't get closed if killed
+            if self.error:
+                raise TestProcessError(self, "check_kill found error output")
+        else:
+            raise TestProcessError(self, "check_kill process not running")
+
+    def expect(self, pattern):
+        line = self.stdout.readline()
+        match = re.search(pattern, line)
+        if not match:
+            raise Exception("%s: can't find '%s' in '%s'" % (self.cmd, pattern, line))
+        return match
+
+    @property
+    def error(self):
+        """Return stderr as string, may only be used after process has terminated."""
+        assert(self.poll is not None)
+        if not hasattr(self, "_error"):
+            self.errfile.close() # Not auto-deleted
+            with open(self.errfile.name) as f: # Re-open to read
+                self._error = f.read().strip()
+            os.unlink(self.errfile.name)
+        return self._error
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *args):
+        self.on_exit()
+
+def check_output(*args, **kwargs):
+    return Popen(*args, **kwargs).communicate()[0]
+
+class Server(Popen):
+    """A process that prints 'listening on <port>' to stdout"""
+    def __init__(self, *args, **kwargs):
+        super(Server, self).__init__(*args, **kwargs)
+        self.port = self.expect("listening on ([0-9]+)$").group(1)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/27edd9ac/tests/valgrind.supp
----------------------------------------------------------------------
diff --git a/tests/valgrind.supp b/tests/valgrind.supp
new file mode 100644
index 0000000..3fee095
--- /dev/null
+++ b/tests/valgrind.supp
@@ -0,0 +1,151 @@
+{
+   SSL does a number of uninitialized accesses (expected) 1
+   Memcheck:Cond
+   fun:BN_bin2bn
+   obj:*
+   obj:*
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 2
+   Memcheck:Cond
+   fun:BN_num_bits_word
+   fun:BN_num_bits
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 3
+   Memcheck:Value8
+   fun:BN_num_bits_word
+   fun:BN_num_bits
+   fun:BN_mod_exp_mont_consttime
+   obj:*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 4
+   Memcheck:Value8
+   fun:BN_mod_exp_mont_consttime
+   obj:*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (FreeBSD version)
+   Memcheck:Value8
+   fun:BN_num_bits_word
+   fun:BN_num_bits
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*libcrypto.so*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (FreeBSD version)
+   Memcheck:Value8
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*libcrypto.so*
+   fun:ssl3_ctx_ctrl
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 5
+   Memcheck:Value4
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*
+   obj:*
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 6
+   Memcheck:Value4
+   fun:BN_num_bits_word
+   fun:BN_mod_exp_mont_consttime
+   fun:BN_mod_exp_mont
+   obj:*
+   obj:*
+}
+
+{
+   SSL does a number of uninitialized accesses (expected) 7
+   Memcheck:Cond
+   fun:ASN1_STRING_set
+   fun:ASN1_mbstring_ncopy
+   fun:ASN1_mbstring_copy
+}
+
+{
+   Since we can never safely uninitialize SSL, allow this
+   Memcheck:Leak
+   fun:_vgrZU_libcZdsoZa_realloc
+   fun:CRYPTO_realloc
+   fun:lh_insert
+   obj:/lib64/libcrypto.so.0.9.8e
+   fun:ERR_load_strings
+   fun:ERR_load_X509V3_strings
+   fun:ERR_load_crypto_strings
+   fun:SSL_load_error_strings
+}
+
+{
+   Since we can never safely uninitialize SSL, allow this
+   Memcheck:Leak
+   fun:_vgrZU_libcZdsoZa_malloc
+   fun:CRYPTO_malloc
+   fun:lh_new
+   fun:OBJ_NAME_init
+   fun:OBJ_NAME_add
+   fun:EVP_add_cipher
+   fun:SSL_library_init
+}
+
+{
+   Since we can never safely uninitialize SSL, allow this
+   Memcheck:Leak
+   fun:malloc
+   obj:*
+   fun:CRYPTO_malloc
+}
+
+{
+   Known memory leak in cyrus-sasl (fixed in 2.1.26)
+   Memcheck:Leak
+   fun:malloc
+   fun:*
+   fun:sasl_config_init
+   fun:sasl_server_init
+}
+
+{
+   Known bug in glibc which tries to free ipv6 related static when getaddrinfo used
+   Memcheck:Free
+   fun:free
+   fun:__libc_freeres
+   fun:_vgnU_freeres
+   fun:__run_exit_handlers
+   fun:exit
+}
+
+{
+   Benign race in pni_log_enabled
+   Helgrind:Race
+   fun:pni_log_enabled
+}
+
+{
+   NSS library poking around in its own data segment upsets helgrind
+   Helgrind:Race
+   fun:strpbrk
+   fun:_nss_files_parse_servent
+}
+
+{
+   NSS library poking around in its own text segment upsets helgrind
+   Helgrind:Race
+   fun:*
+   fun:_nss_files_getservbyname_r
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[3/6] qpid-proton git commit: PROTON-1798: [cpp] C++ broker example, remove unused shutdown code.

Posted by ac...@apache.org.
PROTON-1798: [cpp] C++ broker example, remove unused shutdown code.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/e5aac008
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/e5aac008
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/e5aac008

Branch: refs/heads/master
Commit: e5aac0083bb1cc2a6e96a361ff6031066e4dc449
Parents: c6db635
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Sep 5 13:56:46 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Fri Sep 7 11:26:25 2018 -0400

----------------------------------------------------------------------
 c/examples/example_test.py |  4 ++--
 cpp/examples/broker.cpp    | 14 ++------------
 2 files changed, 4 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e5aac008/c/examples/example_test.py
----------------------------------------------------------------------
diff --git a/c/examples/example_test.py b/c/examples/example_test.py
index 5d6322f..1834989 100644
--- a/c/examples/example_test.py
+++ b/c/examples/example_test.py
@@ -117,8 +117,8 @@ class ExampleTest(unittest.TestCase):
                 self.assertIn("secure connection:", got)
                 self.assertIn(send_expect(), got)
                 self.assertMultiLineEqual(receive_expect(), self.runex("receive", b.port))
-        except subprocess.CalledProcessError as e:
-            if e.output.startswith(b"error initializing SSL"):
+        except TestProcessError as e:
+            if e.output and e.output.startswith(b"error initializing SSL"):
                 print("Skipping %s: SSL not available" % self.id())
             else:
                 raise

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e5aac008/cpp/examples/broker.cpp
----------------------------------------------------------------------
diff --git a/cpp/examples/broker.cpp b/cpp/examples/broker.cpp
index 479ec01..d45309e 100644
--- a/cpp/examples/broker.cpp
+++ b/cpp/examples/broker.cpp
@@ -337,18 +337,8 @@ public:
     // A receiver receives messages from a publisher to a queue.
     void on_receiver_open(proton::receiver &receiver) OVERRIDE {
         std::string qname = receiver.target().address();
-        if (qname == "shutdown") {
-            std::cout << "broker shutting down" << std::endl;
-            // Sending to the special "shutdown" queue stops the broker.
-            receiver.connection().container().stop(
-                proton::error_condition("shutdown", "stop broker"));
-        } else {
-            if (qname.empty()) {
-                DOUT(std::cerr << "ODD - trying to attach to a empty address\n";);
-            }
-            Receiver* r = new Receiver(receiver);
-            queue_manager_.add(make_work(&QueueManager::findQueueReceiver, &queue_manager_, r, qname));
-        }
+        Receiver* r = new Receiver(receiver);
+        queue_manager_.add(make_work(&QueueManager::findQueueReceiver, &queue_manager_, r, qname));
     }
 
     void on_session_close(proton::session &session) OVERRIDE {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[6/6] qpid-proton git commit: PROTON-1929: [c] library prints directly to stderr/stdout

Posted by ac...@apache.org.
PROTON-1929: [c] library prints directly to stderr/stdout

Replace direct use of stdout with pn_log calls.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6c765bc6
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6c765bc6
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6c765bc6

Branch: refs/heads/master
Commit: 6c765bc66461c17b02ce740804f4d9e171f0fe24
Parents: d3c1135
Author: Alan Conway <ac...@redhat.com>
Authored: Mon Sep 10 15:54:57 2018 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Mon Sep 10 15:54:57 2018 -0400

----------------------------------------------------------------------
 c/src/core/log.c        |   1 +
 c/src/core/transport.c  |   1 +
 c/src/core/util.c       |  22 +++----
 c/src/core/util.h       |   3 +-
 c/src/sasl/cyrus_sasl.c |   4 +-
 c/src/ssl/openssl.c     |  27 ++++-----
 c/src/ssl/schannel.c    | 133 +++++++++++++++++++++----------------------
 7 files changed, 87 insertions(+), 104 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/core/log.c
----------------------------------------------------------------------
diff --git a/c/src/core/log.c b/c/src/core/log.c
index 754eed3..ed04573 100644
--- a/c/src/core/log.c
+++ b/c/src/core/log.c
@@ -51,6 +51,7 @@ void pn_log_logger(pn_logger_t new_logger) {
 void pni_vlogf_impl(const char *fmt, va_list ap) {
     vfprintf(stderr, fmt, ap);
     fprintf(stderr, "\n");
+    fflush(stderr);
 }
 
 /**@internal

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/core/transport.c
----------------------------------------------------------------------
diff --git a/c/src/core/transport.c b/c/src/core/transport.c
index 106a2c8..7dee571 100644
--- a/c/src/core/transport.c
+++ b/c/src/core/transport.c
@@ -135,6 +135,7 @@ static void pni_delivery_map_clear(pn_delivery_map_t *dm)
 static void pni_default_tracer(pn_transport_t *transport, const char *message)
 {
   fprintf(stderr, "[%p]:%s\n", (void *) transport, message);
+  fflush(stderr);
 }
 
 static ssize_t pn_io_layer_input_passthru(pn_transport_t *, unsigned int, const char *, size_t );

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/core/util.c
----------------------------------------------------------------------
diff --git a/c/src/core/util.c b/c/src/core/util.c
index a676e9f..2597d60 100644
--- a/c/src/core/util.c
+++ b/c/src/core/util.c
@@ -19,9 +19,9 @@
  *
  */
 
-#include "util.h"
-
 #include "buffer.h"
+#include "log_private.h"
+#include "util.h"
 
 #include <proton/error.h>
 #include <proton/types.h>
@@ -82,27 +82,19 @@ int pn_quote(pn_string_t *dst, const char *src, size_t size)
   }
 }
 
-void pn_fprint_data(FILE *stream, const char *bytes, size_t size)
+void pn_log_data(const char *msg, const char *bytes, size_t size)
 {
   char buf[256];
   ssize_t n = pn_quote_data(buf, 256, bytes, size);
   if (n >= 0) {
-    fputs(buf, stream);
+    pn_logf("%s: %s", msg, buf);
+  } else if (n == PN_OVERFLOW) {
+    pn_logf("%s: %s (truncated)", msg, buf);
   } else {
-    if (n == PN_OVERFLOW) {
-      fputs(buf, stream);
-      fputs("... (truncated)", stream);
-    }
-    else
-      fprintf(stderr, "pn_quote_data: %s\n", pn_code(n));
+    pn_logf("%s: cannot log data: %s", msg, pn_code(n));
   }
 }
 
-void pn_print_data(const char *bytes, size_t size)
-{
-  pn_fprint_data(stdout, bytes, size);
-}
-
 int pn_strcasecmp(const char *a, const char *b)
 {
   int diff;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/core/util.h
----------------------------------------------------------------------
diff --git a/c/src/core/util.h b/c/src/core/util.h
index 78b1c4d..559fbaa 100644
--- a/c/src/core/util.h
+++ b/c/src/core/util.h
@@ -36,8 +36,7 @@
 
 ssize_t pn_quote_data(char *dst, size_t capacity, const char *src, size_t size);
 int pn_quote(pn_string_t *dst, const char *src, size_t size);
-void pn_fprint_data(FILE *stream, const char *bytes, size_t size);
-void pn_print_data(const char *bytes, size_t size);
+void pn_log_data(const char *msg, const char *bytes, size_t size);
 bool pn_env_bool(const char *name);
 pn_timestamp_t pn_timestamp_min(pn_timestamp_t a, pn_timestamp_t b);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/sasl/cyrus_sasl.c
----------------------------------------------------------------------
diff --git a/c/src/sasl/cyrus_sasl.c b/c/src/sasl/cyrus_sasl.c
index a7387e6..30c5784 100644
--- a/c/src/sasl/cyrus_sasl.c
+++ b/c/src/sasl/cyrus_sasl.c
@@ -22,6 +22,8 @@
 #define _GNU_SOURCE
 #endif
 
+#include "core/log_private.h"
+
 #include "proton/sasl.h"
 #include "proton/sasl-plugin.h"
 #include "proton/transport.h"
@@ -130,7 +132,7 @@ static void pni_cyrus_interact(pn_transport_t *transport, sasl_interact_t *inter
       break;
     }
     default:
-      fprintf(stderr, "(%s): %s - %s\n", i->challenge, i->prompt, i->defresult);
+      pn_logf("(%s): %s - %s", i->challenge, i->prompt, i->defresult);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/ssl/openssl.c
----------------------------------------------------------------------
diff --git a/c/src/ssl/openssl.c b/c/src/ssl/openssl.c
index 2d086c7..c2b5869 100644
--- a/c/src/ssl/openssl.c
+++ b/c/src/ssl/openssl.c
@@ -20,8 +20,9 @@
  */
 
 #include "platform/platform.h"
-#include "core/util.h"
 #include "core/engine-internal.h"
+#include "core/log_private.h"
+#include "core/util.h"
 
 #include <proton/ssl.h>
 #include <proton/engine.h>
@@ -184,16 +185,13 @@ static void ssl_log_error(const char *fmt, ...)
     ssl_vlog(NULL, fmt, ap);
     va_end(ap);
   }
-
   ssl_log_flush(NULL);
 }
 
 static void ssl_log_clear_data(pn_transport_t *transport, const char *data, size_t len)
 {
   if (PN_TRACE_RAW & transport->trace) {
-    fprintf(stderr, "SSL decrypted data: \"");
-    pn_fprint_data( stderr, data, len );
-    fprintf(stderr, "\"\n");
+    pn_log_data("SSL decrypted data", data, len );
   }
 }
 
@@ -662,9 +660,6 @@ found:
   // Check if we found anything
   if (options==all_prots) return PN_ARG_ERR;
 
-  // Debug test only
-  //printf("%30s %016lx (~%016lx)\n", protocols, options, ~options&all_prots);
-
   SSL_CTX_clear_options(domain->ctx, all_prots);
   SSL_CTX_set_options(domain->ctx, options);
   return 0;
@@ -719,8 +714,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
 #endif
 
     if (!domain->has_ca_db) {
-      pn_transport_logf(NULL, "Error: cannot verify peer without a trusted CA configured.\n"
-                        "       Use pn_ssl_domain_set_trusted_ca_db()");
+      pn_transport_logf(NULL, "Error: cannot verify peer without a trusted CA configured, use pn_ssl_domain_set_trusted_ca_db()");
       return -1;
     }
 
@@ -732,8 +726,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
         return -1;
       }
       if (!domain->has_certificate) {
-        pn_transport_logf(NULL, "Error: Server cannot verify peer without configuring a certificate.\n"
-                          "       Use pn_ssl_domain_set_credentials()");
+        pn_transport_logf(NULL, "Error: Server cannot verify peer without configuring a certificate, use pn_ssl_domain_set_credentials()");
       }
 
       if (domain->trusted_CAs) free(domain->trusted_CAs);
@@ -1406,13 +1399,13 @@ int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t finger
     digest_name = "md5";
     break;
    default:
-    ssl_log_error("Unknown or unhandled hash algorithm %i \n", hash_alg);
+    ssl_log_error("Unknown or unhandled hash algorithm %i ", hash_alg);
     return PN_ERR;
 
   }
 
   if(fingerprint_length < min_required_length) {
-    ssl_log_error("Insufficient fingerprint_length %i. fingerprint_length must be %i or above for %s digest\n",
+    ssl_log_error("Insufficient fingerprint_length %i. fingerprint_length must be %i or above for %s digest",
                   fingerprint_length, min_required_length, digest_name);
     return PN_ERR;
   }
@@ -1428,7 +1421,7 @@ int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t finger
     unsigned char bytes[64]; // sha512 uses 64 octets, we will use that as the maximum.
 
     if (X509_digest(cert, digest, bytes, &len) != 1) {
-      ssl_log_error("Failed to extract X509 digest\n");
+      ssl_log_error("Failed to extract X509 digest");
       return PN_ERR;
     }
 
@@ -1442,7 +1435,7 @@ int pn_ssl_get_cert_fingerprint(pn_ssl_t *ssl0, char *fingerprint, size_t finger
     return PN_OK;
   }
   else {
-    ssl_log_error("No certificate is available yet \n");
+    ssl_log_error("No certificate is available yet ");
     return PN_ERR;
   }
 
@@ -1475,7 +1468,7 @@ const char* pn_ssl_get_remote_subject_subfield(pn_ssl_t *ssl0, pn_ssl_cert_subje
     openssl_field = NID_commonName;
     break;
    default:
-    ssl_log_error("Unknown or unhandled certificate subject subfield %i \n", field);
+    ssl_log_error("Unknown or unhandled certificate subject subfield %i", field);
     return NULL;
   }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6c765bc6/c/src/ssl/schannel.c
----------------------------------------------------------------------
diff --git a/c/src/ssl/schannel.c b/c/src/ssl/schannel.c
index b541c96..15e7d8a 100644
--- a/c/src/ssl/schannel.c
+++ b/c/src/ssl/schannel.c
@@ -32,12 +32,15 @@
  * the latter.
  */
 
-#include <proton/ssl.h>
-#include <proton/engine.h>
+#include "core/autodetect.h"
 #include "core/engine-internal.h"
-#include "platform/platform.h"
+#include "core/log_private.h"
 #include "core/util.h"
-#include "core/autodetect.h"
+
+#include "platform/platform.h"
+
+#include <proton/ssl.h>
+#include <proton/engine.h>
 
 #include <assert.h>
 
@@ -194,7 +197,7 @@ static int win_credential_load_cert(win_credential_t *cred, const char *store_na
       if (cert_count == 1) {
         found_ctx = CertDuplicateCertificateContext(tmpctx);
       } else {
-        ssl_log_error("Multiple certificates to choose from certificate store %s\n", store_name);
+        ssl_log_error("Multiple certificates to choose from certificate store %s", store_name);
         found_ctx = NULL;
         break;
       }
@@ -206,7 +209,7 @@ static int win_credential_load_cert(win_credential_t *cred, const char *store_na
     tmpctx = false;
   }
   if (!found_ctx && cert_name && cert_count == 1)
-    ssl_log_error("Could not find certificate %s in store %s\n", cert_name, store_name);
+    ssl_log_error("Could not find certificate %s in store %s", cert_name, store_name);
   cred->cert_context = found_ctx;
 
   free(fn);
@@ -366,9 +369,8 @@ static void ssl_log_error(const char *fmt, ...)
 {
   va_list ap;
   va_start(ap, fmt);
-  vfprintf(stderr, fmt, ap);
+  pn_vlogf(fmt, ap);
   va_end(ap);
-  fflush(stderr);
 }
 
 // @todo: used to avoid littering the code with calls to printf...
@@ -377,9 +379,8 @@ static void ssl_log(pn_transport_t *transport, const char *fmt, ...)
   if (PN_TRACE_DRV & transport->trace) {
     va_list ap;
     va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
+    pn_vlogf(fmt, ap);
     va_end(ap);
-    fflush(stderr);
   }
 }
 
@@ -390,25 +391,21 @@ static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
 
   if (fmt) {
     va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
+    pn_vlogf(fmt, ap);
     va_end(ap);
   }
 
   if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
                     0, status, 0, buf, sizeof(buf), 0))
-    ssl_log_error(" : %s\n", buf);
+    ssl_log_error(" : %s", buf);
   else
-    fprintf(stderr, "pn internal Windows error: %x for %x\n", GetLastError(), status);
-
-  fflush(stderr);
+    pn_logf("pn internal Windows error: %x for %x", GetLastError(), status);
 }
 
 static void ssl_log_clear_data(pn_transport_t *transport, const char *data, size_t len)
 {
   if (PN_TRACE_RAW & transport->trace) {
-    fprintf(stderr, "SSL decrypted data: \"");
-    pn_fprint_data( stderr, data, len );
-    fprintf(stderr, "\"\n");
+    pn_log_data("SSL decrypted data", data, len);
   }
 }
 
@@ -473,7 +470,7 @@ pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
     break;
 
   default:
-    ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
+    ssl_log_error("Invalid mode for pn_ssl_mode_t: %d", mode);
     free(domain);
     return NULL;
   }
@@ -568,8 +565,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
   csguard g2(&domain->cred->cslock);
 
   if (!domain->has_ca_db && (mode == PN_SSL_VERIFY_PEER || mode == PN_SSL_VERIFY_PEER_NAME)) {
-    ssl_log_error("Error: cannot verify peer without a trusted CA configured.\n"
-                  "       Use pn_ssl_domain_set_trusted_ca_db()\n");
+    ssl_log_error("Error: cannot verify peer without a trusted CA configured, use pn_ssl_domain_set_trusted_ca_db()");
     return -1;
   }
 
@@ -585,8 +581,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
         return -1;
       }
       if (!win_credential_has_certificate(domain->cred)) {
-        ssl_log_error("Error: Server cannot verify peer without configuring a certificate.\n"
-                   "       Use pn_ssl_domain_set_credentials()");
+        ssl_log_error("Error: Server cannot verify peer without configuring a certificate, use pn_ssl_domain_set_credentials()");
         return -1;
       }
       int ec = 0;
@@ -603,7 +598,7 @@ int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
     break;
 
   default:
-    ssl_log_error("Invalid peer authentication mode given.\n");
+    ssl_log_error("Invalid peer authentication mode given.");
     return -1;
   }
 
@@ -711,7 +706,7 @@ int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
 {
   if (!domain) return -1;
   if (domain->mode != PN_SSL_MODE_SERVER) {
-    ssl_log_error("Cannot permit unsecured clients - not a server.\n");
+    ssl_log_error("Cannot permit unsecured clients - not a server.");
     return -1;
   }
   domain->allow_unsecured = true;
@@ -768,7 +763,7 @@ bool pn_ssl_get_protocol_name(pn_ssl_t *ssl0, char *buffer, size_t size )
     else if ((info.dwProtocol & 0xC00))
       pni_snprintf(buffer, size, "%s", "TLSv1.2");
     else {
-      ssl_log_error("unexpected protocol %x\n", info.dwProtocol);
+      ssl_log_error("unexpected protocol %x", info.dwProtocol);
       return false;
     }
     return true;
@@ -781,7 +776,7 @@ void pn_ssl_free( pn_transport_t *transport)
 {
   pni_ssl_t *ssl = transport->ssl;
   if (!ssl) return;
-  ssl_log( transport, "SSL socket freed.\n" );
+  ssl_log( transport, "SSL socket freed." );
   // clean up Windows per TLS session data before releasing the domain count
   csguard g(&ssl->domain->cslock);
   csguard g2(&ssl->cred->cslock);
@@ -978,7 +973,7 @@ static void ssl_encrypt(pn_transport_t *transport, char *app_data, size_t count)
   ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
   ssl->network_outp = ssl->sc_outbuf;
   ssl->network_out_pending = ssl->sc_out_count;
-  ssl_log(transport, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
+  ssl_log(transport, "ssl_encrypt %d network bytes", ssl->network_out_pending);
 }
 
 // Returns true if decryption succeeded (even for empty content)
@@ -1020,7 +1015,7 @@ static bool ssl_decrypt(pn_transport_t *transport)
       return false;
 
     case SEC_I_RENEGOTIATE:
-      ssl_log_error("unexpected TLS renegotiation\n");
+      ssl_log_error("unexpected TLS renegotiation");
       // TODO.  Fall through for now.
     default:
       ssl_failed(transport, 0);
@@ -1081,7 +1076,7 @@ static void client_handshake_init(pn_transport_t *transport)
     ssl->network_out_pending = ssl->sc_out_count;
     // the token is the whole quantity to send
     ssl->network_outp = ssl->sc_outbuf;
-    ssl_log(transport, "Sending client hello %d bytes\n", ssl->network_out_pending);
+    ssl_log(transport, "Sending client hello %d bytes", ssl->network_out_pending);
   } else {
     ssl_log_error_status(status, "InitializeSecurityContext failed");
     ssl_failed(transport, 0);
@@ -1137,7 +1132,7 @@ static void client_handshake( pn_transport_t* transport) {
   case SEC_E_INCOMPLETE_MESSAGE:
     // Not enough - get more data from the server then try again.
     // Leave input buffers untouched.
-    ssl_log(transport, "client handshake: incomplete record\n");
+    ssl_log(transport, "client handshake: incomplete record");
     ssl->sc_in_incomplete = true;
     return;
 
@@ -1147,7 +1142,7 @@ static void client_handshake( pn_transport_t* transport) {
     // the token is the whole quantity to send
     ssl->network_out_pending = ssl->sc_out_count;
     ssl->network_outp = ssl->sc_outbuf;
-    ssl_log(transport, "client handshake token %d bytes\n", ssl->network_out_pending);
+    ssl_log(transport, "client handshake token %d bytes", ssl->network_out_pending);
     break;
 
   case SEC_E_OK:
@@ -1158,7 +1153,7 @@ static void client_handshake( pn_transport_t* transport) {
         // the token is the whole quantity to send
         ssl->network_out_pending = ssl->sc_out_count;
         ssl->network_outp = ssl->sc_outbuf;
-        ssl_log(transport, "client shutdown token %d bytes\n", ssl->network_out_pending);
+        ssl_log(transport, "client shutdown token %d bytes", ssl->network_out_pending);
       } else {
         ssl->state = SSL_CLOSED;
       }
@@ -1178,9 +1173,9 @@ static void client_handshake( pn_transport_t* transport) {
       HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, ssl->peer_hostname, tracing);
       if (ec) {
         if (ssl->peer_hostname)
-          ssl_log_error_status(ec, "certificate verification failed for host %s\n", ssl->peer_hostname);
+          ssl_log_error_status(ec, "certificate verification failed for host %s", ssl->peer_hostname);
         else
-          ssl_log_error_status(ec, "certificate verification failed\n");
+          ssl_log_error_status(ec, "certificate verification failed");
         ssl_failed(transport, "TLS certificate verification error");
         break;
       }
@@ -1197,7 +1192,7 @@ static void client_handshake( pn_transport_t* transport) {
                              SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
     max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
     if (max > ssl->sc_out_size) {
-      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+      ssl_log_error("Buffer size mismatch have %d, need %d", (int) ssl->sc_out_size, (int) max);
       ssl->state = SHUTTING_DOWN;
       ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
       start_ssl_shutdown(transport);
@@ -1207,13 +1202,13 @@ static void client_handshake( pn_transport_t* transport) {
 
     ssl->state = RUNNING;
     ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
-    ssl_log(transport, "client handshake successful %d max record size\n", max);
+    ssl_log(transport, "client handshake successful %d max record size", max);
     break;
 
   case SEC_I_CONTEXT_EXPIRED:
     // ended before we got going
   default:
-    ssl_log(transport, "client handshake failed %d\n", (int) status);
+    ssl_log(transport, "client handshake failed %d", (int) status);
     ssl_failed(transport, 0);
     break;
   }
@@ -1238,7 +1233,7 @@ static void server_handshake(pn_transport_t* transport)
     // waiting for more bytes.  Help out here.
     pni_protocol_type_t type = pni_sniff_header(ssl->sc_inbuf, ssl->sc_in_count);
     if (type == PNI_PROTOCOL_INSUFFICIENT) {
-      ssl_log(transport, "server handshake: incomplete record\n");
+      ssl_log(transport, "server handshake: incomplete record");
       ssl->sc_in_incomplete = true;
       return;
     } else {
@@ -1300,7 +1295,7 @@ static void server_handshake(pn_transport_t* transport)
   case SEC_E_INCOMPLETE_MESSAGE:
     // Not enough - get more data from the client then try again.
     // Leave input buffers untouched.
-    ssl_log(transport, "server handshake: incomplete record\n");
+    ssl_log(transport, "server handshake: incomplete record");
     ssl->sc_in_incomplete = true;
     return;
 
@@ -1316,7 +1311,7 @@ static void server_handshake(pn_transport_t* transport)
         // the token is the whole quantity to send
         ssl->network_out_pending = ssl->sc_out_count;
         ssl->network_outp = ssl->sc_outbuf;
-        ssl_log(transport, "server shutdown token %d bytes\n", ssl->network_out_pending);
+        ssl_log(transport, "server shutdown token %d bytes", ssl->network_out_pending);
       } else {
         ssl->state = SSL_CLOSED;
       }
@@ -1333,7 +1328,7 @@ static void server_handshake(pn_transport_t* transport)
       bool tracing = PN_TRACE_DRV & transport->trace;
       HRESULT ec = verify_peer(ssl, ssl->cred->trust_store, NULL, tracing);
       if (ec) {
-        ssl_log_error_status(ec, "certificate verification failed\n");
+        ssl_log_error_status(ec, "certificate verification failed");
         ssl_failed(transport, "certificate verification error");
         break;
       }
@@ -1343,7 +1338,7 @@ static void server_handshake(pn_transport_t* transport)
                              SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
     max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
     if (max > ssl->sc_out_size) {
-      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
+      ssl_log_error("Buffer size mismatch have %d, need %d", (int) ssl->sc_out_size, (int) max);
       ssl->state = SHUTTING_DOWN;
       ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
       start_ssl_shutdown(transport);
@@ -1356,13 +1351,13 @@ static void server_handshake(pn_transport_t* transport)
 
     ssl->state = RUNNING;
     ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
-    ssl_log(transport, "server handshake successful %d max record size\n", max);
+    ssl_log(transport, "server handshake successful %d max record size", max);
     break;
 
   case SEC_I_CONTEXT_EXPIRED:
     // ended before we got going
   default:
-    ssl_log(transport, "server handshake failed %d\n", (int) status);
+    ssl_log(transport, "server handshake failed %d", (int) status);
     ssl_failed(transport, 0);
     break;
   }
@@ -1374,7 +1369,7 @@ static void server_handshake(pn_transport_t* transport)
     // the token is the whole quantity to send
     ssl->network_out_pending = ssl->sc_out_count;
     ssl->network_outp = ssl->sc_outbuf;
-    ssl_log(transport, "server handshake token %d bytes\n", ssl->network_out_pending);
+    ssl_log(transport, "server handshake token %d bytes", ssl->network_out_pending);
   }
 
   if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0 &&
@@ -1408,7 +1403,7 @@ static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
   if (max_frame != 0) {
     if (old_capacity >= max_frame) {
       //  already big enough
-      ssl_log(transport, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
+      ssl_log(transport, "Application expecting %d bytes (> negotiated maximum frame)", new_capacity);
       ssl_failed(transport, "TLS: transport maximum frame size error");
       return false;
     }
@@ -1417,7 +1412,7 @@ static bool grow_inbuf2(pn_transport_t *transport, size_t minimum_size) {
   size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
   int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
   if (err) {
-    ssl_log(transport, "TLS memory allocation failed for %d bytes\n", max_frame);
+    ssl_log(transport, "TLS memory allocation failed for %d bytes", max_frame);
     ssl_failed(transport, "TLS memory allocation failed");
     return false;
   }
@@ -1437,7 +1432,7 @@ static void start_ssl_shutdown(pn_transport_t *transport)
   if (ssl->queued_shutdown)
     return;
   ssl->queued_shutdown = true;
-  ssl_log(transport, "Shutting down SSL connection...\n");
+  ssl_log(transport, "Shutting down SSL connection...");
 
   DWORD shutdown = SCHANNEL_SHUTDOWN;
   SecBuffer shutBuff;
@@ -1603,7 +1598,7 @@ static void read_closed(pn_transport_t *transport, unsigned int layer, ssize_t e
 static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer, const char *input_data, size_t available)
 {
   pni_ssl_t *ssl = transport->ssl;
-  ssl_log( transport, "process_input_ssl( data size=%d )\n",available );
+  ssl_log( transport, "process_input_ssl( data size=%d )",available );
   ssize_t consumed = 0;
   ssize_t forwarded = 0;
   bool new_app_input;
@@ -1680,7 +1675,7 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
             rewind_sc_inbuf(ssl);
           }
         }
-        ssl_log(transport, "Next decryption, %d left over\n", available);
+        ssl_log(transport, "Next decryption, %d left over", available);
       }
     }
 
@@ -1702,7 +1697,7 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
             forwarded += count;
             // advance() can increase app_inbytes.size if double buffered
             app_inbytes_advance(transport, count);
-            ssl_log(transport, "Application consumed %d bytes from peer\n", (int) count);
+            ssl_log(transport, "Application consumed %d bytes from peer", (int) count);
           } else if (count == 0) {
             size_t old_size = ssl->app_inbytes.size;
             app_inbytes_advance(transport, 0);
@@ -1711,13 +1706,13 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
             }
           } else {
             // count < 0
-            ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)\n",
+            ssl_log(transport, "Application layer closed its input, error=%d (discarding %d bytes)",
                  (int) count, (int)ssl->app_inbytes.size);
             app_inbytes_advance(transport, ssl->app_inbytes.size);    // discard
             read_closed(transport, layer, count);
           }
         } else {
-          ssl_log(transport, "Input closed discard %d bytes\n",
+          ssl_log(transport, "Input closed discard %d bytes",
                (int)ssl->app_inbytes.size);
           app_inbytes_advance(transport, ssl->app_inbytes.size);      // discard
         }
@@ -1737,7 +1732,7 @@ static ssize_t process_input_ssl(pn_transport_t *transport, unsigned int layer,
       }
     }
   }
-  ssl_log(transport, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
+  ssl_log(transport, "process_input_ssl() returning %d, forwarded %d", (int) consumed, (int) forwarded);
   return consumed;
 }
 
@@ -1745,7 +1740,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
 {
   pni_ssl_t *ssl = transport->ssl;
   if (!ssl) return PN_EOS;
-  ssl_log( transport, "process_output_ssl( max_len=%d )\n",max_len );
+  ssl_log( transport, "process_output_ssl( max_len=%d )",max_len );
 
   ssize_t written = 0;
   ssize_t total_app_bytes = 0;
@@ -1784,17 +1779,17 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
         if (app_bytes > 0) {
           app_outp += app_bytes;
           remaining -= app_bytes;
-          ssl_log( transport, "Gathered %d bytes from app to send to peer\n", app_bytes );
+          ssl_log( transport, "Gathered %d bytes from app to send to peer", app_bytes );
         } else {
           if (app_bytes < 0) {
-            ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)\n",
+            ssl_log(transport, "Application layer closed its output, error=%d (%d bytes pending send)",
                  (int) app_bytes, (int) ssl->network_out_pending);
             ssl->app_output_closed = app_bytes;
             if (ssl->app_input_closed)
               ssl->state = SHUTTING_DOWN;
           } else if (total_app_bytes == 0 && ssl->app_input_closed) {
             // We've drained all the App layer can provide
-            ssl_log(transport, "Application layer blocked on input, closing\n");
+            ssl_log(transport, "Application layer blocked on input, closing");
             ssl->state = SHUTTING_DOWN;
             ssl->app_output_closed = PN_ERR;
           }
@@ -1830,7 +1825,7 @@ static ssize_t process_output_ssl( pn_transport_t *transport, unsigned int layer
       transport->io_layers[layer] = &ssl_output_closed_layer;
     }
   }
-  ssl_log(transport, "process_output_ssl() returning %d\n", (int) written);
+  ssl_log(transport, "process_output_ssl() returning %d", (int) written);
   return written;
 }
 
@@ -2099,7 +2094,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
   wchar_t *nameUCS2 = 0;
 
   if (server_name && strlen(server_name) > 255) {
-    ssl_log_error("invalid server name: %s\n", server_name);
+    ssl_log_error("invalid server name: %s", server_name);
     return WSAENAMETOOLONG;
   }
 
@@ -2144,7 +2139,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
     return st;
   }
   if (chain_context->cChain < 1 || chain_context->rgpChain[0]->cElement < 1) {
-    ssl_log_error("empty chain with status %x %x\n", chain_context->TrustStatus.dwErrorStatus,
+    ssl_log_error("empty chain with status %x %x", chain_context->TrustStatus.dwErrorStatus,
                  chain_context->TrustStatus.dwInfoStatus);
     return SEC_E_CERT_UNKNOWN;
   }
@@ -2154,7 +2149,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
   PCCERT_CONTEXT trunk_cert = chain_context->rgpChain[0]->rgpElement[chain_len - 1]->pCertContext;
   if (tracing)
     // See doc for CERT_CHAIN_POLICY_STATUS for bit field error and info status values
-    ssl_log_error("status for complete chain: error bits %x info bits %x\n",
+    ssl_log_error("status for complete chain: error bits %x info bits %x",
                   chain_context->TrustStatus.dwErrorStatus, chain_context->TrustStatus.dwInfoStatus);
 
   // Supplement with checks against Proton's trusted_ca_db, custom revocation and usage.
@@ -2167,7 +2162,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
       PCCERT_CONTEXT cc = ce->pCertContext;
       if (cc->pCertInfo->dwVersion != CERT_V3) {
         if (tracing)
-          ssl_log_error("certificate chain element %d is not version 3\n", i);
+          ssl_log_error("certificate chain element %d is not version 3", i);
         error = SEC_E_CERT_WRONG_USAGE; // A fossil
         break;
       }
@@ -2192,7 +2187,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
         if (!CertNameToStr(cc->dwCertEncodingType, &cc->pCertInfo->Subject,
                            CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, name, sizeof(name)))
           strcpy(name, "[too long]");
-        ssl_log_error("element %d (name: %s)%s error bits %x info bits %x\n", i, name, is_anchor,
+        ssl_log_error("element %d (name: %s)%s error bits %x info bits %x", i, name, is_anchor,
                       ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
       }
     }
@@ -2208,9 +2203,9 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
       if (trust_anchor) {
         if (tracing) {
           if (flags & CERT_STORE_SIGNATURE_FLAG)
-            ssl_log_error("root certificate signature failure\n");
+            ssl_log_error("root certificate signature failure");
           if (flags & CERT_STORE_TIME_VALIDITY_FLAG)
-            ssl_log_error("root certificate time validity failure\n");
+            ssl_log_error("root certificate time validity failure");
         }
         if (flags) {
           CertFreeCertificateContext(trust_anchor);
@@ -2292,7 +2287,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
         if (chain_status.lChainIndex == 0 && chain_status.lElementIndex != -1) {
           int idx = chain_status.lElementIndex;
           CERT_CHAIN_ELEMENT *ce = chain_context->rgpChain[0]->rgpElement[idx];
-          ssl_log_error("  chain failure at %d error/info: %x %x\n", idx,
+          ssl_log_error("  chain failure at %d error/info: %x %x", idx,
                         ce->TrustStatus.dwErrorStatus, ce->TrustStatus.dwInfoStatus);
         }
       }
@@ -2312,7 +2307,7 @@ static HRESULT verify_peer(pni_ssl_t *ssl, HCERTSTORE root_store, const char *se
   } while (0);
 
   if (tracing && !error)
-    ssl_log_error("peer certificate authenticated\n");
+    ssl_log_error("peer certificate authenticated");
 
   // Lots to clean up.
   if (peer_cc)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org