Harden binary stream overlapping writes
This commit is contained in:
@@ -91,7 +91,7 @@ Known local toolchain state:
|
|||||||
`pp_paint`, `pp_document`, `pp_renderer_api`, `pp_renderer_gl`,
|
`pp_paint`, `pp_document`, `pp_renderer_api`, `pp_renderer_gl`,
|
||||||
`pp_paint_renderer`,
|
`pp_paint_renderer`,
|
||||||
`pp_ui_core`, `pano_cli`, and their current headless test binaries,
|
`pp_ui_core`, `pano_cli`, and their current headless test binaries,
|
||||||
including foundation event/logging/task queue coverage, PNG metadata and
|
including foundation binary-stream/event/logging/task queue coverage, PNG metadata and
|
||||||
decode, PPI header/layout, settings document, document
|
decode, PPI header/layout, settings document, document
|
||||||
snapshot/per-layer-frame/move/duration/face-pixel/PPI export coverage,
|
snapshot/per-layer-frame/move/duration/face-pixel/PPI export coverage,
|
||||||
snapshot-embedded face-payload rejection, paint brush/final-blend/
|
snapshot-embedded face-payload rejection, paint brush/final-blend/
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ Gate:
|
|||||||
Goal: split libraries while keeping current app behavior.
|
Goal: split libraries while keeping current app behavior.
|
||||||
|
|
||||||
Status: started. `pp_foundation` exists with binary stream utilities and
|
Status: started. `pp_foundation` exists with binary stream utilities and
|
||||||
boundary/overread tests. It also owns strict decimal `uint32` parsing used by
|
boundary/overread/overlapping-write tests. It also owns strict decimal `uint32` parsing used by
|
||||||
`pano_cli`, with rejection tests for empty, signed, mixed, and overflowing
|
`pano_cli`, with rejection tests for empty, signed, mixed, and overflowing
|
||||||
input. A synchronous event dispatcher, structured logging facade, bounded FIFO
|
input. A synchronous event dispatcher, structured logging facade, bounded FIFO
|
||||||
task queue, and deterministic `TraceRecorder` now record
|
task queue, and deterministic `TraceRecorder` now record
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
#include "foundation/binary_stream.h"
|
#include "foundation/binary_stream.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace pp::foundation {
|
namespace pp::foundation {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] bool overlaps_backing_storage(
|
||||||
|
const std::vector<std::byte>& backing,
|
||||||
|
std::span<const std::byte> bytes) noexcept
|
||||||
|
{
|
||||||
|
if (backing.empty() || bytes.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto backing_begin = reinterpret_cast<std::uintptr_t>(backing.data());
|
||||||
|
const auto backing_end = backing_begin + backing.size();
|
||||||
|
const auto bytes_begin = reinterpret_cast<std::uintptr_t>(bytes.data());
|
||||||
|
const auto bytes_end = bytes_begin + bytes.size();
|
||||||
|
return bytes_begin < backing_end && backing_begin < bytes_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ByteReader::ByteReader(std::span<const std::byte> bytes) noexcept
|
ByteReader::ByteReader(std::span<const std::byte> bytes) noexcept
|
||||||
: bytes_(bytes)
|
: bytes_(bytes)
|
||||||
{
|
{
|
||||||
@@ -135,6 +156,12 @@ Status ByteWriter::write_bytes(std::span<const std::byte> bytes)
|
|||||||
return Status::invalid_argument("writer has no backing storage");
|
return Status::invalid_argument("writer has no backing storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (overlaps_backing_storage(*bytes_, bytes)) {
|
||||||
|
const std::vector<std::byte> copy(bytes.begin(), bytes.end());
|
||||||
|
bytes_->insert(bytes_->end(), copy.begin(), copy.end());
|
||||||
|
return Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
bytes_->insert(bytes_->end(), bytes.begin(), bytes.end());
|
bytes_->insert(bytes_->end(), bytes.begin(), bytes.end());
|
||||||
return Status::success();
|
return Status::success();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,26 @@ void boundary_reads_are_consistent(pp::tests::Harness& h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void appends_overlapping_source_bytes_deterministically(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
std::vector<std::byte> bytes {
|
||||||
|
std::byte { 0x10 },
|
||||||
|
std::byte { 0x20 },
|
||||||
|
std::byte { 0x30 },
|
||||||
|
};
|
||||||
|
ByteWriter writer(bytes);
|
||||||
|
|
||||||
|
const auto status = writer.write_bytes(std::span<const std::byte>(bytes.data() + 1, 2));
|
||||||
|
|
||||||
|
PP_EXPECT(h, status.ok());
|
||||||
|
PP_EXPECT(h, writer.size() == 5U);
|
||||||
|
PP_EXPECT(h, bytes[0] == std::byte { 0x10 });
|
||||||
|
PP_EXPECT(h, bytes[1] == std::byte { 0x20 });
|
||||||
|
PP_EXPECT(h, bytes[2] == std::byte { 0x30 });
|
||||||
|
PP_EXPECT(h, bytes[3] == std::byte { 0x20 });
|
||||||
|
PP_EXPECT(h, bytes[4] == std::byte { 0x30 });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@@ -96,5 +116,6 @@ int main()
|
|||||||
harness.run("rejects_overread_without_moving_cursor", rejects_overread_without_moving_cursor);
|
harness.run("rejects_overread_without_moving_cursor", rejects_overread_without_moving_cursor);
|
||||||
harness.run("rejects_out_of_range_seek", rejects_out_of_range_seek);
|
harness.run("rejects_out_of_range_seek", rejects_out_of_range_seek);
|
||||||
harness.run("boundary_reads_are_consistent", boundary_reads_are_consistent);
|
harness.run("boundary_reads_are_consistent", boundary_reads_are_consistent);
|
||||||
|
harness.run("appends_overlapping_source_bytes_deterministically", appends_overlapping_source_bytes_deterministically);
|
||||||
return harness.finish();
|
return harness.finish();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user