aboutsummaryrefslogtreecommitdiffstats
path: root/include/GFModuleMemory.h
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2026-09-19 11:57:16 +0200
committersaturneric <[email protected]>2026-09-19 11:57:16 +0200
commitcf2eebe9eea1cad1d12dd789fea13d511a63b4b0 (patch)
treee25c9cf4f21a4c0d11d7b4be3888bd60b6fed52b /include/GFModuleMemory.h
parentfeat(modules): package modules as signed gfmodule files (diff)
downloadmodules-cf2eebe9eea1cad1d12dd789fea13d511a63b4b0.tar.gz
modules-cf2eebe9eea1cad1d12dd789fea13d511a63b4b0.zip
refactor(module): centralize module headers and identity
- split common utilities into focused logging, event, i18n, memory, and conversion headers - add GFModule.h as the unified module include - derive bootstrap identity and translation context from generated metadata - replace parameterized bootstrap macros with GF_MODULE_BOOTSTRAP() - retain deprecated compatibility headers and allocation helper names - remove the obsolete GFModuleDeclare.h interface - correct non-debug logging macros to use their intended levels
Diffstat (limited to 'include/GFModuleMemory.h')
-rw-r--r--include/GFModuleMemory.h213
1 files changed, 213 insertions, 0 deletions
diff --git a/include/GFModuleMemory.h b/include/GFModuleMemory.h
new file mode 100644
index 0000000..07e1584
--- /dev/null
+++ b/include/GFModuleMemory.h
@@ -0,0 +1,213 @@
+/**
+ * Copyright (C) 2021-2024 Saturneric <[email protected]>
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * All the source code of GpgFrontend was modified and released by
+ * Saturneric <[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#pragma once
+
+#include <GFSDKBasic.h>
+
+#include <QByteArray>
+#include <QSharedPointer>
+#include <QString>
+#include <cstring>
+#include <memory>
+#include <new>
+
+/**
+ * @file GFModuleMemory.h
+ * @brief Who frees what, and the helpers that make it obvious.
+ *
+ * ## The rule, in one place
+ *
+ * **SDK arguments are borrowed.** Pass a pointer straight through --
+ * `s.toUtf8().constData()` for a QString -- and keep owning it. Do *not*
+ * pre-allocate one to hand over: nothing on the other side will free it. That
+ * is what the old `DUP()`/`QDUP()` at call sites was for, and why doing it now
+ * simply leaks.
+ *
+ * The one exception is a struct rather than an argument: the few aggregates a
+ * module builds and hands over whole -- `GFModuleEvent`, `GFModuleEventParam`,
+ * `GFModuleMetaData`, `GFCommandExecuteContext` -- still transfer, so their
+ * `char*` members are still allocated with GFModuleStrDup.
+ *
+ * **SDK return values are owned.** Reclaim them, which is what the `U...`
+ * family below is for.
+ */
+
+/// Allocate a copy of @p v that a transferring struct will own.
+#define DUP(v) GFModuleStrDup(v)
+
+/// The same, from the wiping allocator, for a value that is a secret.
+#define SECDUP(v) GFModuleSecStrDup(v)
+
+/// Take ownership of an SDK string and return it as a QString.
+#define UDUP(v) UnStrDup(v)
+
+/// The same, releasing it back to the wiping allocator.
+#define USECDUP(v) UnSecStrDup(v)
+
+/// Take ownership of a sized SDK buffer and return its exact octets.
+#define UDUPN(v, n) UnBytesDup(v, n)
+
+/// Takes ownership of a sized SDK buffer and returns its octets verbatim.
+///
+/// The QString forms below decode UTF-8 and stop at the first NUL, which is
+/// right for identifiers and error strings and wrong for message data: a MIME
+/// entity may be 8bit or binary, and a signature covers exact octets. Anything
+/// that crosses the crypto boundary must use this and the matching @c *N SDK
+/// entry points instead.
+inline auto UnBytesDup(const char* s, size_t size) -> QByteArray {
+ if (s == nullptr) return {};
+ QByteArray bytes(s, static_cast<qsizetype>(size));
+ GFFreeMemory(static_cast<void*>(const_cast<char*>(s)));
+ return bytes;
+}
+
+inline auto UnStrDup(const char* s) -> QString {
+ auto q_s = QString::fromUtf8(s == nullptr ? "" : s);
+ if (s != nullptr) GFFreeMemory(static_cast<void*>(const_cast<char*>(s)));
+ return q_s;
+}
+
+inline auto UnSecStrDup(const char* s) -> QString {
+ auto q_s = QString::fromUtf8(s == nullptr ? "" : s);
+ if (s != nullptr) GFSecFreeMemory(static_cast<void*>(const_cast<char*>(s)));
+ return q_s;
+}
+
+inline auto QStrDup(const QString& str) -> char* { return DUP(str.toUtf8()); }
+
+inline auto QSecStrDup(const QString& str) -> char* {
+ return SECDUP(str.toUtf8());
+}
+
+/// Copies @p b into an SDK buffer, NUL-terminated one past the end.
+///
+/// The terminator is not optional politeness: the buffer is handed to the
+/// host, and a caller that treats it as a C string would otherwise read past
+/// the allocation. @p b .size() stays authoritative for the byte count.
+inline auto AllocBufferAndCopy(const QByteArray& b) -> char* {
+ auto* p = static_cast<char*>(GFAllocateMemory(sizeof(char) * (b.size() + 1)));
+ if (p == nullptr) return nullptr;
+ memcpy(p, b.constData(), b.size());
+ p[b.size()] = '\0';
+ return p;
+}
+
+template <typename T>
+class PointerConverter {
+ public:
+ explicit PointerConverter(void* ptr) : ptr_(ptr) {}
+
+ auto AsType() const -> T* { return static_cast<T*>(ptr_); }
+
+ private:
+ void* ptr_;
+};
+
+/**
+ * @brief Construct a T in SDK-allocated memory, freed through the SDK.
+ *
+ * NAMING. These four used to be called `Secure...`, which said the wrong
+ * thing: they allocate from the ORDINARY SDK arena (GFAllocateMemory), not the
+ * wiping one (GFSecAllocateMemory). The old names had a comment saying so,
+ * which is the weakest possible place to put it -- a name is read every time
+ * and a comment once. For anything that must actually be erased, use the
+ * secure entry points explicitly or a GFBuf handle.
+ */
+template <typename T, typename... Args>
+auto SdkCreateSharedObject(Args&&... args) -> std::shared_ptr<T> {
+ void* mem = GFAllocateMemory(sizeof(T));
+ if (!mem) throw std::bad_alloc();
+
+ try {
+ T* obj = new (mem) T(std::forward<Args>(args)...);
+ return std::shared_ptr<T>(obj, [](T* ptr) {
+ ptr->~T();
+ GFFreeMemory(ptr);
+ });
+ } catch (...) {
+ GFFreeMemory(mem);
+ throw;
+ }
+}
+
+template <typename T, typename... Args>
+auto SdkCreateQSharedObject(Args&&... args) -> QSharedPointer<T> {
+ void* mem = GFAllocateMemory(sizeof(T));
+ if (!mem) throw std::bad_alloc();
+
+ try {
+ T* obj = new (mem) T(std::forward<Args>(args)...);
+ return QSharedPointer<T>(obj, [](T* ptr) {
+ ptr->~T();
+ GFFreeMemory(ptr);
+ });
+ } catch (...) {
+ GFFreeMemory(mem);
+ throw;
+ }
+}
+
+/// Allocate @p size bytes from the ordinary SDK arena, typed.
+template <typename T>
+auto SdkMallocAsType(std::size_t size) -> T* {
+ return PointerConverter<T>(GFAllocateMemory(size)).AsType();
+}
+
+/// Resize an SDK allocation, typed.
+template <typename T>
+auto SdkReallocAsType(T* ptr, std::size_t size) -> T* {
+ return PointerConverter<T>(GFReallocateMemory(ptr, size)).AsType();
+}
+
+// Deprecated spellings, kept for one cycle so a module can be ported without
+// being rewritten. They allocate from the ordinary arena, exactly as the new
+// names say and the old ones did not.
+template <typename T, typename... Args>
+[[deprecated("renamed to SdkCreateSharedObject: it is not a secure allocation")]]
+auto SecureCreateSharedObject(Args&&... args) -> std::shared_ptr<T> {
+ return SdkCreateSharedObject<T>(std::forward<Args>(args)...);
+}
+
+template <typename T, typename... Args>
+[[deprecated("renamed to SdkCreateQSharedObject: it is not a secure allocation")]]
+auto SecureCreateQSharedObject(Args&&... args) -> QSharedPointer<T> {
+ return SdkCreateQSharedObject<T>(std::forward<Args>(args)...);
+}
+
+template <typename T>
+[[deprecated("renamed to SdkMallocAsType: it is not a secure allocation")]]
+auto SecureMallocAsType(std::size_t size) -> T* {
+ return SdkMallocAsType<T>(size);
+}
+
+template <typename T>
+[[deprecated("renamed to SdkReallocAsType: it is not a secure allocation")]]
+auto SecureReallocAsType(T* ptr, std::size_t size) -> T* {
+ return SdkReallocAsType<T>(ptr, size);
+}