如何将C++二维vector转换为C类型以传入SGX enclave?
vector<vector<int>> to C-compatible Type for SGX Enclave Got it, since SGX's edger8r only supports C types for ECALL/OCALL interfaces, we need to flatten and wrap the 2D vector into a C-style structure that the enclave can handle. Here's a step-by-step example:
1. Define a C-compatible Image Structure
First, create a struct in your EDL file (and mirror it in your C/C++ code if needed) to represent the grayscale image. We'll flatten the 2D vector into a 1D array since C doesn't have built-in dynamic 2D arrays:
// In your enclave.edl file typedef struct { int rows; // Number of rows in the image int cols; // Number of columns per row int* pixel_data; // Flattened 1D array holding all pixel values } GrayscaleImage;
2. Convert vector<vector<int>> to the C Structure
In your untrusted C++ code, write a helper function to convert the 2D vector into the GrayscaleImage struct. We'll use malloc for memory allocation since it's C-compatible and easy to free later:
#include <vector> #include <cstdlib> #include <cstring> GrayscaleImage convert_to_c_image(const std::vector<std::vector<int>>& image_pixels) { GrayscaleImage c_image{}; c_image.rows = image_pixels.size(); // Handle empty image case if (c_image.rows == 0) { c_image.cols = 0; c_image.pixel_data = nullptr; return c_image; } c_image.cols = image_pixels[0].size(); const size_t total_pixels = static_cast<size_t>(c_image.rows) * c_image.cols; // Allocate contiguous memory for flattened pixels c_image.pixel_data = static_cast<int*>(malloc(total_pixels * sizeof(int))); if (!c_image.pixel_data) { // Handle allocation failure c_image.rows = 0; c_image.cols = 0; return c_image; } // Copy pixel data into the 1D array int idx = 0; for (const auto& row : image_pixels) { // Optional: Validate all rows have the same column count if (row.size() != static_cast<size_t>(c_image.cols)) { free(c_image.pixel_data); c_image.pixel_data = nullptr; c_image.rows = 0; c_image.cols = 0; return c_image; } memcpy(c_image.pixel_data + idx, row.data(), c_image.cols * sizeof(int)); idx += c_image.cols; } return c_image; }
3. Update EDL for ECALL
When declaring your ECALL in the EDL, you need to tell edger8r how much data to copy for the pixel_data pointer using the [size] attribute. This ensures the enclave receives the full flattened pixel array:
enclave { trusted { // Declare the ECALL that accepts the image struct void process_grayscale_image([in, size=image->rows * image->cols * sizeof(int)] const GrayscaleImage* image); }; };
4. Process the Image in the Enclave
In your trusted enclave code, access the pixel data using the flattened array. Calculate the index for a pixel at (row, col) with row * cols + col:
#include "enclave_t.h" // Generated by edger8r void process_grayscale_image(const GrayscaleImage* image) { // Validate input to avoid invalid memory access if (!image || image->rows <= 0 || image->cols <= 0 || !image->pixel_data) { return; } // Example: Iterate over all pixels for (int row = 0; row < image->rows; ++row) { for (int col = 0; col < image->cols; ++col) { const int pixel_value = image->pixel_data[static_cast<size_t>(row) * image->cols + col]; // Add your image processing logic here } } }
5. Clean Up Memory
Don't forget to free the allocated memory in your untrusted code after the ECALL completes to avoid leaks:
// After calling the ECALL GrayscaleImage c_img = convert_to_c_image(ImagePixels); if (c_img.pixel_data) { // Call your ECALL here: sgx_status_t status = ecall_process_grayscale_image(enclave_id, &ret_val, &c_img); free(c_img.pixel_data); }
Key Notes
- Input Validation: Always check for empty images, mismatched row lengths, and null pointers to prevent crashes in the enclave.
- Memory Safety: The
[in]attribute tells edger8r to copy data from untrusted memory into the enclave's protected memory, ensuring isolation. - Flexible Alternative: If you prefer, use a flexible array member in the struct (e.g.,
int pixel_data[];), but you'll need to allocate the struct plus pixel data in a singlemalloccall.
内容的提问来源于stack exchange,提问作者asonnino

