You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2018/07/13 22:06:47 UTC

[trafficserver] branch master updated: Add generic "guard" class (PostScript) for exception and early function return safety.

This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 77fb66b  Add generic "guard" class (PostScript) for exception and early function return safety.
77fb66b is described below

commit 77fb66b114fd18defc9a0d161992de72c7ef30af
Author: Walter Karas <wk...@oath.com>
AuthorDate: Thu Jul 12 10:46:53 2018 -0500

    Add generic "guard" class (PostScript) for exception and early function return safety.
---
 lib/ts/Makefile.am                   |  4 +-
 lib/ts/PostScript.h                  | 68 +++++++++++++++++++++++++++++++
 lib/ts/unit-tests/test_PostScript.cc | 77 ++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+), 1 deletion(-)

diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
index e0bebb8..4b9d0be 100644
--- a/lib/ts/Makefile.am
+++ b/lib/ts/Makefile.am
@@ -20,7 +20,7 @@ include $(top_srcdir)/build/tidy.mk
 
 library_includedir=$(includedir)/ts
 
-library_include_HEADERS = apidefs.h TextView.h
+library_include_HEADERS = apidefs.h TextView.h PostScript.h
 
 noinst_PROGRAMS = mkdfa CompileParseRules
 check_PROGRAMS = test_tsutil test_arena test_atomic test_freelist test_geometry test_List test_Map test_Vec test_X509HostnameValidator test_tslib
@@ -75,6 +75,7 @@ libtsutil_la_SOURCES = \
 	EventNotify.h \
 	fastlz.c \
 	fastlz.h \
+	PostScript.h \
 	Hash.cc \
 	HashFNV.cc \
 	HashFNV.h \
@@ -268,6 +269,7 @@ test_tslib_SOURCES = \
 	unit-tests/unit_test_main.cc \
 	unit-tests/test_BufferWriter.cc \
 	unit-tests/test_BufferWriterFormat.cc \
+	unit-tests/test_PostScript.cc \
 	unit-tests/test_ink_inet.cc \
 	unit-tests/test_IntrusiveDList.cc \
 	unit-tests/test_IntrusivePtr.cc \
diff --git a/lib/ts/PostScript.h b/lib/ts/PostScript.h
new file mode 100644
index 0000000..af91471
--- /dev/null
+++ b/lib/ts/PostScript.h
@@ -0,0 +1,68 @@
+/** @file
+
+   Generic "guard" class templates.  The destructor calls a function object with arbitrary parameters.  This utility is
+   available in both the core and plugins.
+
+   @section license License
+
+   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.
+ */
+
+#pragma once
+
+#include <tuple>
+
+namespace ts
+{
+// The destructor of this class calls the function object passed to its constructor, with the given arguments.
+// For example:
+//   ts::PostScript g(TSHandleMLocRelease, bufp, parent, hdr);
+//
+// The release() member will prevent the call to the function upon destruction.
+//
+// Helpful in avoiding errors due to exception throws or error function return points, like the one that caused
+// Heartbleed.
+//
+template <typename Callable, typename... Args> class PostScript
+{
+public:
+  PostScript(Callable f, Args &&... args) : _f(f), _argsTuple(args...) {}
+
+  ~PostScript()
+  {
+    if (_armed) {
+      std::apply(_f, _argsTuple);
+    }
+  }
+
+  void
+  release()
+  {
+    _armed = false;
+  }
+
+  // No copying or moving.
+  PostScript(const PostScript &) = delete;
+  PostScript &operator=(const PostScript &) = delete;
+
+private:
+  bool _armed = true;
+  Callable _f;
+  std::tuple<Args...> _argsTuple;
+};
+
+} // end namespace ts
diff --git a/lib/ts/unit-tests/test_PostScript.cc b/lib/ts/unit-tests/test_PostScript.cc
new file mode 100644
index 0000000..1f95fec
--- /dev/null
+++ b/lib/ts/unit-tests/test_PostScript.cc
@@ -0,0 +1,77 @@
+/** @file
+
+    Unit tests for PostScript.h.
+
+    @section license License
+
+    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.
+ */
+
+#include "catch.hpp"
+#include <ts/PostScript.h>
+
+namespace
+{
+int f1Called;
+int f2Called;
+int f3Called;
+
+void
+f1(int a, double b, int c)
+{
+  ++f1Called;
+
+  REQUIRE(a == 1);
+  REQUIRE(b == 2.0);
+  REQUIRE(c == 3);
+}
+
+void
+f2(double a)
+{
+  ++f2Called;
+}
+
+void
+f3(int a, double b)
+{
+  ++f3Called;
+
+  REQUIRE(a == 5);
+  REQUIRE(b == 6.0);
+}
+
+} // namespace
+
+TEST_CASE("PostScript", "[PSC]")
+{
+  int lambdaCalled = 0;
+
+  {
+    ts::PostScript g1(f1, 1, 2.0, 3);
+    ts::PostScript g2(f2, 4);
+    ts::PostScript g3(f3, 5, 6.0);
+    ts::PostScript g4([&]() -> void { ++lambdaCalled; });
+
+    g2.release();
+  }
+
+  REQUIRE(f1Called == 1);
+  REQUIRE(f2Called == 0);
+  REQUIRE(f3Called == 1);
+  REQUIRE(lambdaCalled == 1);
+}