diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 05:33:33 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 05:33:33 +0000 |
| commit | 4e22f464387725a5a282f3d72e11cfb694a31a5a (patch) | |
| tree | 17fed09b30633e6aae583f490a0ad9c0c95fb045 /lib | |
| parent | 4dd85fd6ecd9a67e5c2b68380873e6e114714355 (diff) | |
feat(memory): add checked REALLOC with failure preservation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/Builtins.h | 1 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 7 | ||||
| -rw-r--r-- | lib/CodeGen/MemoryHandler.cc | 34 |
3 files changed, 42 insertions, 0 deletions
diff --git a/lib/CodeGen/Builtins.h b/lib/CodeGen/Builtins.h index 69361cf..b74afc4 100644 --- a/lib/CodeGen/Builtins.h +++ b/lib/CodeGen/Builtins.h @@ -27,6 +27,7 @@ inline constexpr BuiltinInfo Builtins[] = { {"STR_TO_NUM", 1, "REAL"}, {"EOF", 1, "BOOLEAN"}, {"MALLOC", 1, "C_TYPE(\"void*\")"}, + {"REALLOC", 2, "C_TYPE(\"void*\")"}, {"FREE", 1, "C_TYPE(\"void*\")"}, }; diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc index 0a24c8d..9ea79d8 100644 --- a/lib/CodeGen/ExpressionGen.cc +++ b/lib/CodeGen/ExpressionGen.cc @@ -192,6 +192,13 @@ Value *CodeGen::emitCall(const std::string &Callee, if (!Size) return nullptr; return Memory->emitAllocate(Size, Line); } + if (Name == "REALLOC") { + Value *Address = emitCoercedExpr(ArgExprs[0].get(), resolveType("C_TYPE(\"void*\")")); + if (!Address) return nullptr; + Value *Size = emitAllocationSize(ArgExprs[1].get()); + if (!Size) return nullptr; + return Memory->emitResize(Address, Size, Line); + } if (Name == "FREE") { Value *Address = emitCoercedExpr(ArgExprs[0].get(), resolveType("C_TYPE(\"void*\")")); if (!Address) return nullptr; diff --git a/lib/CodeGen/MemoryHandler.cc b/lib/CodeGen/MemoryHandler.cc index fc6d982..07fe6f6 100644 --- a/lib/CodeGen/MemoryHandler.cc +++ b/lib/CodeGen/MemoryHandler.cc @@ -27,6 +27,7 @@ void MemoryHandler::ensureRuntime() { ConstantPointerNull::get(Ptr), "__cps_memory_head"); Malloc = Module.getOrInsertFunction("malloc", FunctionType::get(Ptr, {SizeTy}, false)); Free = Module.getOrInsertFunction("free", FunctionType::get(Type::getVoidTy(Context), {Ptr}, false)); + Realloc = Module.getOrInsertFunction("realloc", FunctionType::get(Ptr, {Ptr, SizeTy}, false)); AllocationError = Builder.CreateGlobalString("[Fatal] line %d: Memory allocation failed\n", "err_allocation", 0, &Module); TrackingError = Builder.CreateGlobalString("[Fatal] line %d: Allocation tracking failed\n", @@ -39,6 +40,8 @@ void MemoryHandler::ensureRuntime() { buildAllocate(); ReleaseFn = createHelper("__cps_memory_release", {Ptr, I32}); buildRelease(); + ResizeFn = createHelper("__cps_memory_resize", {Ptr, SizeTy, I32}); + buildResize(); } // Return the address of the list link that owns the matching node. This also @@ -118,3 +121,34 @@ Value *MemoryHandler::emitRelease(Value *Address, int Line) { ensureRuntime(); return Exceptions.emitCall(ReleaseFn, {Address, Builder.getInt32(Line)}, "released"); } + +void MemoryHandler::buildResize() { + auto *Ptr = PointerType::getUnqual(Context); + Value *Address = ResizeFn->getArg(0), *Size = ResizeFn->getArg(1), *Line = ResizeFn->getArg(2); + auto *Allocate = BasicBlock::Create(Context, "allocate", ResizeFn); + auto *Validate = BasicBlock::Create(Context, "validate", ResizeFn); + auto *Release = BasicBlock::Create(Context, "release", ResizeFn); + auto *Resize = BasicBlock::Create(Context, "resize", ResizeFn); + Builder.CreateCondBr(Builder.CreateIsNull(Address), Allocate, Validate); + Builder.SetInsertPoint(Allocate); + Builder.CreateRet(Exceptions.emitCall(AllocateFn, {Size, Line}, "allocation")); + Builder.SetInsertPoint(Validate); + Value *Link = Exceptions.emitCall(FindFn, {Address, Line}, "link"); + Value *Node = Builder.CreateLoad(Ptr, Link); + Builder.CreateCondBr(Builder.CreateICmpEQ(Size, ConstantInt::get(SizeTy, 0)), Release, Resize); + Builder.SetInsertPoint(Release); + Exceptions.emitCall(ReleaseFn, {Address, Line}); + Builder.CreateRet(ConstantPointerNull::get(Ptr)); + Builder.SetInsertPoint(Resize); + Value *NewAddress = Builder.CreateCall(Realloc, {Address, Size}, "resized"); + // libc preserves the original block on nonzero-size failure. Leave the + // tracking entry untouched until the check has succeeded as well. + Checker.emitCheck(Builder.CreateIsNull(NewAddress), AllocationError, {Line}); + Builder.CreateStore(NewAddress, Builder.CreateStructGEP(NodeTy, Node, 0)); + Builder.CreateRet(NewAddress); +} + +Value *MemoryHandler::emitResize(Value *Address, Value *Size, int Line) { + ensureRuntime(); + return Exceptions.emitCall(ResizeFn, {Address, Size, Builder.getInt32(Line)}, "resized"); +} |
