andry81/tacklelib

View on GitHub
src/utility/memory.cpp

Summary

Maintainability
Test Coverage
#include <tacklelib/utility/memory.hpp>
#include <tacklelib/utility/string.hpp>
#include <tacklelib/utility/utility.hpp>

#include <tacklelib/tackle/file_handle.hpp>

#include <boost/scope_exit.hpp>

#if ERROR_IF_EMPTY_PP_DEF(USE_FMT_LIBRARY_FORMAT_INSTEAD_UTILITY_STRING_FORMAT)
#  include <fmt/format.h>
#endif

#include "inttypes.h"

#if defined(UTILITY_PLATFORM_WINDOWS)
#include "windows.h"
#include "psapi.h"
#elif defined(UTILITY_PLATFORM_POSIX)
#include <cstdlib>
#include <cstdio>
#include <string>
#else
#error platform is not implemented
#endif


namespace utility {

    // for details: https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
    //
    size_t get_process_memory_size(MemoryType mem_type, size_t proc_id)
    {
        switch(mem_type) {
        case MemType_VirtualMemory: {
#if defined(UTILITY_PLATFORM_WINDOWS)
            PROCESS_MEMORY_COUNTERS_EX pmc;
            HANDLE proc_handle = {};

            BOOST_SCOPE_EXIT(&proc_handle, &proc_id) {
                if (proc_id) {
                    CloseHandle(proc_handle);
                    proc_handle = HANDLE{}; // just in case
                }
            } BOOST_SCOPE_EXIT_END

            if (proc_id) {
                proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, DWORD(proc_id));
            }
            else {
                proc_handle = GetCurrentProcess();
            }
            if (VERIFY_TRUE(GetProcessMemoryInfo(proc_handle, (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc)))) {
                return pmc.PrivateUsage;
            }
#elif defined(UTILITY_PLATFORM_POSIX)
            std::string buf;
            if (proc_id) {
                buf = string_format(256, "/proc/%zu/status", proc_id);
            }
            else {
                buf = "/proc/self/status";
            }
            const tackle::generic_file_handle<char> proc_file_handle = utility::open_file(tackle::generic_path_string{ buf }, "r", utility::SharedAccess_DenyNone);

            size_t mem_size = 0;

            char tmp_buf[4096];

            while (std::fgets(tmp_buf, UTILITY_CONSTEXPR_ARRAY_SIZE(tmp_buf), proc_file_handle.get())) {
                if (!strncmp(tmp_buf, UTILITY_LITERAL_STRING_WITH_SIZE_TUPLE("VmSize:"))) {
                    mem_size = strlen(tmp_buf);
                    const char* p = tmp_buf;
                    while (*p <'0' || *p > '9') p++;
                    tmp_buf[mem_size - 3] = '\0';
                    mem_size = atoi(p);
                    break;
                }
            }

            return mem_size * 1024; // to bytes
#endif
        } break;

        case MemType_PhysicalMemory: {
            DEBUG_ASSERT_TRUE(0); // not implemented
        } break;

        default:
            DEBUG_ASSERT_TRUE(0);
        }

        return 0;
    }

    void Buffer::check_buffer_guards()
    {
        if (m_size < m_reserve) {
            /*CONSTEXPR*/ const auto & guard_sequence_str = _guard_sequence_str();
            CONSTEXPR const size_t guard_sequence_str_len = UTILITY_CONSTEXPR_ARRAY_SIZE(guard_sequence_str) - 1;

            uint8_t * buf_ptr = m_buf_ptr.get();

            {
                const size_t guard_size = m_offset;

                const size_t num_whole_chunks = guard_size / guard_sequence_str_len;
                const size_t chunks_remainder = guard_size % guard_sequence_str_len;

                for (size_t i = 0; i < num_whole_chunks; i++) {
                    if (VERIFY_FALSE(std::memcmp(&buf_ptr[i * guard_sequence_str_len], guard_sequence_str, guard_sequence_str_len))) {
                        goto _error;
                    }
                }
                if (chunks_remainder) {
                    if (std::memcmp(&buf_ptr[num_whole_chunks * guard_sequence_str_len], guard_sequence_str, chunks_remainder)) {
                        goto _error;
                    }
                }
            }

            {
                const size_t offset = m_offset + m_size;
                const size_t guard_size = m_reserve - offset;

                const size_t num_whole_chunks = guard_size / guard_sequence_str_len;
                const size_t chunks_remainder = guard_size % guard_sequence_str_len;

                for (size_t i = 0; i < num_whole_chunks; i++) {
                    if (VERIFY_FALSE(std::memcmp(&buf_ptr[offset + i * guard_sequence_str_len], guard_sequence_str, guard_sequence_str_len))) {
                        goto _error;
                    }
                }
                if (chunks_remainder) {
                    if (std::memcmp(&buf_ptr[offset + num_whole_chunks * guard_sequence_str_len], guard_sequence_str, chunks_remainder)) {
                        goto _error;
                    }
                }
            }

            return;

        _error:;
            DEBUG_BREAK_THROW(true) std::out_of_range(
#if ERROR_IF_EMPTY_PP_DEF(USE_FMT_LIBRARY_FORMAT_INSTEAD_UTILITY_STRING_FORMAT)
                fmt::format("{:s}({:d}): out of buffer write: reserve={:d} size={:d} buffer={:p}",
                    UTILITY_PP_FUNCSIG, UTILITY_PP_LINE, m_reserve, m_size, buf_ptr)
#else
                utility::string_format(256, "%s(%d): out of buffer write: reserve=%d size=%d buffer=%p",
                    UTILITY_PP_FUNCSIG, UTILITY_PP_LINE, m_reserve, m_size, buf_ptr)
#endif
            );
        }
    }

    void Buffer::_fill_buffer_guards()
    {
        if (m_size < m_reserve) {
            /*CONSTEXPR*/ const auto & guard_sequence_str = _guard_sequence_str();
            CONSTEXPR const size_t guard_sequence_str_len = UTILITY_CONSTEXPR_ARRAY_SIZE(guard_sequence_str) - 1;

            uint8_t * buf_ptr = m_buf_ptr.get();

            {
                const size_t guard_size = m_offset;

                const size_t num_whole_chunks = guard_size / guard_sequence_str_len;
                const size_t chunks_remainder = guard_size % guard_sequence_str_len;

                for (size_t i = 0; i < num_whole_chunks; i++) {
                    memcpy(&buf_ptr[i * guard_sequence_str_len], guard_sequence_str, guard_sequence_str_len);
                }
                if (chunks_remainder) {
                    memcpy(&buf_ptr[num_whole_chunks * guard_sequence_str_len], guard_sequence_str, chunks_remainder);
                }
            }

            {
                const size_t offset = m_offset + m_size;
                const size_t guard_size = m_reserve - offset;

                const size_t num_whole_chunks = guard_size / guard_sequence_str_len;
                const size_t chunks_remainder = guard_size % guard_sequence_str_len;

                for (size_t i = 0; i < num_whole_chunks; i++) {
                    memcpy(&buf_ptr[offset + i * guard_sequence_str_len], guard_sequence_str, guard_sequence_str_len);
                }
                if (chunks_remainder) {
                    memcpy(&buf_ptr[offset + num_whole_chunks * guard_sequence_str_len], guard_sequence_str, chunks_remainder);
                }
            }
        }
    }

}