Question about unions and heap allocated memory

I tried to use union so that I could update the fields in one thread and then read all the fields in another thread. In a real system, I have mutexes to make sure everything is safe. The problem is fieldB before I had to change it. Field B was declared as field A and C. However, due to a third-party driver, field B must be bound to the page border. When I changed the field B to be highlighted by valloc, I ran into problems.

Questions: 1) Is there a way to statically declare fieldB bound to the page border. Basically doing the same thing as valloc, but on the stack?

2) Is it possible to make a union when field B, or any field is allocated on the heap ?. Not sure if this is even legal.

Here is a simple test program that I experimented with. This does not work unless you declare fieldB as field A and C and make obvious changes to public methods.

#include <iostream> #include <stdlib.h> #include <string.h> #include <stdio.h> class Test { public: Test(void) { // field B must be alligned to page boundary // Is there a way to do this on the stack??? this->field.fieldB = (unsigned char*) valloc(10); }; //I know this is bad, this class is being treated like //a global structure. Its self contained in another class. unsigned char* PointerToFieldA(void) { return &this->field.fieldA[0]; } unsigned char* PointerToFieldB(void) { return this->field.fieldB; } unsigned char* PointerToFieldC(void) { return &this->field.fieldC[0]; } unsigned char* PointerToAllFields(void) { return &this->allFields[0]; } private: // Is this union possible with field B being // allocated on the heap? union { struct { unsigned char fieldA[10]; //This field has to be alligned to page boundary //Is there way to be declared on the stack unsigned char* fieldB; unsigned char fieldC[10]; } field; unsigned char allFields[30]; }; }; int main() { Test test; strncpy((char*) test.PointerToFieldA(), "0123456789", 10); strncpy((char*) test.PointerToFieldB(), "1234567890", 10); strncpy((char*) test.PointerToFieldC(), "2345678901", 10); char dummy[11]; dummy[10] = '\0'; strncpy(dummy, (char*) test.PointerToFieldA(), 10); printf("%s\n", dummy); strncpy(dummy, (char*) test.PointerToFieldB(), 10); printf("%s\n", dummy); strncpy(dummy, (char*) test.PointerToFieldC(), 10); printf("%s\n", dummy); char allFields[31]; allFields[30] = '\0'; strncpy(allFields, (char*) test.PointerToAllFields(), 30); printf("%s\n", allFields); return 0; } 
+4
source share
2 answers

I don’t think you can declare fieldB as a pointer and get the desired behavior (if I understand the question correctly). For the union to make sense when you use it, you need to declare it as an array in the union.

I was curious if it is possible to overload the new operator for the class to force a specific member to be on the page border. I very quickly killed together overloaded operators to do this. This causes the entire sub page to be assigned each time. He finds the offset where this field will be, and then adjusts the address for that amount. Since extra memory is allocated (and if I did the math correctly), that would be safe. Very ugly though.

It fills the distribution offset in a member in the class, so that it knows the amount to “disable” the pointer to free it. This is really scary code. This is like an experiment, but not so good in production code.

 #define PAGE_SIZE 0x1000 class test { public: int allocoffset; void* operator new( size_t ); void operator delete( void* ); union { __declspec( align(4096)) struct { unsigned char fieldA[10]; //This field has to be alligned to page boundary //Is there way to be declared on the stack unsigned char fieldB[10]; unsigned char fieldC[10]; } field; unsigned char allFields[30]; }; }; void* test::operator new(size_t size) { // Allocate an entire extra page so we can offset it by any amount // less than the page size to ensure alignment of fieldB unsigned char *p = (unsigned char*)malloc( sizeof( test ) + PAGE_SIZE ); uintptr_t addr; uintptr_t diff; std::cout << "new " << (void*)p << std::endl; // now offset the returned memory by the amount needed to align // fieldB on a page boundary. addr = (uintptr_t)p + (uintptr_t)( offsetof( test, field.fieldB )); diff = PAGE_SIZE - ( addr & (PAGE_SIZE - 1 )); p += diff; ((test*)p)->allocoffset = diff; return p; } void test::operator delete( void *p ) { // offset by appropriate amount that we allocated it by p = (void*)( (unsigned char*)p - ((test*)p)->allocoffset ); std::cout << "delete " << p << std::endl; free(p); } int main() { test *t; t = new test; std::cout << "allocation offset " << t->allocoffset << std::endl; std::cout << "address of fieldB " << (void*)&t->field.fieldB << std::endl; delete t; } 

Here is an example output:

 new 00353FA0 allocation offset 86 address of fieldB 00355000 delete 00353FA0 
+2
source

I don’t think so - alignment on the stack is a little more complicated, since you need to know where you are right now, allocate enough bytes to consume the “current” memory page, and then distribute the data. On the stack, this is not an ordinary operation (i.e. you will not align anything on the stack).

However, some compilers have pragmas that will align structures, MSVC has ' __ declspec align ', where you can specify the alignment of data elements and the compiler inserts the appropriate number of bytes.

You can create a union in which 1 piece is allocated on the heap - the union will contain all your fields, as usual, but the selected heap will only be a pointer.

Finally, valloc is deprecated - you should use memalign or posix_memalign instead.

+1
source

All Articles