KMDF MmCopyVirtualMemory Undefined - kmdf

Hello and my problem today is I was trying out a new/old method of writing memory with a system files(.sys) after watching Zer0Mem0ry's video on the subject. But I tried to copy but came with the error :
Error C4013 'MmCopyVirtualMemory' undefined; assuming extern returning int
Even after having done everything. So I was wondering if I had to define this function or importation would be enough. Any help would be amazing!
My Code(driver.c)
https://pastebin.com/AfBUGFCh
Couldn't paste code for some reason.
#include "driver.h"
#include <ntddk.h>
#include "driver.tmh"
#pragma comment(lib, "Ntoskrnl.lib")
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, CallOfDutySysFileEvtDeviceAdd)
#pragma alloc_text (PAGE, CallOfDutySysFileEvtDriverContextCleanup)
#endif
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
PEPROCESS SourceProcess = Process;
PEPROCESS TargetProcess = PsGetCurrentProcess();
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
NTSTATUS KeWriteProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
PEPROCESS SourceProcess = PsGetCurrentProcess();
PEPROCESS TargetProcess = Process;
SIZE_T Result;
if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
return STATUS_SUCCESS;
else
return STATUS_ACCESS_DENIED;
}
NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
WDF_DRIVER_CONFIG config;
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES attributes;
WPP_INIT_TRACING(DriverObject, RegistryPath);
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.EvtCleanupCallback = CallOfDutySysFileEvtDriverContextCleanup;
WDF_DRIVER_CONFIG_INIT(&config,
CallOfDutySysFileEvtDeviceAdd
);
status = WdfDriverCreate(DriverObject,
RegistryPath,
&attributes,
&config,
WDF_NO_HANDLE
);
if (!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
WPP_CLEANUP(DriverObject);
return status;
}
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
return status;
}
NTSTATUS
CallOfDutySysFileEvtDeviceAdd(
_In_ WDFDRIVER Driver,
_Inout_ PWDFDEVICE_INIT DeviceInit
)
{
NTSTATUS status;
UNREFERENCED_PARAMETER(Driver);
PAGED_CODE();
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
status = CallOfDutySysFileCreateDevice(DeviceInit);
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
return status;
}
VOID
CallOfDutySysFileEvtDriverContextCleanup(
_In_ WDFOBJECT DriverObject
)
{
UNREFERENCED_PARAMETER(DriverObject);
PAGED_CODE();
TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
}

it exists in another file called ReadWrite.c you can find in the Zer0Mem0ry's github

Related

Updating a File (KeyValueEEPROM) to ArduinoJson 6

I am an engineer not a programmer, but due to circumstance I am fix the programming for a project I am working on.
This is where I am currently stuck. The KeyValueEEPROM.h is used to store the collected data by the main program, and then read from to upload to a SQL database.
Somewhere in this process I am losing the data collected by the sensor. I believe I isolated the problem to the referenced file.
the first version was made using ArduinoJson 5 (I am not the original creator). This is incompatible with the current program, as ArduinoJson 5 has been upgraded to the 6th version.
The other one is edited by me to use ArduinoJson 6.
I had to change the file to get the codes to compile (which it now does), but I am not sure if I was able to preserve the functions.
I would like someone to point out any mistakes I made during the 'update'.
ArduinoJson5 Version:
#ifndef KeyValueEEPROM_h
#define KeyValueEEPROM_h
#include <Arduino.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
#ifndef KeyValueEEPROM_SIZE
#if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
#define KeyValueEEPROM_SIZE 4096
#endif
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
#define KeyValueEEPROM_SIZE 1024
#endif
#if defined(__AVR_ATmega168__)
#define KeyValueEEPROM_SIZE 512
#endif
#endif
class KeyValueEEPROMClass {
public:
// Public methods
void begin() {
// If this method was already called, return.
if (LibraryStartet) return;
// Read JSON data from the EEPROM.
String json = readEEPROM();
// Parse JSON data.
root = &jsonBuffer.parseObject(json);
// If JSON couldn't be parsed,
if (!root->success()) {
// then create an new key-value store.
clear();
}
};
void clear() {
// Clear buffer.
jsonBuffer.clear();
// Create JSON root object.
root = &jsonBuffer.createObject();
};
void remove(String key) {
// Remove key.
root->remove(key);
};
void apply() {
// Clear the EEPROM.
clearEEPROM();
// Extract JSON data from the root object.
String json;
root->printTo(json);
// Write JSON data to the EEPROM.
writeEEPROM(json);
};
bool exists(String key) {
return root->containsKey(key);
};
template <typename T>
T get(String key) {
T value = (*root)[key].as<T>();
return value;
};
template <typename T>
void set(String key, T value) {
(*root)[key] = value;
};
private:
// Private methods
void clearEEPROM() {
#if defined(ESP8266) || defined(ESP32)
// Begin EEPROM library.
EEPROM.begin(KeyValueEEPROM_SIZE);
#endif
// Write all bytes to zero.
for (int i = 0; i < KeyValueEEPROM_SIZE; i++) EEPROM.write(i, '\0');
// End EEPROM library.
EEPROM.end();
};
String readEEPROM() {
#if defined(ESP8266) || defined(ESP32)
// Begin EEPROM library.
EEPROM.begin(KeyValueEEPROM_SIZE);
#endif
// Read JSON data until null-termination.
String string = ""; unsigned int i; unsigned char byte;
for (i = 0; i < KeyValueEEPROM_SIZE; i++) {
byte = EEPROM.read(i);
if (byte == '\0') {
break;
} else {
string += char(byte);
}
}
// End EEPROM library.
EEPROM.end();
// Return JSON data.
return string;
};
void writeEEPROM(String json) {
#if defined(ESP8266) || defined(ESP32)
// Begin EEPROM library.
EEPROM.begin(KeyValueEEPROM_SIZE);
#endif
// Write JSON data.
unsigned int i;
for (i = 0; i < json.length(); i++) {
EEPROM.write(i, json.charAt(i));
}
// If the length of the JSON data is smaller than the EEPROM size,
if (json.length() < KeyValueEEPROM_SIZE)
// than write at the last position a null-termination.
EEPROM.write(json.length(), '\0');
// End EEPROM library.
EEPROM.end();
}
// Properties
StaticJsonBuffer<KeyValueEEPROM_SIZE> jsonBuffer;
JsonObject *root;
bool LibraryStartet = false;
};
static KeyValueEEPROMClass KeyValueEEPROM;
extern KeyValueEEPROMClass KeyValueEEPROM;
#endif
ArduinoJson6 Version
#ifndef KeyValueEEPROM_h
#define KeyValueEEPROM_h
#include <Arduino.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
#ifndef KeyValueEEPROM_SIZE
#if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega1280__) ||
defined(__AVR_ATmega2560__)
#define KeyValueEEPROM_SIZE 4096
#endif
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
#define KeyValueEEPROM_SIZE 1024
#endif
#if defined(__AVR_ATmega168__)
#define KeyValueEEPROM_SIZE 512
#endif
#endif
class KeyValueEEPROMClass {
public:
// Public methods
void begin() {
// If this method was already called, return.
if (LibraryStartet) return;
// Read JSON data from the EEPROM.
String json = readEEPROM();
// Parse JSON data.
DeserializationError error = deserializeJson(doc,json);
// If JSON couldn't be parsed,
if (error) {
// then create an new key-value store.
clear();
}
};
void clear() {
// Clear buffer.
doc.clear();
// Create JSON root object.
// doc = &doc.createObject();
};
void remove(String key) {
// Remove key.
doc.remove(key);
};
void apply() {
// Clear the EEPROM.
clearEEPROM();
// Extract JSON data from the root object.
String json;
//doc.
serializeJson(doc, json);
// Write JSON data to the EEPROM.
writeEEPROM(json);
};
bool exists(String key) {
return doc.containsKey(key);
};
template <typename T>
T get(String key) {
T value = doc[key].as<T>();
return value;
};
template <typename T>
void set(String key, T value) {
doc[key] = value;
};
private:
// Private methods
void clearEEPROM() {
#if defined(ESP8266) || defined(ESP32)
// Begin EEPROM library.
EEPROM.begin(KeyValueEEPROM_SIZE);
#endif
// Write all bytes to zero.
for (int i = 0; i < KeyValueEEPROM_SIZE; i++) EEPROM.write(i, '\0');
// End EEPROM library.
EEPROM.end();
};
String readEEPROM() {
#if defined(ESP8266) || defined(ESP32)
// Begin EEPROM library.
EEPROM.begin(KeyValueEEPROM_SIZE);
#endif
// Read JSON data until null-termination.
String string = ""; unsigned int i; unsigned char byte;
for (i = 0; i < KeyValueEEPROM_SIZE; i++) {
byte = EEPROM.read(i);
if (byte == '\0') {
break;
} else {
string += char(byte);
}
}
// End EEPROM library.
EEPROM.end();
// Return JSON data.
return string;
};
void writeEEPROM(String json) {
#if defined(ESP8266) || defined(ESP32)
// Begin EEPROM library.
EEPROM.begin(KeyValueEEPROM_SIZE);
#endif
// Write JSON data.
unsigned int i;
for (i = 0; i < json.length(); i++) {
EEPROM.write(i, json.charAt(i));
}
// If the length of the JSON data is smaller than the EEPROM size,
if (json.length() < KeyValueEEPROM_SIZE)
// than write at the last position a null-termination.
EEPROM.write(json.length(), '\0');
// End EEPROM library.
EEPROM.end();
}
// Properties
StaticJsonDocument<KeyValueEEPROM_SIZE> doc;
//JsonObject *doc;
JsonObject object = doc.to<JsonObject>();
bool LibraryStartet = false;
};
static KeyValueEEPROMClass KeyValueEEPROM;
extern KeyValueEEPROMClass KeyValueEEPROM;
#endif
This is also my first post here, so if I have formatting issues or lack clarity I apologize.
Thanks,

C - simple http server + directory listening

Here is a working example of a simple HTTP server written in C (working well for it's purpose)
But what I try to achieve/understand is how to implement directory listening!!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#include <dirent.h>
#define CONNMAX 100
#define BYTES 1024
char* directory;
struct dirent *dirst;
DIR *dir;
char *ROOT;
int listenfd, clients[CONNMAX];
void error(char *);
void startServer(char *);
void respond(int);
int main(int argc, char* argv[])
{
struct sockaddr_in clientaddr;
socklen_t addrlen;
char c;
//Default Values PATH = ~/ and PORT=10000
char PORT[6];
ROOT = getenv("PWD");
strcpy(PORT,"10000");
int slot=0;
//Parsing the command line arguments
while ((c = getopt (argc, argv, "p:r:")) != -1)
switch (c)
{
case 'r':
ROOT = malloc(strlen(optarg));
strcpy(ROOT,optarg);
break;
case 'p':
strcpy(PORT,optarg);
break;
case '?':
fprintf(stderr,"Wrong arguments given!!!\n");
exit(1);
default:
exit(1);
}
printf("Server started at port no. %s%s%s with root directory as %s%s%s\n","\033[92m",PORT,"\033[0m","\033[92m",ROOT,"\033[0m");
// Setting all elements to -1: signifies there is no client connected
int i;
for (i=0; i<CONNMAX; i++)
clients[i]=-1;
startServer(PORT);
// ACCEPT connections
while (1)
{
addrlen = sizeof(clientaddr);
clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot]<0)
error ("accept() error");
else
{
if ( fork()==0 )
{
respond(slot);
exit(0);
}
}
while (clients[slot]!=-1) slot = (slot+1)%CONNMAX;
}
return 0;
}
//start server
void startServer(char *port)
{
struct addrinfo hints, *res, *p;
// getaddrinfo for host
memset (&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo( NULL, port, &hints, &res) != 0)
{
perror ("getaddrinfo() error");
exit(1);
}
// socket and bind
for (p = res; p!=NULL; p=p->ai_next)
{
listenfd = socket (p->ai_family, p->ai_socktype, 0);
if (listenfd == -1) continue;
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break;
}
if (p==NULL)
{
perror ("socket() or bind()");
exit(1);
}
freeaddrinfo(res);
// listen for incoming connections
if ( listen (listenfd, 1000000) != 0 )
{
perror("listen() error");
exit(1);
}
}
//client connection
void respond(int n)
{
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fd, bytes_read;
memset( (void*)mesg, (int)'\0', 99999 );
rcvd=recv(clients[n], mesg, 99999, 0);
if (rcvd<0) // receive error
fprintf(stderr,("recv() error\n"));
else if (rcvd==0) // receive socket closed
fprintf(stderr,"Client disconnected unexpectedly.\n");
else // message received
{
// printf("%s", mesg);
reqline[0] = strtok (mesg, " \t\n");
if ( strncmp(reqline[0], "GET\0", 4)==0 )
{
reqline[1] = strtok (NULL, " \t");
reqline[2] = strtok (NULL, " \t\n");
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0 && strncmp( reqline[2], "HTTP/1.1", 8)!=0 )
{
write(clients[n], "HTTP/1.0 400 Bad Request\n", 25);
}
else
{
if ( strncmp(reqline[1], "/\0", 2)==0 )
reqline[1] = "/index.html"; //Because if no file is specified, index.html will be opened by default (like it happens in APACHE...
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
printf("Serving: %s\n", path);
if ( (fd=open(path, O_RDONLY))!=-1 ) //FILE FOUND
{
send(clients[n], "HTTP/1.0 200 OK\n\n", 17, 0);
while ( (bytes_read=read(fd, data_to_send, BYTES))>0 )
write (clients[n], data_to_send, bytes_read);
}
else write(clients[n], "HTTP/1.0 404 Not Found\n", 23); //FILE NOT FOUND
}
}
}
//Closing SOCKET
shutdown (clients[n], SHUT_RDWR); //All further send and recieve operations are DISABLED...
close(clients[n]);
clients[n]=-1;
}
gcc -Wall -Wextra -Werror simplehttp.c -o http
./http -p 9090 -r /home/configs
Now, in browser if i type address http://localhost:9090 => got error( because index,html is missing)
As I'm still rusty in C(trying to get back in shape), i try to modify the code to allow also dir listen :)
Any help is much appreciate :)

crash on ubuntu but normally on Mac when get instance out from sqlie blob

I had saved a class instance in blob field using sqlite-db.
The table policyRule have only one field which is "blob" type.
Now I get it out from the table, which is run normally in macOS but ubuntu.
Would you give me some advice?
#include <string.h>
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string>
using namespace std;
class SENDFILERULE
{
public:
string a;
int b;
string c;
};
void doTest()
{
sqlite3* conn = NULL;
int result = sqlite3_open("mytest.db",&conn);
if (result != SQLITE_OK)
{
sqlite3_close(conn);
return;
}
char createTableSQL[1024];
sprintf(createTableSQL,"%s","CREATE TABLE IF NOT EXISTS policyRule (rule blob)");
sqlite3_stmt* stmt = NULL;
//8.read from database
const char* selectSQL = "SELECT * FROM policyRule";
stmt = NULL;
if(sqlite3_prepare_v2(conn,selectSQL,strlen(selectSQL),&stmt,NULL) !=SQLITE_OK)
{
if (stmt)
sqlite3_finalize(stmt);
sqlite3_close(conn);
return;
}
do
{
int ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
char* buf =(char*)malloc(1024);
memset(buf,0,1024);
buf = (char*)sqlite3_column_blob(stmt,0);
SENDFILERULE* pRule =reinterpret_cast<SENDFILERULE*>(buf);
printf("%s %d %s \n",pRule->a.c_str(),pRule->b,pRule->c.c_str());
}
else if(ret == SQLITE_DONE)
{
printf("select end \n");
break;
}
}while(1);
sqlite3_finalize(stmt);
}
int main()
{
doTest();
return 0;
}
when I print the pRule->b, it is ok, but the string type.

ev in redisAsyncContext

In redisAsyncContext, stuct ev was defined:
struct {
void *data;
void (*addRead)(void *privdata);
void (*delRead)(void *privdata);
void (*addWrite)(void *privdata);
void (*delWrite)(void *privdata);
void (*cleanup)(void *privdata);
} ev;
There is a function:
void CleanUpEvent()
{
if (m_pstContext->ev.delRead)
{
m_pstContext->ev.delRead(m_pstContext->ev.data);
}
if (m_pstContext->ev.delWrite)
{
m_pstContext->ev.delWrite(m_pstContext->ev.data);
}
}
How it works? When should I use ev?
Basically you need to provide only connect and disconnect callbacks, rest of things hiredis will do for you alone.
#include <hiredis.h>
#include <async.h>
#include <adapters/libuv.h>
void connectCallback(const redisAsyncContext *c, int status);
void disconnectCallback(const redisAsyncContext *c, int status);
void getCallback(redisAsyncContext *c, void *r, void *privdata);
int main (int argc, char **argv) {
//make a async context
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
//now, you need to attach hiredis to your event loop, its depends on event lib that you are using
//example for libuv
redisLibuvAttach(c, uv_default_loop());
//now we setup callbacks
redisAsyncSetConnectCallback(c, connectCallback);
redisAsyncSetDisconnectCallback(c, disconnectCallback);
//enquee "SET foo bar" without callback
redisAsyncCommand(c, NULL, NULL, "SET foo %b", "bar", strlen("bar"));
//enquee "GET foo" with callback and privdata "end-1"
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET foo");
//run your event loop
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
Check https://github.com/redis/hiredis/tree/master/examples for more examples on different event libraries.

How to attach to existing shared memory from Qt?

I have created a shared memory segment with the help of a binary in C and written some data into it. Now I want read that data from Qt. How to attach to existing shared memory from Qt?
QSharedMemory isn't really meant to interoperate with anything else. On Unix, it is implemented via SYSV shared memory, but it passes Qt-specific arguments to ftok:
::ftok(filename.constData(), qHash(filename, proj_id));
You could emulate this behavior in your C code, but I don't think it's necessary.
Instead of opening a shared memory segment, simply map a file to memory, and access it from multiple processes. On Qt, QFile::map does what you need.
The example below shows both techniques: using SYSV shared memory and using memory-mapped files:
// https://github.com/KubaO/stackoverflown/tree/master/questions/sharedmem-interop-39573295
#include <QtCore>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <string>
First, let's have a shared data structure.
struct Data {
int a = 1;
bool b = true;
char c = 'S';
bool operator==(const Data & o) const { return o.a == a && o.b == b && o.c == c; }
static void compare(const void * a, const void * b) {
auto data1 = reinterpret_cast<const Data*>(a);
auto data2 = reinterpret_cast<const Data*>(b);
Q_ASSERT(*data1 == *data2);
}
};
We definitely want error checking, so let's add some helpers that make that easier:
void check(bool ok, const char * msg, const char * detail) {
if (ok) return;
std::string str{msg};
str.append(": ");
str.append(detail);
throw std::runtime_error{str};
}
void check(int f, const char * msg) { check(f != -1, msg, strerror(errno)); }
void check(void * f, const char * msg) { check(f != MAP_FAILED, msg, strerror(errno)); }
void check(bool rc, const QSharedMemory & shm, const char * msg) { check(rc, msg, shm.errorString().toLocal8Bit()); }
void check(bool rc, const QFile & file, const char * msg) { check(rc, msg, file.errorString().toLocal8Bit()); }
And we need RAII wrappers for C APIs:
struct noncopyable { Q_DISABLE_COPY(noncopyable) noncopyable() {} };
struct ShmId : noncopyable {
int id;
ShmId(int id) : id{id} {}
~ShmId() { if (id != -1) shmctl(id, IPC_RMID, NULL); }
};
struct ShmPtr : noncopyable {
void * ptr;
ShmPtr(void * ptr) : ptr{ptr} {}
~ShmPtr() { if (ptr != (void*)-1) shmdt(ptr); }
};
struct Handle : noncopyable {
int fd;
Handle(int fd) : fd{fd} {}
~Handle() { if (fd != -1) close(fd); }
};
Here's how to interoperates SYSV shared memory sections between C and Qt. Unfortunately, unless you reimplement qHash in C, it's not possible:
void ipc_shm_test() {
QTemporaryFile shmFile;
check(shmFile.open(), shmFile, "shmFile.open");
// SYSV SHM
auto nativeKey = QFile::encodeName(shmFile.fileName());
auto key = ftok(nativeKey.constData(), qHash(nativeKey, 'Q'));
check(key, "ftok");
ShmId id{shmget(key, sizeof(Data), IPC_CREAT | 0600)};
check(id.id, "shmget");
ShmPtr ptr1{shmat(id.id, NULL, 0)};
check(ptr1.ptr, "shmat");
new (ptr1.ptr) Data;
// Qt
QSharedMemory shm;
shm.setNativeKey(shmFile.fileName());
check(shm.attach(QSharedMemory::ReadOnly), shm, "shm.attach");
auto ptr2 = shm.constData();
Data::compare(ptr1.ptr, ptr2);
}
Here's how to interoperate memory-mapped files:
void mmap_test() {
QTemporaryFile shmFile;
check(shmFile.open(), "shmFile.open");
shmFile.write({sizeof(Data), 0});
check(true, shmFile, "shmFile.write");
check(shmFile.flush(), shmFile, "shmFile.flush");
// SYSV MMAP
Handle fd{open(QFile::encodeName(shmFile.fileName()), O_RDWR)};
check(fd.fd, "open");
auto ptr1 = mmap(NULL, sizeof(Data), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd.fd, 0);
check(ptr1, "mmap");
new (ptr1) Data;
// Qt
auto ptr2 = shmFile.map(0, sizeof(Data));
Data::compare(ptr1, ptr2);
}
And finally, the test harness:
int main() {
try {
ipc_shm_test();
mmap_test();
}
catch (const std::runtime_error & e) {
qWarning() << e.what();
return 1;
}
return 0;
}

Resources