Prevent Double Construction Issues

This commit is contained in:
TheBrokenRail 2024-09-20 21:30:38 -04:00
parent 2a63f1ff52
commit 5d2b146b08
9 changed files with 106 additions and 53 deletions

View File

@ -157,6 +157,38 @@ T *dup_vtable(T *vtable) {
}
#undef RTTI_SIZE
// Internal Macros
#define __PREVENT_DESTRUCTION(self) \
~self() = delete
#define __PREVENT_CONSTRUCTION(self) \
self() = delete; \
__PREVENT_DESTRUCTION(self)
#define __PREVENT_COPY(self) \
self(const self &) = delete; \
self &operator=(const self &) = delete
// Easily Extend Structures
template<typename T, typename = void>
struct __HasAllocate : std::false_type {};
template<typename T>
struct __HasAllocate<T, std::enable_if_t<std::is_same_v<T *, decltype(T::allocate())>>> : std::true_type {};
template <typename Super, typename Self>
class __ExtendedStruct final {
static_assert(__HasAllocate<Super>::value, "Super Type Does Not Have A Defined Size");
__PREVENT_DESTRUCTION(__ExtendedStruct);
__PREVENT_COPY(__ExtendedStruct);
alignas(Super) uchar _super[sizeof(Super)];
public:
__ExtendedStruct() {}
Super *super() {
return (Super *) &_super[0];
}
Self data;
};
#define EXTEND_STRUCT(name, base, ...) \
typedef __VA_ARGS__ __##name##_data; \
typedef __ExtendedStruct<base, __##name##_data> name
// Forward Declarations
{{ forwardDeclarations }}

View File

@ -100,9 +100,8 @@ export function formatFile(file: string, options: {[key: string]: string}) {
export const INTERNAL = '__';
export function preventConstruction(self: string) {
let out = '';
out += `${INDENT}${self}() = delete;\n`;
out += `${INDENT}${self}(const ${self} &) = delete;\n`;
out += `${INDENT}${self} &operator=(const ${self} &) = delete;\n`;
out += `${INDENT}${INTERNAL}PREVENT_CONSTRUCTION(${self});\n`;
out += `${INDENT}${INTERNAL}PREVENT_COPY(${self});\n`;
return out;
}
export const LEAN_HEADER_GUARD = '#ifndef LEAN_SYMBOLS_HEADER\n';

View File

@ -52,9 +52,9 @@ function loadSymbols() {
}
// Sort
structureObjects.sort((a, b) => {
if (a.getName() > b.getName()) {
if (a.name > b.name) {
return 1;
} else if (a.getName() < b.getName()) {
} else if (a.name < b.name) {
return -1;
} else {
return 0;
@ -113,7 +113,7 @@ function makeHeaderPart() {
// Generate Code
let structures = '';
for (const structure of structureObjects) {
const name = structure.getName();
const name = structure.name;
structures += `// ${name}\n`;
try {
structures += structure.generate();
@ -167,7 +167,7 @@ function makeCompiledCode(outputDir: string) {
}
// Structure
const name = structure.getName();
const name = structure.name;
declarations += `// ${name}\n`;
try {
declarations += structure.generateCode().trim();

View File

@ -116,29 +116,29 @@ export function load(target: Struct, name: string, isExtended: boolean) {
case 'vtable-size': {
// Set VTable Size
if (!isExtended) {
target.setVTableSize(safeParseInt(args));
target.getVTable().setSize(safeParseInt(args));
}
break;
}
case 'vtable': {
// Set VTable Address
target.ensureVTable();
const vtable = target.getVTable();
if (!isExtended && args.length > 0) {
target.setVTableAddress(safeParseInt(args));
vtable.setAddress(safeParseInt(args));
}
break;
}
case 'property': {
// Add Property
const info = parseProperty(args);
target.addProperty(new Property(info.offset, info.type, info.name, target.getName()));
target.addProperty(new Property(info.offset, info.type, info.name, target.name));
break;
}
case 'static-property': {
// Add Static Property
if (!isExtended) {
const info = parseProperty(args);
target.addStaticProperty(new StaticProperty(info.offset, info.type, info.name, target.getName()));
target.addStaticProperty(new StaticProperty(info.offset, info.type, info.name, target.name));
}
break;
}
@ -150,14 +150,14 @@ export function load(target: Struct, name: string, isExtended: boolean) {
}
case 'virtual-method': {
// Add Virtual Method
const method = parseMethod(args, target.getName(), true, isExtended);
const method = parseMethod(args, target.name, true, isExtended);
target.addMethod(method, true);
break;
}
case 'static-method': {
// Add Static Method
if (!isExtended) {
const method = parseMethod(args, target.getName(), false, false);
const method = parseMethod(args, target.name, false, false);
target.addMethod(method, false);
}
break;
@ -165,7 +165,7 @@ export function load(target: Struct, name: string, isExtended: boolean) {
case 'constructor': {
// Constructor
if (!isExtended) {
let data = `${target.getName()} *constructor`;
let data = `${target.name} *constructor`;
if (args.startsWith('(')) {
// No Custom Name
data += ' ';
@ -174,14 +174,22 @@ export function load(target: Struct, name: string, isExtended: boolean) {
data += '_';
}
data += args;
const method = parseMethod(data, target.getName(), true, false);
const method = parseMethod(data, target.name, true, false);
target.addMethod(method, false);
}
break;
}
case 'vtable-destructor-offset': {
// Set VTable Destructor Offset
target.setVTableDestructorOffset(safeParseInt(args));
target.getVTable().setDestructorOffset(safeParseInt(args));
break;
}
case 'mark-as-simple': {
// Mark As Simple
if (isExtended) {
throw new Error('Cannot Extend Simple Structure');
}
target.markAsSimple();
break;
}
default: {

View File

@ -4,7 +4,7 @@ import { Property, StaticProperty } from './property';
import { VTable } from './vtable';
export class Struct {
readonly #name: string;
readonly name: string;
#vtable: VTable | null;
readonly #methods: Method[];
readonly #properties: Property[];
@ -12,10 +12,11 @@ export class Struct {
readonly #dependencies: string[];
readonly #staticProperties: StaticProperty[];
#directParent: string | null;
#isSimple: boolean;
// Constructor
constructor(name: string) {
this.#name = name;
this.name = name;
this.#methods = [];
this.#properties = [];
this.#vtable = null;
@ -23,6 +24,7 @@ export class Struct {
this.#dependencies = [];
this.#staticProperties = [];
this.#directParent = null;
this.#isSimple = false;
}
// Dependencies
@ -34,39 +36,29 @@ export class Struct {
}
// Ensure VTable Exists
ensureVTable() {
getVTable() {
if (this.#vtable === null) {
this.#vtable = new VTable(this.#name);
this.#vtable = new VTable(this.name);
this.addProperty(this.#vtable.property);
}
}
// Set VTable Destructor Offset
setVTableDestructorOffset(offset: number) {
this.ensureVTable();
this.#vtable!.setDestructorOffset(offset);
return this.#vtable;
}
// Setters
setSize(size: number) {
this.#size = size;
}
// Getters
getName() {
return this.#name;
}
// Add Method
addMethod(method: Method, isVirtual: boolean) {
if (method.returnType !== this.#name && method.returnType in STRUCTURE_FILES) {
if (method.returnType !== this.name && method.returnType in STRUCTURE_FILES) {
this.#addDependency(method.returnType);
}
if (isVirtual) {
if (method.self !== this.#name) {
if (method.self !== this.name) {
throw new Error();
}
this.ensureVTable();
this.#vtable!.add(method);
this.getVTable().add(method);
} else {
if (method.isInherited) {
this.#addDependency(method.self);
@ -88,14 +80,21 @@ export class Struct {
this.#staticProperties.push(property);
}
// Configure VTable
setVTableSize(size: number) {
this.ensureVTable();
this.#vtable!.setSize(size);
// "Simple" Structures
markAsSimple() {
this.#isSimple = true;
}
setVTableAddress(address: number) {
this.ensureVTable();
this.#vtable!.setAddress(address);
#checkSimple() {
const checks = [
['Cannot Inherit', this.#directParent !== null],
['Must Have A Defined Size', this.#size === null],
['Cannot Have A VTable', this.#vtable !== null]
];
for (const check of checks) {
if (check[1]) {
throw new Error('Simple Structures ' + check[0]);
}
}
}
// Generate Properties
@ -127,7 +126,9 @@ export class Struct {
if (lastProperty) {
paddingSize += ` - sizeof(${lastProperty.type()})`;
}
out += `${INDENT}uchar ${INTERNAL}padding${i}[${paddingSize}];\n`;
if (!this.#isSimple) {
out += `${INDENT}uchar ${INTERNAL}padding${i}[${paddingSize}];\n`;
}
// The Actual Property
if (property !== sizeProperty) {
@ -175,6 +176,13 @@ export class Struct {
}
}
}
// Allocation Method
if (this.#size !== null) {
// THIS DOES NOT CONSTRUCT THE OBJECT
out += `${INDENT}static ${this.name} *allocate() {\n`;
out += `${INDENT}${INDENT}return (${this.name} *) ::operator new(sizeof(${this.name}));\n`;
out += `${INDENT}}\n`;
}
// Return
out += '#endif\n';
return out;
@ -184,6 +192,11 @@ export class Struct {
generate() {
let out = '';
// Check "Simple" Status
if (this.#isSimple) {
this.#checkSimple();
}
// VTable
if (this.#vtable !== null) {
out += this.#vtable.generate();
@ -214,16 +227,16 @@ export class Struct {
out += '#endif\n';
// Structure
out += `struct ${this.#name} {\n`;
out += `struct ${this.name} final {\n`;
out += this.#generateProperties();
out += this.#generateMethods();
for (const property of this.#staticProperties) {
// Static Property References
out += `${INDENT}static ${property.referenceDefinition(false)};\n`;
}
if (this.#size === null) {
// Prevent Manually Copying/Allocating Structure With Undefined
out += preventConstruction(this.#name);
if (!this.#isSimple) {
// Disable Construction Of Complex Structures
out += preventConstruction(this.name);
}
out += `};\n`;
@ -232,12 +245,12 @@ export class Struct {
const property = this.#properties[i]!;
const name = property.name();
const offset = property.offset;
out += `static_assert(offsetof(${this.#name}, ${name}) == ${toHex(offset)}, "Invalid Offset");\n`;
out += `static_assert(offsetof(${this.name}, ${name}) == ${toHex(offset)}, "Invalid Offset");\n`;
}
// Sanity Check Size
if (this.#size !== null) {
out += assertSize(this.#name, this.#size);
out += assertSize(this.name, this.#size);
}
// Return

View File

@ -133,7 +133,7 @@ export class VTable {
// Structure
out += `typedef struct ${this.#getName()} ${this.#getName()};\n`;
out += `struct ${this.#getName()} {\n`;
out += `struct ${this.#getName()} final {\n`;
for (let i = 0; i < methods.length; i++) {
const info = methods[i];
if (info) {

View File

@ -13,6 +13,7 @@
<item>static-method</item>
<item>constructor</item>
<item>vtable-destructor-offset</item>
<item>mark-as-simple</item>
</list>
<list name="types">
<item>const</item>

View File

@ -2,7 +2,7 @@ syntax def "\.def$"
comment "//"
# Commands
color magenta "\<(extends|size|vtable(-size|-destructor-offset)?|property|static-property|((static|virtual)-)?method|constructor)\>"
color magenta "\<(extends|size|vtable(-size|-destructor-offset)?|property|static-property|((static|virtual)-)?method|constructor|mark-as-simple)\>"
# Types
color green "\<((u?(char|short|int))|float|bool|void|std::(string|vector|map))\>"

View File

@ -34,13 +34,13 @@
<key>name</key>
<string>keyword.control.symbol-processor</string>
<key>match</key>
<string>\b(extends|size|vtable-size|vtable-destructor-offset|vtable|property|static-property|method|virtual-method|static-method|constructor)\b</string>
<string>\b(extends|size|vtable-size|vtable-destructor-offset|vtable|property|static-property|method|virtual-method|static-method|constructor|mark-as-simple)\b</string>
</dict>
<dict>
<key>name</key>
<string>storage.type.symbol-processor</string>
<key>match</key>
<string>\b(const|char|uchar|short|ushort|int|uint|float|bool|void|std::string|std::vector|std::map)\b</string>
<string>\b(const|char|uchar|short|ushort|int|uint|float|bool|void|std::string|std::vector|std::map|unsigned|long)\b</string>
</dict>
<dict>
<key>name</key>