mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-09-21 20:39:35 +00:00
fix(rx): reject undersized typed frames safely
This commit is contained in:
38
tests/run_host_tests.ps1
Normal file
38
tests/run_host_tests.ps1
Normal file
@ -0,0 +1,38 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$repo = Split-Path -Parent $PSScriptRoot
|
||||
$build = Join-Path $PSScriptRoot '.build'
|
||||
New-Item -ItemType Directory -Force -Path $build | Out-Null
|
||||
|
||||
$compiler = if (Test-Path -LiteralPath 'C:\MinGW\bin\g++.exe') {
|
||||
'C:\MinGW\bin\g++.exe'
|
||||
} else {
|
||||
(Get-Command g++ -ErrorAction Stop).Source
|
||||
}
|
||||
|
||||
$common = @(
|
||||
'-std=c++17', '-Wall', '-Wextra', '-Werror',
|
||||
'-Wno-unused-parameter', '-Wno-ignored-qualifiers', '-Wno-sign-compare',
|
||||
'-I', (Join-Path $PSScriptRoot 'arduino_stubs'),
|
||||
'-I', $repo
|
||||
)
|
||||
|
||||
& $compiler @common `
|
||||
(Join-Path $PSScriptRoot 'test_timing_contract.cpp') `
|
||||
(Join-Path $repo 'IR_Encoder.cpp') `
|
||||
(Join-Path $repo 'IR_config.cpp') `
|
||||
'-o' (Join-Path $build 'test_timing_contract.exe')
|
||||
if ($LASTEXITCODE -ne 0) { throw 'timing test build failed' }
|
||||
|
||||
& (Join-Path $build 'test_timing_contract.exe')
|
||||
if ($LASTEXITCODE -ne 0) { throw 'timing test failed' }
|
||||
|
||||
& $compiler @common `
|
||||
(Join-Path $PSScriptRoot 'test_packet_types.cpp') `
|
||||
(Join-Path $repo 'PacketTypes.cpp') `
|
||||
(Join-Path $repo 'IR_config.cpp') `
|
||||
'-o' (Join-Path $build 'test_packet_types.exe')
|
||||
if ($LASTEXITCODE -ne 0) { throw 'packet test build failed' }
|
||||
|
||||
& (Join-Path $build 'test_packet_types.exe')
|
||||
if ($LASTEXITCODE -ne 0) { throw 'packet test failed' }
|
||||
145
tests/test_packet_types.cpp
Normal file
145
tests/test_packet_types.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
#include "PacketTypes.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Packet>
|
||||
class ExposedPacket : public Packet
|
||||
{
|
||||
public:
|
||||
void attach(IR_FOX::PackInfo *info, uint16_t id = 0U)
|
||||
{
|
||||
this->set(info, id);
|
||||
}
|
||||
};
|
||||
|
||||
IR_FOX::PackInfo makeFrame(uint8_t *buffer, uint8_t msgType, uint8_t wireBytes)
|
||||
{
|
||||
buffer[0] = static_cast<uint8_t>((msgType << 5) | (wireBytes & IR_MASK_MSG_INFO));
|
||||
IR_FOX::PackInfo result;
|
||||
result.buffer = buffer;
|
||||
result.packSize = wireBytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Packet>
|
||||
void verifyMinimum(uint8_t msgType, uint8_t minimum)
|
||||
{
|
||||
std::array<uint8_t, irproto::kMaxWireFrameBytes> buffer{};
|
||||
ExposedPacket<Packet> packet;
|
||||
|
||||
IR_FOX::PackInfo shortFrame = makeFrame(buffer.data(), msgType, minimum - 1U);
|
||||
packet.attach(&shortFrame);
|
||||
assert(!packet.available());
|
||||
assert(!packet.availableRaw());
|
||||
|
||||
IR_FOX::PackInfo minimumFrame = makeFrame(buffer.data(), msgType, minimum);
|
||||
packet.attach(&minimumFrame);
|
||||
assert(packet.available());
|
||||
}
|
||||
|
||||
void verifyTypedMinimums()
|
||||
{
|
||||
verifyMinimum<PacketTypes::Data>(IR_MSG_DATA_ACCEPT, 7U);
|
||||
verifyMinimum<PacketTypes::Data>(IR_MSG_DATA_NOACCEPT, 7U);
|
||||
verifyMinimum<PacketTypes::DataBack>(IR_MSG_BACK, 5U);
|
||||
verifyMinimum<PacketTypes::DataBack>(IR_MSG_BACK_TO, 7U);
|
||||
verifyMinimum<PacketTypes::Accept>(IR_MSG_ACCEPT, 6U);
|
||||
verifyMinimum<PacketTypes::Request>(IR_MSG_REQUEST, 7U);
|
||||
}
|
||||
|
||||
void verifyDataAccessCannotUnderflow()
|
||||
{
|
||||
std::array<uint8_t, irproto::kMaxWireFrameBytes> buffer{};
|
||||
ExposedPacket<PacketTypes::Data> data;
|
||||
|
||||
for (uint8_t wireBytes = 0U; wireBytes < irproto::kDataFrameOverheadBytes; ++wireBytes)
|
||||
{
|
||||
IR_FOX::PackInfo malformed = makeFrame(buffer.data(), IR_MSG_DATA_ACCEPT, wireBytes);
|
||||
data.attach(&malformed);
|
||||
assert(!data.available());
|
||||
assert(data.getDataSize() == 0U);
|
||||
assert(data.getDataPrt() == nullptr);
|
||||
assert(data.getAddrTo() == 0U);
|
||||
}
|
||||
|
||||
IR_FOX::PackInfo empty = makeFrame(buffer.data(), IR_MSG_DATA_ACCEPT, 7U);
|
||||
data.attach(&empty);
|
||||
assert(data.available());
|
||||
assert(data.getDataSize() == 0U);
|
||||
assert(data.getDataPrt() == buffer.data() + 5U);
|
||||
|
||||
IR_FOX::PackInfo oneByte = makeFrame(buffer.data(), IR_MSG_DATA_ACCEPT, 8U);
|
||||
data.attach(&oneByte);
|
||||
assert(data.available());
|
||||
assert(data.getDataSize() == 1U);
|
||||
assert(data.getDataPrt() == buffer.data() + 5U);
|
||||
}
|
||||
|
||||
void verifyBackLayouts()
|
||||
{
|
||||
std::array<uint8_t, irproto::kMaxWireFrameBytes> buffer{};
|
||||
ExposedPacket<PacketTypes::DataBack> back;
|
||||
|
||||
IR_FOX::PackInfo shortBroadcast = makeFrame(buffer.data(), IR_MSG_BACK, 4U);
|
||||
back.attach(&shortBroadcast);
|
||||
assert(!back.available());
|
||||
assert(back.getDataSize() == 0U);
|
||||
assert(back.getDataPrt() == nullptr);
|
||||
|
||||
IR_FOX::PackInfo broadcast = makeFrame(buffer.data(), IR_MSG_BACK, 5U);
|
||||
back.attach(&broadcast);
|
||||
assert(back.available());
|
||||
assert(back.getDataSize() == 0U);
|
||||
assert(back.getDataPrt() == buffer.data() + 3U);
|
||||
|
||||
IR_FOX::PackInfo shortAddressed = makeFrame(buffer.data(), IR_MSG_BACK_TO, 6U);
|
||||
back.attach(&shortAddressed);
|
||||
assert(!back.available());
|
||||
assert(back.getDataSize() == 0U);
|
||||
|
||||
IR_FOX::PackInfo addressed = makeFrame(buffer.data(), IR_MSG_BACK_TO, 7U);
|
||||
back.attach(&addressed);
|
||||
assert(back.available());
|
||||
assert(back.getDataSize() == 0U);
|
||||
assert(back.getDataPrt() == buffer.data() + 5U);
|
||||
}
|
||||
|
||||
void verifyRawAndHeaderContracts()
|
||||
{
|
||||
std::array<uint8_t, irproto::kMaxWireFrameBytes> buffer{};
|
||||
ExposedPacket<PacketTypes::BasePack> raw;
|
||||
|
||||
// Raw diagnostics remain able to observe a CRC-sized frame even when its
|
||||
// declared type-specific layout is too short.
|
||||
IR_FOX::PackInfo shortTyped = makeFrame(buffer.data(), IR_MSG_DATA_ACCEPT, 3U);
|
||||
raw.attach(&shortTyped);
|
||||
assert(raw.availableRaw());
|
||||
|
||||
IR_FOX::PackInfo inconsistent = makeFrame(buffer.data(), IR_MSG_BACK, 5U);
|
||||
inconsistent.packSize = 6U;
|
||||
raw.attach(&inconsistent);
|
||||
assert(!raw.available());
|
||||
assert(!raw.availableRaw());
|
||||
|
||||
IR_FOX::PackInfo nullFrame;
|
||||
nullFrame.packSize = 31U;
|
||||
raw.attach(&nullFrame);
|
||||
assert(!raw.available());
|
||||
assert(!raw.availableRaw());
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
verifyTypedMinimums();
|
||||
verifyDataAccessCannotUnderflow();
|
||||
verifyBackLayouts();
|
||||
verifyRawAndHeaderContracts();
|
||||
std::cout << "IR packet boundary tests: OK\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user