mirror of
https://github.com/orange-cpp/omath.git
synced 2026-04-19 11:03:27 +00:00
update
This commit is contained in:
@@ -1,17 +1,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// Linux-only helper: creates an anonymous in-memory file via memfd_create.
|
// Cross-platform helper for creating binary test "files" without writing to disk where possible.
|
||||||
|
//
|
||||||
|
// Strategy:
|
||||||
|
// - Linux (non-Android, or Android API >= 30): memfd_create → /proc/self/fd/<N> (no disk I/O)
|
||||||
|
// - All other platforms: anonymous temp file via std::tmpfile(), accessed via /proc/self/fd/<N>
|
||||||
|
// on Linux, or a named temp file (cleaned up on destruction) elsewhere.
|
||||||
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// MemFdFile f = MemFdFile::create(data.data(), data.size());
|
// auto f = MemFdFile::create(myVector);
|
||||||
// // use f.path() as a std::filesystem::path
|
// ASSERT_TRUE(f.valid());
|
||||||
// // fd is automatically closed on destruction
|
// scanner.scan_for_pattern_in_file(f.path(), ...);
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <fstream>
|
||||||
|
#include <random>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/mman.h>
|
#if defined(__linux__)
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
# if defined(__ANDROID__)
|
||||||
|
# if __ANDROID_API__ >= 30
|
||||||
|
# include <sys/mman.h>
|
||||||
|
# define OMATH_TEST_USE_MEMFD 1
|
||||||
|
# endif
|
||||||
|
// Android < 30: fall through to tmpfile() path below
|
||||||
|
# else
|
||||||
|
// Desktop Linux: memfd_create available since glibc 2.27 / kernel 3.17
|
||||||
|
# include <sys/mman.h>
|
||||||
|
# define OMATH_TEST_USE_MEMFD 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
class MemFdFile
|
class MemFdFile
|
||||||
{
|
{
|
||||||
@@ -20,61 +42,115 @@ public:
|
|||||||
|
|
||||||
~MemFdFile()
|
~MemFdFile()
|
||||||
{
|
{
|
||||||
|
#if defined(OMATH_TEST_USE_MEMFD)
|
||||||
if (m_fd >= 0)
|
if (m_fd >= 0)
|
||||||
::close(m_fd);
|
::close(m_fd);
|
||||||
|
#else
|
||||||
|
if (!m_temp_path.empty())
|
||||||
|
std::filesystem::remove(m_temp_path);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MemFdFile(const MemFdFile&) = delete;
|
MemFdFile(const MemFdFile&) = delete;
|
||||||
MemFdFile& operator=(const MemFdFile&) = delete;
|
MemFdFile& operator=(const MemFdFile&) = delete;
|
||||||
|
|
||||||
MemFdFile(MemFdFile&& o) noexcept : m_fd(o.m_fd), m_path(std::move(o.m_path))
|
MemFdFile(MemFdFile&& o) noexcept
|
||||||
|
: m_path(std::move(o.m_path))
|
||||||
|
#if defined(OMATH_TEST_USE_MEMFD)
|
||||||
|
, m_fd(o.m_fd)
|
||||||
|
#else
|
||||||
|
, m_temp_path(std::move(o.m_temp_path))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
#if defined(OMATH_TEST_USE_MEMFD)
|
||||||
o.m_fd = -1;
|
o.m_fd = -1;
|
||||||
|
#else
|
||||||
|
o.m_temp_path.clear();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool valid() const { return m_fd >= 0; }
|
[[nodiscard]] bool valid() const { return !m_path.empty(); }
|
||||||
|
|
||||||
[[nodiscard]] std::filesystem::path path() const { return m_path; }
|
[[nodiscard]] const std::filesystem::path& path() const { return m_path; }
|
||||||
|
|
||||||
static MemFdFile create(const std::uint8_t* data, std::size_t size)
|
|
||||||
{
|
|
||||||
MemFdFile f;
|
|
||||||
f.m_fd = static_cast<int>(::memfd_create("test_bin", 0));
|
|
||||||
if (f.m_fd < 0)
|
|
||||||
return f;
|
|
||||||
|
|
||||||
f.m_path = std::format("/proc/self/fd/{}", f.m_fd);
|
|
||||||
|
|
||||||
const auto* ptr = reinterpret_cast<const char*>(data);
|
|
||||||
std::size_t written = 0;
|
|
||||||
while (written < size)
|
|
||||||
{
|
|
||||||
const auto n = ::write(f.m_fd, ptr + written, size - written);
|
|
||||||
if (n <= 0)
|
|
||||||
{
|
|
||||||
::close(f.m_fd);
|
|
||||||
f.m_fd = -1;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
written += static_cast<std::size_t>(n);
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MemFdFile create(const std::vector<std::uint8_t>& data)
|
static MemFdFile create(const std::vector<std::uint8_t>& data)
|
||||||
{
|
{
|
||||||
return create(data.data(), data.size());
|
return create(data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MemFdFile create(const std::uint8_t* data, std::size_t size)
|
||||||
|
{
|
||||||
|
MemFdFile f;
|
||||||
|
|
||||||
|
#if defined(OMATH_TEST_USE_MEMFD)
|
||||||
|
f.m_fd = static_cast<int>(::memfd_create("test_bin", 0));
|
||||||
|
if (f.m_fd < 0)
|
||||||
|
return f;
|
||||||
|
|
||||||
|
if (!write_all(f.m_fd, data, size))
|
||||||
|
{
|
||||||
|
::close(f.m_fd);
|
||||||
|
f.m_fd = -1;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
f.m_path = "/proc/self/fd/" + std::to_string(f.m_fd);
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Portable fallback: write to a uniquely-named temp file and delete on destruction
|
||||||
|
const auto tmp_dir = std::filesystem::temp_directory_path();
|
||||||
|
std::mt19937_64 rng(std::random_device{}());
|
||||||
|
const auto unique_name = "omath_test_" + std::to_string(rng()) + ".bin";
|
||||||
|
f.m_temp_path = (tmp_dir / unique_name).string();
|
||||||
|
f.m_path = f.m_temp_path;
|
||||||
|
|
||||||
|
std::ofstream out(f.m_temp_path, std::ios::binary | std::ios::trunc);
|
||||||
|
if (!out.is_open())
|
||||||
|
{
|
||||||
|
f.m_temp_path.clear();
|
||||||
|
f.m_path.clear();
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
out.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
|
||||||
|
if (!out)
|
||||||
|
{
|
||||||
|
out.close();
|
||||||
|
std::filesystem::remove(f.m_temp_path);
|
||||||
|
f.m_temp_path.clear();
|
||||||
|
f.m_path.clear();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
|
||||||
|
#if defined(OMATH_TEST_USE_MEMFD)
|
||||||
int m_fd = -1;
|
int m_fd = -1;
|
||||||
std::string m_path;
|
|
||||||
|
static bool write_all(int fd, const std::uint8_t* data, std::size_t size)
|
||||||
|
{
|
||||||
|
std::size_t written = 0;
|
||||||
|
while (written < size)
|
||||||
|
{
|
||||||
|
const auto n = ::write(fd, data + written, size - written);
|
||||||
|
if (n <= 0)
|
||||||
|
return false;
|
||||||
|
written += static_cast<std::size_t>(n);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::string m_temp_path;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
// Build a minimal PE binary in-memory with a single .text section.
|
// Build a minimal PE binary in-memory with a single .text section.
|
||||||
// Layout (all offsets compile-time):
|
// Layout (all offsets compile-time):
|
||||||
// 0x00: DOS header (64 B) 0x40: pad 0x80: NT sig 0x84: FileHeader (20 B)
|
// 0x00: DOS header (64 B) 0x40: pad 0x80: NT sig 0x84: FileHeader (20 B)
|
||||||
// 0x98: OptionalHeader (0xF0 B) 0x188: SectionHeader (44 B) 0x1B4: section data
|
// 0x98: OptionalHeader (0xF0 B) 0x188: SectionHeader (44 B) 0x1B4: section data
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
inline std::vector<std::uint8_t> build_minimal_pe(const std::vector<std::uint8_t>& section_bytes)
|
inline std::vector<std::uint8_t> build_minimal_pe(const std::vector<std::uint8_t>& section_bytes)
|
||||||
{
|
{
|
||||||
constexpr std::uint32_t e_lfanew = 0x80u;
|
constexpr std::uint32_t e_lfanew = 0x80u;
|
||||||
@@ -103,8 +179,8 @@ inline std::vector<std::uint8_t> build_minimal_pe(const std::vector<std::uint8_t
|
|||||||
const char name[8] = {'.','t','e','x','t',0,0,0};
|
const char name[8] = {'.','t','e','x','t',0,0,0};
|
||||||
std::memcpy(buf.data() + sh_off, name, 8);
|
std::memcpy(buf.data() + sh_off, name, 8);
|
||||||
|
|
||||||
const auto vsize = static_cast<std::uint32_t>(section_bytes.size());
|
const auto vsize = static_cast<std::uint32_t>(section_bytes.size());
|
||||||
const std::uint32_t vaddr = 0x1000u;
|
const std::uint32_t vaddr = 0x1000u;
|
||||||
const auto ptr_raw = static_cast<std::uint32_t>(data_off);
|
const auto ptr_raw = static_cast<std::uint32_t>(data_off);
|
||||||
std::memcpy(buf.data() + sh_off + 8, &vsize, 4);
|
std::memcpy(buf.data() + sh_off + 8, &vsize, 4);
|
||||||
std::memcpy(buf.data() + sh_off + 12, &vaddr, 4);
|
std::memcpy(buf.data() + sh_off + 12, &vaddr, 4);
|
||||||
|
|||||||
Reference in New Issue
Block a user