Skip to content

Commit e6d97fd

Browse files
Fixes and additional tests for issue #120 (PR #121)
2 parents 678838b + d4a3b8f commit e6d97fd

File tree

12 files changed

+306
-33
lines changed

12 files changed

+306
-33
lines changed

libember/Headers/ember/ber/detail/MultiByte.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,11 @@ namespace libember { namespace ber { namespace detail
9797
util::OctetStream::value_type byte = 0;
9898
do
9999
{
100-
byte = input.front();
100+
if (input.empty())
101+
{
102+
throw std::runtime_error("Not enough data");
103+
}
104+
byte = input.front();
101105
input.consume();
102106
++byteCount;
103107
result = (result << 7) | (byte & ~0x80);
@@ -110,4 +114,3 @@ namespace libember { namespace ber { namespace detail
110114
}
111115

112116
#endif // __LIBEMBER_BER_DETAIL_MULTIBYTE_HPP
113-

libember/Headers/ember/ber/traits/Boolean.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ namespace libember { namespace ber
6868

6969
static value_type decode(util::OctetStream& input, std::size_t)
7070
{
71+
if (input.empty())
72+
{
73+
throw std::runtime_error("Not enough data");
74+
}
7175
util::OctetStream::value_type const byte = input.front();
7276
input.consume();
7377
return (byte != 0);
@@ -83,4 +87,3 @@ namespace libember { namespace ber
8387
}
8488

8589
#endif // __LIBEMBER_BER_TRAITS_BOOLEAN_HPP
86-

libember/Headers/ember/ber/traits/Integral.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ namespace libember { namespace ber
118118

119119
static value_type decode(util::OctetStream& input, std::size_t encodedLength)
120120
{
121+
if (input.size() < encodedLength)
122+
{
123+
throw std::runtime_error("Not enough data");
124+
}
121125
typedef typename meta::MakeUnsigned<value_type>::type unsigned_type;
122126
value_type value = 0;
123127
for (std::size_t index = 0; index < encodedLength; ++index)
@@ -347,4 +351,3 @@ namespace libember { namespace ber
347351
}
348352

349353
#endif // __LIBEMBER_BER_TRAITS_INTEGRAL_HPP
350-

libember/Headers/ember/ber/traits/Length.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ namespace libember { namespace ber
7474

7575
static Length<LengthType> decode(util::OctetStream& input)
7676
{
77+
if (input.empty())
78+
{
79+
throw std::runtime_error("Not enough data");
80+
}
81+
7782
underlying_type length = input.front();
7883
input.consume();
7984

@@ -86,6 +91,10 @@ namespace libember { namespace ber
8691
}
8792
else
8893
{
94+
if (input.size() < bytes)
95+
{
96+
throw std::runtime_error("Not enough data");
97+
}
8998
length = 0U;
9099
for (/* Nothing */; bytes > 0U; bytes -= 1U)
91100
{
@@ -101,4 +110,3 @@ namespace libember { namespace ber
101110
}
102111

103112
#endif // __LIBEMBER_BER_TRAITS_LENGTH_HPP
104-

libember/Headers/ember/ber/traits/ObjectIdentifier.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace libember { namespace ber
4444
std::size_t length = 0;
4545
value_type::const_iterator first = value.begin();
4646
value_type::const_iterator const last = value.end();
47-
47+
4848
for (/* Nothing */; first != last; ++first)
4949
{
5050
length += detail::getMultiByteEncodedLength(*first);
@@ -82,6 +82,7 @@ namespace libember { namespace ber
8282

8383
static value_type decode(util::OctetStream& input, std::size_t size)
8484
{
85+
// Note: Multibyte decoding already verifies validity of the given size.
8586
typedef ObjectIdentifier::value_type item_type;
8687
std::vector<item_type> items;
8788
while(size > 0)
@@ -98,4 +99,3 @@ namespace libember { namespace ber
9899
}
99100

100101
#endif // __LIBEMBER_BER_TRAITS_OBJECTIDENTIFIER_HPP
101-

libember/Headers/ember/ber/traits/Real.hpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Integral.hpp"
1616
#include "../../meta/FunctionTraits.hpp"
1717
#include "../../util/TypePun.hpp"
18+
#include "../../util/SignBit.hpp"
1819

1920
//SimianIgnore
2021

@@ -62,15 +63,22 @@ namespace libember { namespace ber
6263
// 0x42 Indicates NaN
6364
output.append(0x42);
6465
}
66+
else if (
67+
(value == static_cast<value_type>(0.0)) &&
68+
util::signbit(value))
69+
{
70+
// 0x43 Indicates -0.0
71+
output.append(0x43);
72+
}
6573
else
6674
{
6775
double const real = value;
6876
unsigned long long const bits = util::type_pun<unsigned long long>(real);
6977

7078
if (bits != 0)
7179
{
72-
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
73-
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
80+
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
81+
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
7482
mantissa |= 0x0010000000000000ULL;
7583

7684
while((mantissa & 0xFF) == 0x00)
@@ -109,8 +117,8 @@ namespace libember { namespace ber
109117

110118
if (bits != 0)
111119
{
112-
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
113-
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
120+
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
121+
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
114122
mantissa |= 0x0010000000000000ULL;
115123

116124
while((mantissa & 0xFF) == 0x00)
@@ -152,38 +160,54 @@ namespace libember { namespace ber
152160
static value_type decode(util::OctetStream& input, std::size_t encodedLength)
153161
{
154162
if (encodedLength == 0)
163+
{
155164
return static_cast<value_type>(0.0);
165+
}
166+
167+
if (encodedLength > input.size())
168+
{
169+
throw std::runtime_error("Not enough data");
170+
}
156171

157172
unsigned char const preamble = input.front();
158173
input.consume();
159174

160-
if (encodedLength == 1 && preamble == 0x40)
175+
if ((encodedLength == 1) && (preamble == 0x40))
161176
{
162177
return +std::numeric_limits<value_type>::infinity();
163178
}
164-
else if (encodedLength == 1 && preamble == 0x41)
179+
else if ((encodedLength == 1) && (preamble == 0x41))
165180
{
166181
return -std::numeric_limits<value_type>::infinity();
167182
}
168-
else if (encodedLength == 1 && preamble == 0x42)
183+
else if ((encodedLength == 1) && (preamble == 0x42))
169184
{
170185
return std::numeric_limits<value_type>::quiet_NaN();
171186
}
187+
else if ((encodedLength == 1) && (preamble == 0x43))
188+
{
189+
return static_cast<value_type>(-0.0);
190+
}
172191
else
173192
{
174193
unsigned long long bits = 0;
175194
unsigned int const sign = (preamble & 0x40);
176195
unsigned int const exponentLength = 1 + (preamble & 3);
177196
unsigned int const mantissaShift = ((preamble >> 2) & 3);
178197

198+
// Note: If (exponentLength > encodedLength - 1), the following call to decode will throw,
199+
// so there is no need to check this separately.
179200
long long exponent = ber::decode<long long>(input, exponentLength);
180201
unsigned long long mantissa = ber::decode<unsigned long long>(input, encodedLength - exponentLength - 1) << mantissaShift;
181202

182-
while((mantissa & 0x7FFFF00000000000ULL) == 0x00)
183-
mantissa <<= 8;
203+
if (mantissa != 0)
204+
{
205+
while((mantissa & 0x7FFFF00000000000ULL) == 0x00)
206+
mantissa <<= 8;
184207

185-
while((mantissa & 0x7FF0000000000000ULL) == 0x00)
186-
mantissa <<= 1;
208+
while((mantissa & 0x7FF0000000000000ULL) == 0x00)
209+
mantissa <<= 1;
210+
}
187211

188212
mantissa &= 0x0FFFFFFFFFFFFFULL;
189213
bits = (static_cast<unsigned long long>(exponent + 1023) << 52) | mantissa;
@@ -246,4 +270,3 @@ namespace libember { namespace ber
246270
//EndSimianIgnore
247271

248272
#endif // __LIBEMBER_BER_TRAITS_REAL_HPP
249-

libember/Headers/ember/ber/traits/Tag.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ namespace libember { namespace ber
6565

6666
static value_type decode(util::OctetStream& input)
6767
{
68+
if (input.empty())
69+
{
70+
throw std::runtime_error("Not enough data");
71+
}
72+
6873
util::OctetStream::value_type byte = input.front();
6974
input.consume();
7075

@@ -82,4 +87,3 @@ namespace libember { namespace ber
8287
}
8388

8489
#endif // __LIBEMBER_BER_TRAITS_TAG_HPP
85-
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
libember -- C++ 03 implementation of the Ember+ Protocol
3+
4+
Copyright (C) 2024 Lawo AG (http://www.lawo.com).
5+
Distributed under the Boost Software License, Version 1.0.
6+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7+
*/
8+
9+
#ifndef __LIBEMBER_UTIL_SIGNBIT_HPP
10+
#define __LIBEMBER_UTIL_SIGNBIT_HPP
11+
12+
#include "TypePun.hpp"
13+
14+
namespace libember { namespace util
15+
{
16+
inline bool signbit(float value)
17+
{
18+
return (type_pun<unsigned int>(value) & 0x80000000U) != 0U;
19+
}
20+
21+
inline bool signbit(double value)
22+
{
23+
return (type_pun<unsigned long long>(value) & 0x8000000000000000LLU) != 0LLU;
24+
}
25+
}
26+
}
27+
28+
#endif // __LIBEMBER_UTIL_SIGNBIT_HPP

libember/Tests/CMakeLists.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ target_link_libraries(libember-test-dynamic_encode_decode PRIVATE ember-headeron
4343
enable_warnings_on_target(libember-test-dynamic_encode_decode)
4444

4545

46+
add_executable(libember-test-decode_length_check ber/DecodeLengthCheck.cpp)
47+
set_target_properties(libember-test-decode_length_check
48+
PROPERTIES
49+
POSITION_INDEPENDENT_CODE ON
50+
VISIBILITY_INLINES_HIDDEN ON
51+
C_VISIBILITY_PRESET hidden
52+
CXX_VISIBILITY_PRESET hidden
53+
C_EXTENSIONS OFF
54+
CXX_EXTENSIONS OFF
55+
)
56+
target_link_libraries(libember-test-decode_length_check PRIVATE ember-headeronly)
57+
enable_warnings_on_target(libember-test-decode_length_check)
58+
59+
4660
add_executable(libember-test-glow_value glow/GlowValue.cpp)
4761
set_target_properties(libember-test-glow_value
4862
PROPERTIES
@@ -69,7 +83,25 @@ if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
6983
set_target_properties(libember-test-streambuffer PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
7084
set_target_properties(libember-test-static_encode_decode PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
7185
set_target_properties(libember-test-dynamic_encode_decode PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
86+
set_target_properties(libember-test-decode_length_check PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
7287
set_target_properties(libember-test-glow_value PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
7388
endif()
7489
endif()
7590

91+
92+
include(CTest)
93+
94+
add_test(NAME length-negative_zero COMMAND libember-test-decode_length_check negative_zero)
95+
add_test(NAME length-encoded_length COMMAND libember-test-decode_length_check encoded_length)
96+
add_test(NAME length-exponent_length COMMAND libember-test-decode_length_check exponent_length)
97+
add_test(NAME length-zero_mantissa COMMAND libember-test-decode_length_check zero_mantissa)
98+
add_test(NAME length-preamble_length_not_one COMMAND libember-test-decode_length_check preamble_length_not_one)
99+
add_test(NAME length-integral COMMAND libember-test-decode_length_check integral)
100+
add_test(NAME length-boolean COMMAND libember-test-decode_length_check boolean)
101+
add_test(NAME length-length_first_byte COMMAND libember-test-decode_length_check length_first_byte)
102+
add_test(NAME length-length_second_byte COMMAND libember-test-decode_length_check length_second_byte)
103+
add_test(NAME length-object_identifier_empty COMMAND libember-test-decode_length_check object_identifier_empty)
104+
add_test(NAME length-object_identifier_too_short COMMAND libember-test-decode_length_check object_identifier_too_short)
105+
add_test(NAME length-tag COMMAND libember-test-decode_length_check tag)
106+
add_test(NAME length-tag_multibyte COMMAND libember-test-decode_length_check tag_multibyte)
107+
add_test(NAME length-tag_multibyte_too_short COMMAND libember-test-decode_length_check tag_multibyte_too_short)

0 commit comments

Comments
 (0)