base: Add size and buffer macros for struct pldm_msg
Give library users a supported way to allocate pldm_msg buffers on the
stack.
A demonstration conversion is done in tests/oem/ibm/host.cpp.
Change-Id: I71158bd6b062c6e6522dc4a4cdcb089a139cd841
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54e1195..529746d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,10 @@
5. pdr: Add pldm_pdr_remove_fru_record_set_by_rsi()
6. pldm_entity_association_tree_copy_root_check()
+7. base: Add size and buffer macros for struct pldm_msg
+
+ Together these macros reduce the need for use of reinterpret_cast<>() in C++.
+
### Changed
1. dsp: bios_table: Null check for pldm_bios_table_iter_is_end()
diff --git a/include/libpldm/base.h b/include/libpldm/base.h
index 2f64849..0904803 100644
--- a/include/libpldm/base.h
+++ b/include/libpldm/base.h
@@ -9,6 +9,7 @@
#include <libpldm/pldm_types.h>
#include <asm/byteorder.h>
+#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -173,6 +174,47 @@
uint8_t payload[1]; //!< &payload[0] is the beginning of the payload
} __attribute__((packed));
+/** @brief Determine the underlying object size for a @struct pldm_msg
+ *
+ * @pre @p size must be a constant expression
+ *
+ * @note Providing an expression for @p size that is not an integer constant
+ * expression will force a compilation failure.
+ *
+ * @param size The desired size of the @struct pldm_msg payload
+ */
+#define PLDM_MSG_SIZE(size) \
+ (sizeof(char[(__builtin_constant_p(size)) ? 1 : -1])) * \
+ (sizeof(struct pldm_msg) - \
+ sizeof(((struct pldm_msg *)NULL)->payload) + (size))
+
+/** @brief Stack-allocate a buffer to hold a @struct pldm_msg
+ *
+ * Allocate an appropriately aligned array named @p name of type unsigned char
+ * with the necessary length to hold a payload of the requested size.
+ *
+ * @param name - The variable name used to define the buffer
+ * @param size - The desired payload length for the intended @struct pldm_msg
+ */
+#define PLDM_MSG_BUFFER(name, size) \
+ alignas(struct pldm_msg) unsigned char(name)[PLDM_MSG_SIZE(size)]
+
+/** @brief Create a pointer to a stack-allocated @struct pldm_msg
+ *
+ * Define a pointer named @p name of type @struct pldm_msg to an object on the
+ * stack of appropriate alignment and length to hold a @struct pldm_msg with a
+ * payload of @p size.
+ *
+ * @param name - The variable name for pointer
+ * @param size - The desired payload length for the underlying @struct pldm_msg
+ * buffer
+ */
+#ifdef __cplusplus
+#define PLDM_MSG_DEFINE_P(name, size) \
+ PLDM_MSG_BUFFER(name##_buf, size); \
+ auto *(name) = new (name##_buf) pldm_msg
+#endif
+
/**
* @brief Compare the headers from two PLDM messages to determine if the latter
* is a message representing a response to the former, where the former must be
diff --git a/tests/oem/ibm/host.cpp b/tests/oem/ibm/host.cpp
index 86c9577..628c123 100644
--- a/tests/oem/ibm/host.cpp
+++ b/tests/oem/ibm/host.cpp
@@ -5,19 +5,18 @@
#include <array>
#include <cstdint>
#include <cstring>
+#include <new>
#include <vector>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
-constexpr auto hdrSize = sizeof(pldm_msg_hdr);
-
TEST(GetAlertStatus, testGoodEncodeRequest)
{
- std::array<uint8_t, hdrSize + PLDM_GET_ALERT_STATUS_REQ_BYTES> requestMsg{};
+ PLDM_MSG_DEFINE_P(request, PLDM_GET_ALERT_STATUS_REQ_BYTES);
uint8_t versionId = 0x0;
- auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
auto rc = encode_get_alert_status_req(0, versionId, request,
PLDM_GET_ALERT_STATUS_REQ_BYTES);
EXPECT_EQ(rc, PLDM_SUCCESS);
@@ -26,9 +25,7 @@
TEST(GetAlertStatus, testBadEncodeRequest)
{
- std::array<uint8_t, hdrSize + PLDM_GET_ALERT_STATUS_REQ_BYTES> requestMsg{};
-
- auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ PLDM_MSG_DEFINE_P(request, PLDM_GET_ALERT_STATUS_REQ_BYTES);
auto rc = encode_get_alert_status_req(0, 0x0, request,
PLDM_GET_ALERT_STATUS_REQ_BYTES + 1);
EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
@@ -39,22 +36,19 @@
uint8_t completionCode = PLDM_SUCCESS;
uint32_t rack_entry = 0xff000030;
uint32_t pri_cec_node = 0x00008030;
- std::array<uint8_t, hdrSize + PLDM_GET_ALERT_STATUS_RESP_BYTES>
- responseMsg{};
+
+ PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES);
+ auto* resp = new (response->payload) pldm_get_alert_status_resp;
+ resp->completion_code = completionCode;
+ resp->rack_entry = htole32(rack_entry);
+ resp->pri_cec_node = htole32(pri_cec_node);
uint8_t retCompletionCode = 0;
uint32_t retRack_entry = 0;
uint32_t retPri_cec_node = 0;
- auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
- struct pldm_get_alert_status_resp* resp =
- reinterpret_cast<struct pldm_get_alert_status_resp*>(response->payload);
- resp->completion_code = completionCode;
- resp->rack_entry = htole32(rack_entry);
- resp->pri_cec_node = htole32(pri_cec_node);
-
auto rc = decode_get_alert_status_resp(
- response, responseMsg.size() - hdrSize, &retCompletionCode,
+ response, PLDM_GET_ALERT_STATUS_RESP_BYTES, &retCompletionCode,
&retRack_entry, &retPri_cec_node);
EXPECT_EQ(rc, PLDM_SUCCESS);
EXPECT_EQ(retCompletionCode, completionCode);
@@ -70,47 +64,38 @@
uint8_t completionCode = PLDM_SUCCESS;
uint32_t rack_entry = 0xff000030;
uint32_t pri_cec_node = 0x00008030;
- std::array<uint8_t, hdrSize + PLDM_GET_ALERT_STATUS_RESP_BYTES>
- responseMsg{};
+
+ PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES);
+ auto* resp = new (response->payload) pldm_get_alert_status_resp;
+ resp->completion_code = completionCode;
+ resp->rack_entry = htole32(rack_entry);
+ resp->pri_cec_node = htole32(pri_cec_node);
uint8_t retCompletionCode = 0;
uint32_t retRack_entry = 0;
uint32_t retPri_cec_node = 0;
- auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
- struct pldm_get_alert_status_resp* resp =
- reinterpret_cast<struct pldm_get_alert_status_resp*>(response->payload);
- resp->completion_code = completionCode;
- resp->rack_entry = htole32(rack_entry);
- resp->pri_cec_node = htole32(pri_cec_node);
-
rc = decode_get_alert_status_resp(
- response, responseMsg.size() - hdrSize + 1, &retCompletionCode,
+ response, PLDM_GET_ALERT_STATUS_RESP_BYTES + 1, &retCompletionCode,
&retRack_entry, &retPri_cec_node);
EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
}
TEST(GetAlertStatus, testGoodEncodeResponse)
{
- uint8_t completionCode = 0;
uint32_t rack_entry = 0xff000030;
uint32_t pri_cec_node = 0x00008030;
- std::vector<uint8_t> responseMsg(hdrSize +
- PLDM_GET_ALERT_STATUS_RESP_BYTES);
- auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES);
- auto rc =
- encode_get_alert_status_resp(0, PLDM_SUCCESS, rack_entry, pri_cec_node,
- response, responseMsg.size() - hdrSize);
+ auto rc = encode_get_alert_status_resp(0, PLDM_SUCCESS, rack_entry,
+ pri_cec_node, response,
+ PLDM_GET_ALERT_STATUS_RESP_BYTES);
- EXPECT_EQ(rc, PLDM_SUCCESS);
- struct pldm_get_alert_status_resp* resp =
- reinterpret_cast<struct pldm_get_alert_status_resp*>(response->payload);
-
- EXPECT_EQ(completionCode, resp->completion_code);
- EXPECT_EQ(rack_entry, le32toh(resp->rack_entry));
- EXPECT_EQ(pri_cec_node, le32toh(resp->pri_cec_node));
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+ EXPECT_THAT(response_buf, testing::ElementsAreArray(
+ {0x00, 0x3f, 0xf0, 0x00, 0x30, 0x00, 0x00,
+ 0xff, 0x30, 0x80, 0x00, 0x00}));
}
TEST(GetAlertStatus, testBadEncodeResponse)
@@ -118,29 +103,24 @@
uint32_t rack_entry = 0xff000030;
uint32_t pri_cec_node = 0x00008030;
- std::vector<uint8_t> responseMsg(hdrSize +
- PLDM_GET_ALERT_STATUS_RESP_BYTES);
- auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+ PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES);
- auto rc = encode_get_alert_status_resp(0, PLDM_SUCCESS, rack_entry,
- pri_cec_node, response,
- responseMsg.size() - hdrSize + 1);
+ auto rc = encode_get_alert_status_resp(
+ 0, PLDM_SUCCESS, rack_entry, pri_cec_node, response,
+ PLDM_GET_ALERT_STATUS_RESP_BYTES + 1);
EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
}
TEST(GetAlertStatus, testGoodDecodeRequest)
{
- std::array<uint8_t, hdrSize + PLDM_GET_ALERT_STATUS_REQ_BYTES> requestMsg{};
-
uint8_t versionId = 0x0;
uint8_t retVersionId;
- auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
-
+ PLDM_MSG_DEFINE_P(req, PLDM_GET_ALERT_STATUS_REQ_BYTES);
req->payload[0] = versionId;
- auto rc = decode_get_alert_status_req(req, requestMsg.size() - hdrSize,
+ auto rc = decode_get_alert_status_req(req, PLDM_GET_ALERT_STATUS_REQ_BYTES,
&retVersionId);
EXPECT_EQ(rc, PLDM_SUCCESS);
@@ -149,17 +129,14 @@
TEST(GetAlertStatus, testBadDecodeRequest)
{
- std::array<uint8_t, hdrSize + PLDM_GET_ALERT_STATUS_REQ_BYTES> requestMsg{};
-
uint8_t versionId = 0x0;
uint8_t retVersionId;
- auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
-
+ PLDM_MSG_DEFINE_P(req, PLDM_GET_ALERT_STATUS_REQ_BYTES);
req->payload[0] = versionId;
- auto rc = decode_get_alert_status_req(req, requestMsg.size() - hdrSize + 1,
- &retVersionId);
+ auto rc = decode_get_alert_status_req(
+ req, PLDM_GET_ALERT_STATUS_REQ_BYTES + 1, &retVersionId);
EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
}