From 917d9705b0eeaaaa2b6e12e3e9343fa55c4dd62d Mon Sep 17 00:00:00 2001 From: trgv Date: Mon, 29 Sep 2025 22:06:34 +0300 Subject: [PATCH 1/2] Add AGENTS.md --- AGENTS.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..c44a0073 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,68 @@ +# AGENTS.md + +Problem definition → small, safe change → change review → refactor — repeat the loop. + +## Mandatory Rules + +- Before changing anything, read the relevant files end to end, including all call/reference paths. +- Keep tasks, commits, and PRs small. +- If you make assumptions, record them in the Issue/PR/ADR. +- Never commit or log secrets; validate all inputs and encode/normalize outputs. +- Avoid premature abstraction and use intention-revealing names. +- Compare at least two options before deciding. + +## Mindset + +- Think like a senior engineer. +- Don’t jump in on guesses or rush to conclusions. +- Always evaluate multiple approaches; write one line each for pros/cons/risks, then choose the simplest solution. + +## Code & File Reference Rules + +- Read files thoroughly from start to finish (no partial reads). +- Before changing code, locate and read definitions, references, call sites, related tests, docs/config/flags. +- Do not change code without having read the entire file. +- Before modifying a symbol, run a global search to understand pre/postconditions and leave a 1–3 line impact note. + +## Required Coding Rules + +- Before coding, write a Problem 1-Pager: Context / Problem / Goal / Non-Goals / Constraints. +- Enforce limits: file ≤ 300 LOC, function ≤ 50 LOC, parameters ≤ 5, cyclomatic complexity ≤ 10. If exceeded, split/refactor. +- Prefer explicit code; no hidden “magic.” +- Follow DRY, but avoid premature abstraction. +- Isolate side effects (I/O, network, global state) at the boundary layer. +- Catch only specific exceptions and present clear user-facing messages. +- Use structured logging and do not log sensitive data (propagate request/correlation IDs when possible). +- Account for time zones and DST. + +## Testing Rules + +- New code requires new tests; bug fixes must include a regression test (write it to fail first). +- Tests must be deterministic and independent; replace external systems with fakes/contract tests. +- Include ≥1 happy path and ≥1 failure path in e2e tests. +- Proactively assess risks from concurrency/locks/retries (duplication, deadlocks, etc.). + +## Security Rules + +- Never leave secrets in code/logs/tickets. +- Validate, normalize, and encode inputs; use parameterized operations. +- Apply the Principle of Least Privilege. + +## Clean Code Rules + +- Use intention-revealing names. +- Each function should do one thing. +- Keep side effects at the boundary. +- Prefer guard clauses first. +- Symbolize constants (no hardcoding). +- Structure code as Input → Process → Return. +- Report failures with specific errors/messages. +- Make tests serve as usage examples; include boundary and failure cases. + +## Anti-Pattern Rules + +- Don’t modify code without reading the whole context. +- Don’t expose secrets. +- Don’t ignore failures or warnings. +- Don’t introduce unjustified optimization or abstraction. +- Don’t overuse broad exceptions. From 1a98bafa1819bd23b961396609fc5ccb8f7fd3c5 Mon Sep 17 00:00:00 2001 From: tumalaB Date: Mon, 29 Sep 2025 22:37:56 +0300 Subject: [PATCH 2/2] Harden GXByteArray capacity management --- development/include/GXByteArray.h | 1 + development/src/GXByteArray.cpp | 273 +++++++++++++++++------------- 2 files changed, 160 insertions(+), 114 deletions(-) diff --git a/development/include/GXByteArray.h b/development/include/GXByteArray.h index edd31caa..b06f5f93 100644 --- a/development/include/GXByteArray.h +++ b/development/include/GXByteArray.h @@ -51,6 +51,7 @@ class CGXByteArray unsigned char* m_Data; unsigned long m_Capacity; unsigned long m_Size; + int EnsureCapacity(unsigned long required); public: //Constructor. CGXByteArray(); diff --git a/development/src/GXByteArray.cpp b/development/src/GXByteArray.cpp index 61befdb8..bd4f09f8 100644 --- a/development/src/GXByteArray.cpp +++ b/development/src/GXByteArray.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "../include/errorcodes.h" #include "../include/GXByteArray.h" #include "../include/GXHelpers.h" @@ -71,24 +72,39 @@ unsigned long CGXByteArray::GetSize() void CGXByteArray::SetSize(unsigned long value) { - assert(!(value > m_Capacity)); + if (value > m_Capacity) + { + if (EnsureCapacity(value) != 0) + { + return; + } + } m_Size = value; } int CGXByteArray::IncreaseSize(unsigned long size) { - if (size > 1) + if (size == 0) { - return -1; + return (int)m_Size; } - m_Size += size; - return m_Size; + if (size > std::numeric_limits::max() - m_Size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = m_Size + size; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; + } + m_Size = required; + return (int)m_Size; } // Allocate new size for the array in bytes. int CGXByteArray::Capacity(unsigned long capacity) { - m_Capacity = capacity; if (capacity == 0) { if (m_Data != NULL) @@ -97,17 +113,18 @@ int CGXByteArray::Capacity(unsigned long capacity) m_Data = NULL; } m_Size = 0; + m_Capacity = 0; } else { unsigned char* tmp; if (m_Data == NULL) { - tmp = (unsigned char*)malloc(m_Capacity); + tmp = (unsigned char*)malloc(capacity); } else { - tmp = (unsigned char*)realloc(m_Data, m_Capacity); + tmp = (unsigned char*)realloc(m_Data, capacity); } //If not enought memory available. if (tmp == NULL) @@ -119,10 +136,37 @@ int CGXByteArray::Capacity(unsigned long capacity) { m_Size = capacity; } + m_Capacity = capacity; } return 0; } +int CGXByteArray::EnsureCapacity(unsigned long required) +{ + if (required <= m_Capacity) + { + return 0; + } + unsigned long newCapacity = m_Capacity; + if (newCapacity == 0) + { + newCapacity = VECTOR_CAPACITY; + } + if (newCapacity < VECTOR_CAPACITY) + { + newCapacity = VECTOR_CAPACITY; + } + while (newCapacity < required) + { + if (newCapacity > std::numeric_limits::max() - VECTOR_CAPACITY) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + newCapacity += VECTOR_CAPACITY; + } + return Capacity(newCapacity); +} + unsigned long CGXByteArray::Capacity() { return m_Capacity; @@ -131,13 +175,22 @@ unsigned long CGXByteArray::Capacity() // Fill buffer it with zeros. void CGXByteArray::Zero(unsigned long index, unsigned long count) { - if (index + count > m_Capacity) + if (count == 0) { - CGXByteArray::Capacity(index + count); + return; } - if (m_Size < index + count) + if (count > std::numeric_limits::max() - index) { - m_Size = index + count; + return; + } + unsigned long required = index + count; + if (EnsureCapacity(required) != 0) + { + return; + } + if (m_Size < required) + { + m_Size = required; } memset(m_Data + index, 0, count); } @@ -145,101 +198,94 @@ void CGXByteArray::Zero(unsigned long index, unsigned long count) // Push new data to the byteArray. int CGXByteArray::SetUInt8(unsigned char item) { - int ret = SetUInt8(m_Size, item); - if (ret == 0) - { - ++m_Size; - } - return ret; + return SetUInt8(m_Size, item); } int CGXByteArray::SetUInt8(unsigned long index, unsigned char item) { - if (m_Capacity == 0 || index + 1 > m_Capacity) + if (index > std::numeric_limits::max() - 1) { - m_Capacity += VECTOR_CAPACITY; - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = index + 1; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } m_Data[index] = item; + if (m_Size < required) + { + m_Size = required; + } return 0; } int CGXByteArray::SetUInt16(unsigned short item) { - int ret = SetUInt16(m_Size, item); - if (ret == 0) - { - m_Size += 2; - } - return ret; + return SetUInt16(m_Size, item); } int CGXByteArray::SetUInt16(unsigned long index, unsigned short item) { - if (m_Capacity == 0 || index + 2 > m_Capacity) + if (index > std::numeric_limits::max() - 2) { - m_Capacity += VECTOR_CAPACITY; - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = index + 2; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } m_Data[index] = (item >> 8) & 0xFF; m_Data[index + 1] = item & 0xFF; + if (m_Size < required) + { + m_Size = required; + } return 0; } int CGXByteArray::SetUInt32(unsigned long item) { - int ret = CGXByteArray::SetUInt32ByIndex(m_Size, item); - if (ret == 0) - { - m_Size += 4; - } - return ret; + return CGXByteArray::SetUInt32ByIndex(m_Size, item); } int CGXByteArray::SetUInt32ByIndex(unsigned long index, unsigned long item) { - if (m_Capacity == 0 || index + 4 > m_Capacity) + if (index > std::numeric_limits::max() - 4) { - m_Capacity += VECTOR_CAPACITY; - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = index + 4; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } m_Data[index] = (item >> 24) & 0xFF; m_Data[index + 1] = (item >> 16) & 0xFF; m_Data[index + 2] = (item >> 8) & 0xFF; m_Data[index + 3] = item & 0xFF; + if (m_Size < required) + { + m_Size = required; + } return 0; } int CGXByteArray::SetUInt64(unsigned long long item) { - if (m_Capacity == 0 || m_Size + 8 > m_Capacity) + if (8 > std::numeric_limits::max() - m_Size) { - m_Capacity += VECTOR_CAPACITY; - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = m_Size + 8; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } m_Data[m_Size] = (unsigned char)((item >> 56) & 0xFF); m_Data[m_Size + 1] = (item >> 48) & 0xFF; @@ -249,7 +295,7 @@ int CGXByteArray::SetUInt64(unsigned long long item) m_Data[m_Size + 5] = (item >> 16) & 0xFF; m_Data[m_Size + 6] = (item >> 8) & 0xFF; m_Data[m_Size + 7] = item & 0xFF; - m_Size += 8; + m_Size = required; return 0; } @@ -263,22 +309,21 @@ int CGXByteArray::SetFloat(float value) HELPER tmp; tmp.value = value; - if (m_Capacity == 0 || m_Size + 4 > m_Capacity) + if (4 > std::numeric_limits::max() - m_Size) { - m_Capacity += VECTOR_CAPACITY; - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = m_Size + 4; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } m_Data[m_Size] = tmp.b[3]; m_Data[m_Size + 1] = tmp.b[2]; m_Data[m_Size + 2] = tmp.b[1]; m_Data[m_Size + 3] = tmp.b[0]; - m_Size += 4; + m_Size = required; return 0; } @@ -292,16 +337,15 @@ int CGXByteArray::SetDouble(double value) HELPER tmp; tmp.value = value; - if (m_Capacity == 0 || m_Size + 8 > m_Capacity) + if (8 > std::numeric_limits::max() - m_Size) { - m_Capacity += VECTOR_CAPACITY; - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = m_Size + 8; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } m_Data[m_Size] = tmp.b[7]; m_Data[m_Size + 1] = tmp.b[6]; @@ -311,7 +355,7 @@ int CGXByteArray::SetDouble(double value) m_Data[m_Size + 5] = tmp.b[2]; m_Data[m_Size + 6] = tmp.b[1]; m_Data[m_Size + 7] = tmp.b[0]; - m_Size += 8; + m_Size = required; return 0; } @@ -339,27 +383,18 @@ int CGXByteArray::Set(const void* pSource, unsigned long count) { if (pSource != NULL && count != 0) { - if (m_Size + count > m_Capacity) + if (count > std::numeric_limits::max() - m_Size) { - //First time data is reserved only for the added data. - if (m_Capacity == 0) - { - m_Capacity = count; - } - else - { - m_Capacity += count + VECTOR_CAPACITY; - } - unsigned char* tmp = (unsigned char*)realloc(m_Data, m_Capacity); - //If not enought memory available. - if (tmp == NULL) - { - return DLMS_ERROR_CODE_OUTOFMEMORY; - } - m_Data = tmp; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + unsigned long required = m_Size + count; + int ret = EnsureCapacity(required); + if (ret != 0) + { + return ret; } memcpy(m_Data + m_Size, pSource, count); - m_Size += count; + m_Size = required; } return 0; } @@ -380,6 +415,7 @@ int CGXByteArray::Set( { data->m_Position += count; } + return ret; } return 0; } @@ -598,9 +634,19 @@ void CGXByteArray::ToArray(unsigned char*& value, unsigned long& count) if (value != NULL) { free(value); + value = NULL; } count = m_Size; + if (count == 0) + { + return; + } value = (unsigned char*)malloc(count); + if (value == NULL) + { + count = 0; + return; + } memcpy(value, m_Data, count); } @@ -706,9 +752,9 @@ int CGXByteArray::GetStringUnicode( { return DLMS_ERROR_CODE_INVALID_PARAMETER; } - if (m_Size != 0) + if (count != 0) { - value.append(reinterpret_cast(m_Data + index), m_Size); + value.append(reinterpret_cast(m_Data + index), count); } return 0; } @@ -722,9 +768,13 @@ int CGXByteArray::GetStringUnicode( { return DLMS_ERROR_CODE_INVALID_PARAMETER; } - if (m_Size != 0) + if (count != 0) { - value.append(reinterpret_cast(m_Data + index), m_Size); + if (count % sizeof(wchar_t) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + value.append(reinterpret_cast(m_Data + index), count / sizeof(wchar_t)); } return 0; } @@ -778,12 +828,7 @@ int CGXByteArray::FromBase64(std::string input) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } - size_t len = (input.length() * 3) / 4; size_t pos = input.find('=', 0); - if (pos > 0) - { - len -= input.length() - pos; - } std::string inChars; int b[4]; for (pos = 0; pos != input.length(); pos += 4)