stream: check for address overflows in memory_stream

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-05-27 11:55:07 +02:00
parent 406d14746f
commit 191f3bb2f9

View File

@ -1,4 +1,4 @@
/*
/*
SPDX-License-Identifier: MIT
Copyright © 2023-2025 Amebis
*/
@ -73,7 +73,8 @@ namespace stdex
constexpr fsize_t fsize_max = UINT64_MAX;
constexpr size_t iterate_count = 0x10;
constexpr size_t default_block_size = 0x10000; ///< Amount of space used by copy or reallocation increments
constexpr int default_block_pow = 16; ///< Copy or reallocation increments use 2^default_block_pow blocks
constexpr size_t default_block_size = 1 << default_block_pow; ///< Amount of space used by copy or reallocation increments
constexpr utf16_t utf16_bom = u'\ufeff'; ///< Byte-order-mark written at each UTF-16 file start
constexpr utf32_t utf32_bom = U'\ufeff'; ///< Byte-order-mark written at each UTF-32 file start
constexpr const char utf8_bom[3] = { '\xef', '\xbb', '\xbf' }; ///> UTF-8 byte-order-mark
@ -3451,7 +3452,13 @@ namespace stdex
m_state = state_t::fail;
return;
}
size_t reserved = tight ? required : ((required + required / 4 + (default_block_size - 1)) / default_block_size) * default_block_size;
size_t reserved;
if (tight)
reserved = required;
else {
reserved = stdex::add(required, required >> 2);
reserved = stdex::align_up(reserved, default_block_pow);
}
auto data = reinterpret_cast<uint8_t*>(realloc(m_data, reserved));
if (!data && reserved) _Unlikely_ {
m_state = state_t::fail;
@ -3600,7 +3607,7 @@ namespace stdex
data = 0;
return *this;
}
size_t end_offset = m_offset + sizeof(T);
size_t end_offset = stdex::add(m_offset, sizeof(T));
if (end_offset <= m_size) {
data = LE2HE(*reinterpret_cast<T*>(&m_data[m_offset]));
m_offset = end_offset;
@ -3640,7 +3647,7 @@ namespace stdex
data.clear();
return *this;
}
size_t end_offset = m_offset + sizeof(uint32_t);
size_t end_offset = stdex::add(m_offset, sizeof(uint32_t));
if (end_offset <= m_size) {
uint32_t num_chars = LE2HE(*reinterpret_cast<uint32_t*>(&m_data[m_offset]));
m_offset = end_offset;
@ -3669,7 +3676,7 @@ namespace stdex
#if SET_FILE_OP_TIMES
m_atime = m_mtime = time_point::now();
#endif
size_t end_offset = m_offset + length;
size_t end_offset = stdex::add(m_offset, length);
if (end_offset > m_reserved) {
reserve(end_offset);
if (!ok()) _Unlikely_
@ -3691,7 +3698,7 @@ namespace stdex
#if SET_FILE_OP_TIMES
m_atime = m_mtime = time_point::now();
#endif
size_t end_offset = m_offset + amount;
size_t end_offset = stdex::add(m_offset, amount);
if (end_offset > m_reserved) {
reserve(end_offset);
if (!ok()) _Unlikely_
@ -3726,7 +3733,7 @@ namespace stdex
#endif
if (CHECK_STREAM_STATE && !ok()) _Unlikely_
return *this;
size_t end_offset = m_offset + sizeof(T);
size_t end_offset = stdex::add(m_offset, sizeof(T));
if (end_offset > m_reserved) {
reserve(end_offset);
if (!ok()) _Unlikely_
@ -3767,9 +3774,9 @@ namespace stdex
size_t num_chars = stdex::strlen(data);
if (num_chars > UINT32_MAX)
throw std::invalid_argument("string too long");
size_t size_chars = num_chars * sizeof(T);
size_t size = sizeof(uint32_t) + size_chars;
size_t end_offset = m_offset + size;
size_t size_chars = stdex::mul(num_chars, sizeof(T));
size_t size = stdex::add(sizeof(uint32_t), size_chars);
size_t end_offset = stdex::add(m_offset, size);
if (end_offset > m_reserved) {
reserve(end_offset);
if (!ok()) _Unlikely_
@ -3812,9 +3819,9 @@ namespace stdex
size_t num_chars = data.size();
if (num_chars > UINT32_MAX)
throw std::invalid_argument("string too long");
size_t size_chars = num_chars * sizeof(T);
size_t size = sizeof(uint32_t) + size_chars;
size_t end_offset = m_offset + size;
size_t size_chars = stdex::mul(num_chars, sizeof(T));
size_t size = stdex::add(sizeof(uint32_t), size_chars);
size_t end_offset = stdex::add(m_offset, size);
if (end_offset > m_reserved) {
reserve(end_offset);
if (!ok()) _Unlikely_