catch2/include/internal/catch_message.cpp
Billy Robert O'Neal III b1dcdc5032 Fix invalid isspace call detected by PREfast
D:\vcpkg\toolsrc\include\catch2\catch.hpp(11285): warning C6330: 'char' passed as _Param_(1) when 'unsigned char' is required in call to 'isspace'.
D:\vcpkg\toolsrc\include\catch2\catch.hpp(11288): warning C6330: 'char' passed as _Param_(1) when 'unsigned char' is required in call to 'isspace'.

ISO/IEC 9899:2011:
"7.4 Character handling <ctype.h>"/1
[...] In all cases the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of the macro
EOF. If the argument has any other value, the behavior is undefined.

This means if isspace was passed a character like ñ it could corrupt
memory without the static_cast to treat it as a positive value after
integral promotion (and C libraries commonly use the int index supplied
as a key into a table which result in out of bounds access if the
resulting int is negative).
2020-05-12 14:07:22 +02:00

143 lines
4.7 KiB
C++

/*
* Created by Phil Nash on 1/2/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#include "catch_message.h"
#include "catch_interfaces_capture.h"
#include "catch_uncaught_exceptions.h"
#include "catch_enforce.h"
#include <cassert>
#include <stack>
namespace Catch {
MessageInfo::MessageInfo( StringRef const& _macroName,
SourceLineInfo const& _lineInfo,
ResultWas::OfType _type )
: macroName( _macroName ),
lineInfo( _lineInfo ),
type( _type ),
sequence( ++globalCount )
{}
bool MessageInfo::operator==( MessageInfo const& other ) const {
return sequence == other.sequence;
}
bool MessageInfo::operator<( MessageInfo const& other ) const {
return sequence < other.sequence;
}
// This may need protecting if threading support is added
unsigned int MessageInfo::globalCount = 0;
////////////////////////////////////////////////////////////////////////////
Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
SourceLineInfo const& lineInfo,
ResultWas::OfType type )
:m_info(macroName, lineInfo, type) {}
////////////////////////////////////////////////////////////////////////////
ScopedMessage::ScopedMessage( MessageBuilder const& builder )
: m_info( builder.m_info ), m_moved()
{
m_info.message = builder.m_stream.str();
getResultCapture().pushScopedMessage( m_info );
}
ScopedMessage::ScopedMessage( ScopedMessage&& old )
: m_info( old.m_info ), m_moved()
{
old.m_moved = true;
}
ScopedMessage::~ScopedMessage() {
if ( !uncaught_exceptions() && !m_moved ){
getResultCapture().popScopedMessage(m_info);
}
}
Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
auto trimmed = [&] (size_t start, size_t end) {
while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
++start;
}
while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
--end;
}
return names.substr(start, end - start + 1);
};
auto skipq = [&] (size_t start, char quote) {
for (auto i = start + 1; i < names.size() ; ++i) {
if (names[i] == quote)
return i;
if (names[i] == '\\')
++i;
}
CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
};
size_t start = 0;
std::stack<char> openings;
for (size_t pos = 0; pos < names.size(); ++pos) {
char c = names[pos];
switch (c) {
case '[':
case '{':
case '(':
// It is basically impossible to disambiguate between
// comparison and start of template args in this context
// case '<':
openings.push(c);
break;
case ']':
case '}':
case ')':
// case '>':
openings.pop();
break;
case '"':
case '\'':
pos = skipq(pos, c);
break;
case ',':
if (start != pos && openings.empty()) {
m_messages.emplace_back(macroName, lineInfo, resultType);
m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
m_messages.back().message += " := ";
start = pos;
}
}
}
assert(openings.empty() && "Mismatched openings");
m_messages.emplace_back(macroName, lineInfo, resultType);
m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
m_messages.back().message += " := ";
}
Capturer::~Capturer() {
if ( !uncaught_exceptions() ){
assert( m_captured == m_messages.size() );
for( size_t i = 0; i < m_captured; ++i )
m_resultCapture.popScopedMessage( m_messages[i] );
}
}
void Capturer::captureValue( size_t index, std::string const& value ) {
assert( index < m_messages.size() );
m_messages[index].message += value;
m_resultCapture.pushScopedMessage( m_messages[index] );
m_captured++;
}
} // end namespace Catch