Bug 1114703: Remove mozilla::pkix's polyfill for std::bind, r=mmc

--HG--
extra : rebase_source : 11457f210c7f7534db2e6ebe1a8328985ff6d8b0
This commit is contained in:
Brian Smith 2015-01-21 04:00:40 -08:00
parent 12229012ec
commit 2968c94831
12 changed files with 76 additions and 338 deletions

View File

@ -1,231 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This code is made available to you under your choice of the following sets
* of licensing terms:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* Copyright 2013 Mozilla Contributors
*
* Licensed 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.
*/
// Work around missing std::bind, std::ref, std::cref in older compilers. This
// implementation isn't intended to be complete; rather, it is the minimal
// implementation needed to make our use of std::bind work for compilers that
// lack both C++11 and TR1 support for these features. We cannot even assume
// that rvalue references work, which means we don't get perfect forwarding
// and thus we basically have to define a new overload for every distinct call
// signature.
//
// A positive side-effect of this code is improved debugging usability; it is
// much more convenient to step through code that uses this polyfill than it is
// to step through the many nested layers of a real std::bind implementation.
//
// Build with MOZILLA_PKIX_USE_REAL_FUNCTIONAL defined in order to use the
// compiler's definitions of these functions. This is helpful in order to
// ensure that the calling code is actually compatible with the real std::bind
// and friends.
#ifndef mozilla_pkix__bind_h
#define mozilla_pkix__bind_h
#ifdef MOZILLA_PKIX_USE_REAL_FUNCTIONAL
#include <functional>
#endif
namespace mozilla { namespace pkix {
#ifdef MOZILLA_PKIX_USE_REAL_FUNCTIONAL
using std::bind;
using std::cref;
using std::ref;
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
#else
extern class Placeholder1 { } _1;
extern class Placeholder2 { } _2;
extern class Placeholder3 { } _3;
extern class Placeholder4 { } _4;
template <typename V> V& ref(V& v) { return v; }
template <typename V> const V& cref(const V& v) { return v; }
namespace internal {
template <typename R, typename P1, typename B1>
class Bind1
{
public:
typedef R (&F)(P1&, B1&);
Bind1(F f, B1& b1) : f(f), b1(b1) { }
R operator()(P1& p1) const { return f(p1, b1); }
private:
F f;
B1& b1;
void operator=(const Bind1&) = delete;
};
template <typename R, typename P1, typename B1, typename B2>
class Bind2
{
public:
typedef R (&F)(P1&, B1&, B2&);
Bind2(F f, B1& b1, B2& b2) : f(f), b1(b1), b2(b2) { }
R operator()(P1& p1) const { return f(p1, b1, b2); }
private:
F f;
B1& b1;
B2& b2;
void operator=(const Bind2&) = delete;
};
template <typename R, typename P1, typename B1, typename B2, typename B3>
class Bind3
{
public:
typedef R (&F)(P1&, B1, B2, B3&);
Bind3(F f, B1& b1, B2& b2, B3& b3)
: f(f), b1(b1), b2(b2), b3(b3) { }
R operator()(P1& p1) const { return f(p1, b1, b2, b3); }
private:
F f;
B1& b1;
B2& b2;
B3& b3;
void operator=(const Bind3&) = delete;
};
template <typename R, typename P1, typename B1, typename B2, typename B3,
typename B4>
class Bind4
{
public:
typedef R (&F)(P1&, B1, B2, B3&, B4&);
Bind4(F f, B1& b1, B2& b2, B3& b3, B4& b4)
: f(f), b1(b1), b2(b2), b3(b3), b4(b4) { }
R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4); }
private:
F f;
B1& b1;
B2& b2;
B3& b3;
B4& b4;
void operator=(const Bind4&) = delete;
};
template <typename R, typename C1, typename P1, typename P2, typename P3,
typename P4>
class BindToMemberFunction4
{
public:
// XXX: C++ doesn't have reference-to-member function, only
// pointer-to-member function, so we can't enforce the non-nullness of f
// using the type system.
typedef R (C1::*F)(P1&, P2&, P3, P4&);
BindToMemberFunction4(F f, C1& that) : f(f), that(that) { }
R operator()(P1& p1, P2& p2, P3 p3, P4& p4) const
{
return (that.*f)(p1, p2, p3, p4);
}
private:
const F f;
C1& that;
void operator=(const BindToMemberFunction4&) = delete;
};
template <typename R, typename P1, typename B1, typename B2, typename B3,
typename B4, typename B5>
class Bind5
{
public:
typedef R (&F)(P1&, B1, B2, B3, B4, B5);
Bind5(F f, B1 b1, B2 b2, B3 b3, B4 b4, B5 b5)
: f(f), b1(b1), b2(b2), b3(b3), b4(b4), b5(b5) { }
R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4, b5); }
private:
F f;
B1 b1;
B2 b2;
B3 b3;
B4 b4;
B5 b5;
void operator=(const Bind5&) = delete;
};
} // namespace internal
template <typename R, typename P1, typename B1>
inline internal::Bind1<R, P1, B1>
bind(R (&f)(P1&, B1&), Placeholder1&, B1& b1)
{
return internal::Bind1<R, P1, B1>(f, b1);
}
template <typename R, typename P1, typename B1, typename B2>
inline internal::Bind2<R, P1, B1, B2>
bind(R (&f)(P1&, B1&, B2&), Placeholder1&, B1& b1, B2& b2)
{
return internal::Bind2<R, P1, B1, B2>(f, b1, b2);
}
template <typename R, typename P1, typename B1, typename B2, typename B3>
inline internal::Bind3<R, P1, const B1, const B2, B3>
bind(R (&f)(P1&, B1, B2, B3&), Placeholder1&, const B1& b1, const B2& b2,
B3& b3)
{
return internal::Bind3<R, P1, const B1, const B2, B3>(f, b1, b2, b3);
}
template <typename R, typename P1, typename B1, typename B2, typename B3,
typename B4>
inline internal::Bind4<R, P1, const B1, const B2, B3, B4>
bind(R (&f)(P1&, B1, B2, B3&, B4&), Placeholder1&, const B1& b1, const B2& b2,
B3& b3, B4& b4)
{
return internal::Bind4<R, P1, const B1, const B2, B3, B4>(f, b1, b2, b3, b4);
}
// XXX: C++ doesn't have reference-to-member function, only
// pointer-to-member function, so we can't enforce the non-nullness of f
// using the type system.
template <typename R, typename C1, typename P1, typename P2, typename P3,
typename P4>
inline internal::BindToMemberFunction4<R, C1, P1, P2, P3, P4>
bind(R (C1::*f)(P1&, P2&, P3, P4&), C1& that, Placeholder1&,
Placeholder2&, Placeholder3, Placeholder4&)
{
return internal::BindToMemberFunction4<R, C1, P1, P2, P3, P4>(f, that);
}
template <typename R, typename P1, typename B1, typename B2, typename B3,
typename B4, typename B5>
inline internal::Bind5<R, P1, B1, B2, B3, B4, B5&>
bind(R (&f)(P1&, B1, B2, B3, B4, B5&), Placeholder1&, B1 b1, B2 b2, B3 b3,
B4 b4, B5& b5)
{
return internal::Bind5<R, P1, B1, B2, B3, B4, B5&>(f, b1, b2, b3, b4, b5);
}
#endif
} } // namespace mozilla::pkix
#endif // mozilla_pkix__bind_h

View File

@ -1,38 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This code is made available to you under your choice of the following sets
* of licensing terms:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* Copyright 2013 Mozilla Contributors
*
* Licensed 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 "pkix/bind.h"
#ifndef MOZILLA_PKIX_USE_REAL_FUNCTIONAL
namespace mozilla { namespace pkix {
Placeholder1 _1;
Placeholder2 _2;
Placeholder3 _3;
Placeholder4 _4;
} } // namespace mozilla::pkix
#endif

View File

@ -22,7 +22,6 @@
* limitations under the License.
*/
#include "pkix/bind.h"
#include "pkixutil.h"
namespace mozilla { namespace pkix {
@ -140,9 +139,12 @@ BackCert::Init()
}
}
rv = der::OptionalExtensions(tbsCertificate, CSC | 3,
bind(&BackCert::RememberExtension, *this, _1,
_2, _3, _4));
rv = der::OptionalExtensions(
tbsCertificate, CSC | 3,
[this](Reader& extnID, const Input& extnValue, bool critical,
/*out*/ bool& understood) {
return RememberExtension(extnID, extnValue, critical, understood);
});
if (rv != Success) {
return rv;
}
@ -178,10 +180,8 @@ BackCert::Init()
return der::End(tbsCertificate);
}
// XXX: The second value is of type |const Input&| instead of type |Input| due
// to limitations in our std::bind polyfill.
Result
BackCert::RememberExtension(Reader& extnID, const Input& extnValue,
BackCert::RememberExtension(Reader& extnID, Input extnValue,
bool critical, /*out*/ bool& understood)
{
understood = false;

View File

@ -24,7 +24,6 @@
#include "pkixcheck.h"
#include "pkix/bind.h"
#include "pkixder.h"
#include "pkixutil.h"
@ -296,24 +295,6 @@ static const long UNLIMITED_PATH_LEN = -1; // must be less than zero
// BasicConstraints ::= SEQUENCE {
// cA BOOLEAN DEFAULT FALSE,
// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
static Result
DecodeBasicConstraints(Reader& input, /*out*/ bool& isCA,
/*out*/ long& pathLenConstraint)
{
if (der::OptionalBoolean(input, isCA) != Success) {
return Result::ERROR_EXTENSION_VALUE_INVALID;
}
// TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT
// be included (as per RFC 5280 section 4.2.1.9), but for compatibility
// reasons, we don't check this for now.
if (der::OptionalInteger(input, UNLIMITED_PATH_LEN, pathLenConstraint)
!= Success) {
return Result::ERROR_EXTENSION_VALUE_INVALID;
}
return Success;
}
// RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints)
Result
@ -327,9 +308,19 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
if (encodedBasicConstraints) {
Reader input(*encodedBasicConstraints);
if (der::Nested(input, der::SEQUENCE,
bind(DecodeBasicConstraints, _1, ref(isCA),
ref(pathLenConstraint))) != Success) {
Result rv = der::Nested(input, der::SEQUENCE,
[&isCA, &pathLenConstraint](Reader& r) {
Result rv = der::OptionalBoolean(r, isCA);
if (rv != Success) {
return rv;
}
// TODO(bug 985025): If isCA is false, pathLenConstraint
// MUST NOT be included (as per RFC 5280 section
// 4.2.1.9), but for compatibility reasons, we don't
// check this.
return der::OptionalInteger(r, UNLIMITED_PATH_LEN, pathLenConstraint);
});
if (rv != Success) {
return Result::ERROR_EXTENSION_VALUE_INVALID;
}
if (der::End(input) != Success) {
@ -488,10 +479,11 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
bool found = requiredEKU == KeyPurposeId::anyExtendedKeyUsage;
Reader input(*encodedExtendedKeyUsage);
if (der::NestedOf(input, der::SEQUENCE, der::OIDTag, der::EmptyAllowed::No,
bind(MatchEKU, _1, requiredEKU, endEntityOrCA,
ref(found), ref(foundOCSPSigning)))
!= Success) {
Result rv = der::NestedOf(input, der::SEQUENCE, der::OIDTag,
der::EmptyAllowed::No, [&](Reader& r) {
return MatchEKU(r, requiredEKU, endEntityOrCA, found, foundOCSPSigning);
});
if (rv != Success) {
return Result::ERROR_INADEQUATE_CERT_TYPE;
}
if (der::End(input) != Success) {

View File

@ -24,7 +24,6 @@
#include "pkixder.h"
#include "pkix/bind.h"
#include "pkixutil.h"
namespace mozilla { namespace pkix { namespace der {

View File

@ -186,14 +186,24 @@ Nested(Reader& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder)
// Foo ::= SEQUENCE {
// }
//
// using a call like this:
// using code like this:
//
// rv = NestedOf(input, SEQEUENCE, SEQUENCE, bind(_1, Foo));
// Result Foo(Reader& r) { /*...*/ }
//
// Result Foo(Reader& input) {
// }
// rv = der::NestedOf(input, der::SEQEUENCE, der::SEQUENCE, Foo);
//
// In this example, Foo will get called once for each element of foos.
// or:
//
// Result Bar(Reader& r, int value) { /*...*/ }
//
// int value = /*...*/;
//
// rv = der::NestedOf(input, der::SEQUENCE, [value](Reader& r) {
// return Bar(r, value);
// });
//
// In these examples the function will get called once for each element of
// foos.
//
template <typename Decoder>
inline Result

View File

@ -34,7 +34,6 @@
// constraints, the reference identifier is the entire encoded name constraint
// extension value.
#include "pkix/bind.h"
#include "pkixcheck.h"
#include "pkixutil.h"
@ -468,10 +467,10 @@ SearchNames(/*optional*/ const Input* subjectAltName,
// SET SIZE (1..MAX) OF AttributeTypeAndValue
Reader subjectReader(subject);
return der::NestedOf(subjectReader, der::SEQUENCE, der::SET,
der::EmptyAllowed::Yes,
bind(SearchWithinRDN, _1, referenceIDType,
referenceID, fallBackToEmailAddress,
fallBackToCommonName, ref(match)));
der::EmptyAllowed::Yes, [&](Reader& r) {
return SearchWithinRDN(r, referenceIDType, referenceID,
fallBackToEmailAddress, fallBackToCommonName, match);
});
}
// RelativeDistinguishedName ::=
@ -489,10 +488,11 @@ SearchWithinRDN(Reader& rdn,
/*in/out*/ MatchResult& match)
{
do {
Result rv = der::Nested(rdn, der::SEQUENCE,
bind(SearchWithinAVA, _1, referenceIDType,
referenceID, fallBackToEmailAddress,
fallBackToCommonName, ref(match)));
Result rv = der::Nested(rdn, der::SEQUENCE, [&](Reader& r) {
return SearchWithinAVA(r, referenceIDType, referenceID,
fallBackToEmailAddress, fallBackToCommonName,
match);
});
if (rv != Success) {
return rv;
}

View File

@ -24,7 +24,6 @@
#include <limits>
#include "pkix/bind.h"
#include "pkix/pkix.h"
#include "pkixcheck.h"
#include "pkixutil.h"
@ -298,8 +297,9 @@ VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
thisUpdate, validThrough);
Reader input(encodedResponse);
Result rv = der::Nested(input, der::SEQUENCE,
bind(OCSPResponse, _1, ref(context)));
Result rv = der::Nested(input, der::SEQUENCE, [&context](Reader& r) {
return OCSPResponse(r, context);
});
if (rv != Success) {
return MapBadDERToMalformedOCSPResponse(rv);
}
@ -358,7 +358,9 @@ OCSPResponse(Reader& input, Context& context)
}
return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
der::SEQUENCE, bind(ResponseBytes, _1, ref(context)));
der::SEQUENCE, [&context](Reader& r) {
return ResponseBytes(r, context);
});
}
// ResponseBytes ::= SEQUENCE {
@ -377,7 +379,9 @@ ResponseBytes(Reader& input, Context& context)
}
return der::Nested(input, der::OCTET_STRING, der::SEQUENCE,
bind(BasicResponse, _1, ref(context)));
[&context](Reader& r) {
return BasicResponse(r, context);
});
}
// BasicOCSPResponse ::= SEQUENCE {
@ -493,8 +497,9 @@ ResponseData(Reader& input, Context& context,
// responder will never return an empty response, and handling the case of an
// empty response makes things unnecessarily complicated.
rv = der::NestedOf(input, der::SEQUENCE, der::SEQUENCE,
der::EmptyAllowed::No,
bind(SingleResponse, _1, ref(context)));
der::EmptyAllowed::No, [&context](Reader& r) {
return SingleResponse(r, context);
});
if (rv != Success) {
return rv;
}
@ -517,8 +522,9 @@ static inline Result
SingleResponse(Reader& input, Context& context)
{
bool match = false;
Result rv = der::Nested(input, der::SEQUENCE,
bind(CertID, _1, cref(context), ref(match)));
Result rv = der::Nested(input, der::SEQUENCE, [&context, &match](Reader& r) {
return CertID(r, context, match);
});
if (rv != Success) {
return rv;
}
@ -599,8 +605,9 @@ SingleResponse(Reader& input, Context& context)
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0;
if (input.Peek(NEXT_UPDATE_TAG)) {
Time nextUpdate(Time::uninitialized);
rv = der::Nested(input, NEXT_UPDATE_TAG,
bind(der::GeneralizedTime, _1, ref(nextUpdate)));
rv = der::Nested(input, NEXT_UPDATE_TAG, [&nextUpdate](Reader& r) {
return der::GeneralizedTime(r, nextUpdate);
});
if (rv != Success) {
return rv;
}

View File

@ -140,8 +140,8 @@ private:
Input subjectAltName;
Input criticalNetscapeCertificateType;
Result RememberExtension(Reader& extnID, const Input& extnValue,
bool critical, /*out*/ bool& understood);
Result RememberExtension(Reader& extnID, Input extnValue, bool critical,
/*out*/ bool& understood);
BackCert(const BackCert&) = delete;
void operator=(const BackCert&) = delete;

View File

@ -5,7 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'lib/pkixbind.cpp',
'lib/pkixbuild.cpp',
'lib/pkixcert.cpp',
'lib/pkixcheck.cpp',

View File

@ -26,7 +26,6 @@
#include <vector>
#include <gtest/gtest.h>
#include "pkix/bind.h"
#include "pkixder.h"
using namespace mozilla::pkix;
@ -844,9 +843,10 @@ TEST_F(pkixder_input_tests, NestedOf)
std::vector<uint8_t> readValues;
ASSERT_EQ(Success,
NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
mozilla::pkix::bind(NestedOfHelper, mozilla::pkix::_1,
mozilla::pkix::ref(readValues))));
NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
[&readValues](Reader& r) {
return NestedOfHelper(r, readValues);
}));
ASSERT_EQ((size_t) 3, readValues.size());
ASSERT_EQ(0x01, readValues[0]);
ASSERT_EQ(0x02, readValues[1]);
@ -862,8 +862,9 @@ TEST_F(pkixder_input_tests, NestedOfWithTruncatedData)
std::vector<uint8_t> readValues;
ASSERT_EQ(Result::ERROR_BAD_DER,
NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
mozilla::pkix::bind(NestedOfHelper, mozilla::pkix::_1,
mozilla::pkix::ref(readValues))));
[&readValues](Reader& r) {
return NestedOfHelper(r, readValues);
}));
ASSERT_EQ((size_t) 0, readValues.size());
}

View File

@ -26,7 +26,6 @@
#include <vector>
#include <gtest/gtest.h>
#include "pkix/bind.h"
#include "pkixder.h"
#include "pkixtestutil.h"
#include "stdint.h"