Skip to content

Commit

Permalink
Make ranged for loops work with STACK_OF(T).
Browse files Browse the repository at this point in the history
My original plan here was to make STACK_OF(T) expand to a template so
the inner type were extractable. Unfortunately, we cannot sanely make
STACK_OF(T) expand to a different type in C and C++ even across
compilation units because UBSan sometimes explodes. This is nuts, but so
it goes.

Instead, use StackTraits to extract the STACK_OF(T) parameters and
define an iterator type.

Bug: 189
Change-Id: I64f5173b34b723ec471f7a355ff46b04f161386a
Reviewed-on: https://boringssl-review.googlesource.com/18467
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
  • Loading branch information
davidben committed Jul 26, 2017
1 parent d4e3795 commit ec78383
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 19 deletions.
85 changes: 69 additions & 16 deletions include/openssl/stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,21 +222,22 @@ struct StackTraits {};
}
}

#define BORINGSSL_DEFINE_STACK_TRAITS(name, is_const) \
extern "C++" { \
namespace bssl { \
namespace internal { \
template <> \
struct StackTraits<STACK_OF(name)> { \
using Type = name; \
static constexpr bool kIsConst = is_const; \
}; \
} \
} \
#define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) \
extern "C++" { \
namespace bssl { \
namespace internal { \
template <> \
struct StackTraits<STACK_OF(name)> { \
static constexpr bool kIsStack = true; \
using Type = type; \
static constexpr bool kIsConst = is_const; \
}; \
} \
} \
}

#else
#define BORINGSSL_DEFINE_STACK_TRAITS(name, is_const)
#define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const)
#endif

/* Stack functions must be tagged unused to support file-local stack types.
Expand Down Expand Up @@ -350,15 +351,15 @@ struct StackTraits {};

/* DEFINE_STACK_OF defines |STACK_OF(type)| to be a stack whose elements are
* |type| *. */
#define DEFINE_STACK_OF(type) \
#define DEFINE_STACK_OF(type) \
BORINGSSL_DEFINE_STACK_OF_IMPL(type, type *, const type *) \
BORINGSSL_DEFINE_STACK_TRAITS(type, false)
BORINGSSL_DEFINE_STACK_TRAITS(type, type, false)

/* DEFINE_CONST_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
* are const |type| *. */
#define DEFINE_CONST_STACK_OF(type) \
#define DEFINE_CONST_STACK_OF(type) \
BORINGSSL_DEFINE_STACK_OF_IMPL(type, const type *, const type *) \
BORINGSSL_DEFINE_STACK_TRAITS(type, true)
BORINGSSL_DEFINE_STACK_TRAITS(type, const type, true)

/* DEFINE_SPECIAL_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
* are |type|, where |type| must be a typedef for a pointer. */
Expand Down Expand Up @@ -407,10 +408,62 @@ struct DeleterImpl<
}
};

template <typename Stack>
class StackIteratorImpl {
public:
using Type = typename StackTraits<Stack>::Type;
// Iterators must be default-constructable.
StackIteratorImpl() : sk_(nullptr), idx_(0) {}
StackIteratorImpl(const Stack *sk, size_t idx) : sk_(sk), idx_(idx) {}

bool operator==(StackIteratorImpl other) const {
return sk_ == other.sk_ && idx_ == other.idx_;
}
bool operator!=(StackIteratorImpl other) const {
return !(*this == other);
}

Type *operator*() const {
return reinterpret_cast<Type *>(
sk_value(reinterpret_cast<const _STACK *>(sk_), idx_));
}

StackIteratorImpl &operator++(/* prefix */) {
idx_++;
return *this;
}

StackIteratorImpl operator++(int /* postfix */) {
StackIteratorImpl copy(*this);
++(*this);
return copy;
}

private:
const Stack *sk_;
size_t idx_;
};

template <typename Stack>
using StackIterator = typename std::enable_if<StackTraits<Stack>::kIsStack,
StackIteratorImpl<Stack>>::type;

} // namespace internal

} // namespace bssl

// Define begin() and end() for stack types so C++ range for loops work.
template <typename Stack>
static inline bssl::internal::StackIterator<Stack> begin(const Stack *sk) {
return bssl::internal::StackIterator<Stack>(sk, 0);
}

template <typename Stack>
static inline bssl::internal::StackIterator<Stack> end(const Stack *sk) {
return bssl::internal::StackIterator<Stack>(
sk, sk_num(reinterpret_cast<const _STACK *>(sk)));
}

} // extern C++
#endif

Expand Down
4 changes: 1 addition & 3 deletions ssl/ssl_cert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -721,9 +721,7 @@ int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
return CBB_flush(cbb);
}

for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i);

for (const CRYPTO_BUFFER *name : names) {
if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
!CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
CRYPTO_BUFFER_len(name))) {
Expand Down

0 comments on commit ec78383

Please sign in to comment.