Add valgrind pass to test script. Fix valgrind errors.
diff --git a/c++/src/kj/array.c++ b/c++/src/kj/array.c++
index 53f8ed6..36d7055 100644
--- a/c++/src/kj/array.c++
+++ b/c++/src/kj/array.c++
@@ -22,6 +22,7 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "array.h"
+#include "exception.h"
namespace kj {
@@ -62,38 +63,43 @@
namespace _ { // private
+struct AutoDeleter {
+ void* ptr;
+ inline void* release() { void* result = ptr; ptr = nullptr; return result; }
+ inline AutoDeleter(void* ptr): ptr(ptr) {}
+ inline ~AutoDeleter() { operator delete(ptr); }
+};
+
void* HeapArrayDisposer::allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
void (*constructElement)(void*),
void (*destroyElement)(void*)) {
- void* result = operator new(elementSize * capacity);
+ AutoDeleter result(operator new(elementSize * capacity));
if (constructElement == nullptr) {
// Nothing to do.
} else if (destroyElement == nullptr) {
- byte* pos = reinterpret_cast<byte*>(result);
+ byte* pos = reinterpret_cast<byte*>(result.ptr);
while (elementCount > 0) {
constructElement(pos);
pos += elementSize;
--elementCount;
}
} else {
- ExceptionSafeArrayUtil guard(result, elementSize, 0, destroyElement);
+ ExceptionSafeArrayUtil guard(result.ptr, elementSize, 0, destroyElement);
guard.construct(elementCount, constructElement);
guard.release();
}
- return result;
+ return result.release();
}
void HeapArrayDisposer::disposeImpl(
void* firstElement, size_t elementSize, size_t elementCount, size_t capacity,
void (*destroyElement)(void*)) const {
// Note that capacity is ignored since operator delete() doesn't care about it.
+ AutoDeleter deleter(firstElement);
- if (destroyElement == nullptr) {
- operator delete(firstElement);
- } else {
- KJ_DEFER(operator delete(firstElement));
+ if (destroyElement != nullptr) {
ExceptionSafeArrayUtil guard(firstElement, elementSize, elementCount, destroyElement);
guard.destroyAll();
}
diff --git a/c++/src/kj/exception-test.c++ b/c++/src/kj/exception-test.c++
index 3e2df30..5d18248 100644
--- a/c++/src/kj/exception-test.c++
+++ b/c++/src/kj/exception-test.c++
@@ -95,6 +95,40 @@
#endif
}
+#if !KJ_NO_EXCEPTIONS
+TEST(Exception, ScopeSuccessFail) {
+ bool success = false;
+ bool failure = false;
+
+ {
+ KJ_ON_SCOPE_SUCCESS(success = true);
+ KJ_ON_SCOPE_FAILURE(failure = true);
+
+ EXPECT_FALSE(success);
+ EXPECT_FALSE(failure);
+ }
+
+ EXPECT_TRUE(success);
+ EXPECT_FALSE(failure);
+
+ success = false;
+ failure = false;
+
+ try {
+ KJ_ON_SCOPE_SUCCESS(success = true);
+ KJ_ON_SCOPE_FAILURE(failure = true);
+
+ EXPECT_FALSE(success);
+ EXPECT_FALSE(failure);
+
+ throw 1;
+ } catch (int) {}
+
+ EXPECT_FALSE(success);
+ EXPECT_TRUE(failure);
+}
+#endif
+
} // namespace
} // namespace _ (private)
} // namespace kj
diff --git a/c++/src/kj/exception.h b/c++/src/kj/exception.h
index b701e3d..c0c21f0 100644
--- a/c++/src/kj/exception.h
+++ b/c++/src/kj/exception.h
@@ -262,6 +262,16 @@
}
}
+#define KJ_ON_SCOPE_SUCCESS(code) \
+ ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
+ KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
+// Runs `code` if the current scope is exited normally (not due to an exception).
+
+#define KJ_ON_SCOPE_FAILURE(code) \
+ ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
+ KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
+// Runs `code` if the current scope is exited due to an exception.
+
} // namespace kj
#endif // KJ_EXCEPTION_H_
diff --git a/c++/src/kj/io.c++ b/c++/src/kj/io.c++
index 0493fe7..3dfe4cb 100644
--- a/c++/src/kj/io.c++
+++ b/c++/src/kj/io.c++
@@ -295,11 +295,11 @@
}
while (current < iov.end()) {
- ssize_t n;
+ ssize_t n = 0;
KJ_SYSCALL(n = ::writev(fd, current, iov.end() - current), fd);
KJ_ASSERT(n > 0, "writev() returned zero.");
- while (static_cast<size_t>(n) >= current->iov_len) {
+ while (n > 0 && static_cast<size_t>(n) >= current->iov_len) {
n -= current->iov_len;
++current;
}