mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
[svn r225] Fixed: delete expressions no longer use llvm's free instruction, which crashes on a GC provided pointer.
This commit is contained in:
@@ -932,6 +932,19 @@ void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoFinalizeClass(llvm::Value* inst)
|
||||
{
|
||||
// get runtime function
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_callfinalizer");
|
||||
// build args
|
||||
llvm::SmallVector<llvm::Value*,1> arg;
|
||||
arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp"));
|
||||
// call
|
||||
llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DValue* DtoCastClass(DValue* val, Type* _to)
|
||||
{
|
||||
Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars());
|
||||
|
||||
@@ -28,6 +28,7 @@ DValue* DtoNewClass(TypeClass* type, NewExp* newexp);
|
||||
void DtoInitClass(TypeClass* tc, llvm::Value* dst);
|
||||
DValue* DtoCallClassCtor(TypeClass* type, CtorDeclaration* ctor, Array* arguments, llvm::Value* mem);
|
||||
void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
|
||||
void DtoFinalizeClass(llvm::Value* inst);
|
||||
|
||||
DValue* DtoCastClass(DValue* val, Type* to);
|
||||
DValue* DtoDynamicCastObject(DValue* val, Type* to);
|
||||
|
||||
@@ -283,6 +283,40 @@ static void LLVM_D_BuildRuntimeModule()
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
|
||||
// void _d_delarray(size_t plength, void* pdata)
|
||||
{
|
||||
std::string fname("_d_delarray");
|
||||
std::vector<const llvm::Type*> types;
|
||||
types.push_back(sizeTy);
|
||||
types.push_back(voidPtrTy);
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
|
||||
// void _d_delmemory(void* p)
|
||||
// void _d_delinterface(void* p)
|
||||
// void _d_callfinalizer(void* p)
|
||||
{
|
||||
std::string fname("_d_delmemory");
|
||||
std::string fname2("_d_delinterface");
|
||||
std::string fname3("_d_callfinalizer");
|
||||
std::vector<const llvm::Type*> types;
|
||||
types.push_back(voidPtrTy);
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname3, M);
|
||||
}
|
||||
|
||||
// void _d_delclass(Object p)
|
||||
{
|
||||
std::string fname("_d_delclass");
|
||||
std::vector<const llvm::Type*> types;
|
||||
types.push_back(objectTy);
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
141
gen/toir.cpp
141
gen/toir.cpp
@@ -1984,66 +1984,6 @@ DValue* NewExp::toElem(IRState* p)
|
||||
return new DImValue(type, mem, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
const llvm::Type* t = DtoType(ntype);
|
||||
|
||||
llvm::Value* emem = 0;
|
||||
bool inplace = false;
|
||||
|
||||
if (ntype->ty == Tarray) {
|
||||
assert(arguments);
|
||||
if (arguments->dim == 1) {
|
||||
DValue* sz = ((Expression*)arguments->data[0])->toElem(p);
|
||||
llvm::Value* dimval = sz->getRVal();
|
||||
Type* nnt = DtoDType(ntype->next);
|
||||
if (nnt->ty == Tvoid)
|
||||
nnt = Type::tint8;
|
||||
|
||||
if (p->topexp() && p->topexp()->e2 == this) {
|
||||
assert(p->topexp()->v);
|
||||
emem = p->topexp()->v->getLVal();
|
||||
DtoNewDynArray(emem, dimval, nnt);
|
||||
inplace = true;
|
||||
}
|
||||
else {
|
||||
const llvm::Type* restype = DtoType(type);
|
||||
Logger::cout() << "restype = " << *restype << '\n';
|
||||
emem = new llvm::AllocaInst(restype,"newstorage",p->topallocapoint());
|
||||
DtoNewDynArray(emem, dimval, nnt);
|
||||
return new DVarValue(newtype, emem, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(0 && "num args to 'new' != 1");
|
||||
}
|
||||
}
|
||||
// simple new of a single non-class, non-array value
|
||||
else {
|
||||
// get runtime function
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocmemoryT");
|
||||
// get type info
|
||||
llvm::Constant* ti = DtoTypeInfoOf(newtype);
|
||||
assert(isaPointer(ti));
|
||||
// call runtime
|
||||
llvm::SmallVector<llvm::Value*,1> arg;
|
||||
arg.push_back(ti);
|
||||
emem = p->ir->CreateCall(fn, arg.begin(), arg.end(), ".gc_mem");
|
||||
}
|
||||
|
||||
if (ntype->ty == Tstruct) {
|
||||
TypeStruct* ts = (TypeStruct*)ntype;
|
||||
if (ts->isZeroInit()) {
|
||||
DtoStructZeroInit(emem);
|
||||
}
|
||||
else {
|
||||
assert(ts->sym);
|
||||
DtoStructCopy(emem,ts->sym->ir.irStruct->init);
|
||||
}
|
||||
}
|
||||
|
||||
return new DImValue(type, emem, inplace);
|
||||
*/
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -2054,55 +1994,54 @@ DValue* DeleteExp::toElem(IRState* p)
|
||||
Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
//assert(e1->type->ty != Tclass);
|
||||
DValue* dval = e1->toElem(p);
|
||||
Type* et = DtoDType(e1->type);
|
||||
|
||||
DValue* v = e1->toElem(p);
|
||||
const llvm::Type* t = DtoType(v->getType());
|
||||
llvm::Value* ldval = 0;
|
||||
llvm::Constant* z = llvm::Constant::getNullValue(t);
|
||||
|
||||
Type* e1type = DtoDType(e1->type);
|
||||
|
||||
if (e1type->ty == Tpointer) {
|
||||
llvm::Value* val = v->getRVal();
|
||||
Logger::cout() << *z << '\n';
|
||||
Logger::cout() << *val << '\n';
|
||||
new llvm::FreeInst(val, p->scopebb());
|
||||
new llvm::StoreInst(z, v->getLVal(), p->scopebb());
|
||||
// simple pointer
|
||||
if (et->ty == Tpointer)
|
||||
{
|
||||
llvm::Value* rval = dval->getRVal();
|
||||
DtoDeleteMemory(rval);
|
||||
if (dval->isVar() && dval->isVar()->lval)
|
||||
DtoStore(llvm::Constant::getNullValue(rval->getType()), dval->getLVal());
|
||||
}
|
||||
else if (e1type->ty == Tclass) {
|
||||
TypeClass* tc = (TypeClass*)e1type;
|
||||
llvm::Value* val = 0;
|
||||
if (tc->sym->dtors.dim > 0) {
|
||||
val = v->getRVal();
|
||||
DtoCallClassDtors(tc, val);
|
||||
}
|
||||
|
||||
if (DVarValue* vv = v->isVar()) {
|
||||
if (vv->var && !vv->var->onstack) {
|
||||
if (!val) val = v->getRVal();
|
||||
new llvm::FreeInst(val, p->scopebb());
|
||||
// class
|
||||
else if (et->ty == Tclass)
|
||||
{
|
||||
bool onstack = false;
|
||||
if (DVarValue* vv = dval->isVar()) {
|
||||
if (vv->var && vv->var->onstack) {
|
||||
TypeClass* tc = (TypeClass*)et;
|
||||
if (tc->sym->dtors.dim > 0) {
|
||||
DtoFinalizeClass(dval->getRVal());
|
||||
onstack = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!v->isThis())
|
||||
new llvm::StoreInst(z, v->getLVal(), p->scopebb());
|
||||
if (!onstack) {
|
||||
llvm::Value* rval = dval->getRVal();
|
||||
DtoDeleteClass(rval);
|
||||
}
|
||||
if (dval->isVar() && dval->isVar()->lval) {
|
||||
llvm::Value* lval = dval->getLVal();
|
||||
DtoStore(llvm::Constant::getNullValue(lval->getType()->getContainedType(0)), lval);
|
||||
}
|
||||
}
|
||||
else if (e1type->ty == Tarray) {
|
||||
// must be on the heap (correct?)
|
||||
llvm::Value* val = v->getRVal();
|
||||
llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
|
||||
llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
|
||||
llvm::Value* ptr = DtoGEP(val,zero,one,"tmp",p->scopebb());
|
||||
ptr = new llvm::LoadInst(ptr,"tmp",p->scopebb());
|
||||
new llvm::FreeInst(ptr, p->scopebb());
|
||||
DtoSetArrayToNull(val);
|
||||
// dyn array
|
||||
else if (et->ty == Tarray)
|
||||
{
|
||||
DtoDeleteArray(dval);
|
||||
if (!dval->isSlice())
|
||||
DtoSetArrayToNull(dval->getRVal());
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
// unknown/invalid
|
||||
else
|
||||
{
|
||||
assert(0 && "invalid delete");
|
||||
}
|
||||
|
||||
// this expression produces no useful data
|
||||
return 0;
|
||||
// no value to return
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -703,6 +703,40 @@ llvm::Value* DtoNew(Type* newtype)
|
||||
return DtoBitCast(mem, getPtrToType(DtoType(newtype)), ".gc_mem");
|
||||
}
|
||||
|
||||
void DtoDeleteMemory(llvm::Value* ptr)
|
||||
{
|
||||
// get runtime function
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delmemory");
|
||||
// build args
|
||||
llvm::SmallVector<llvm::Value*,1> arg;
|
||||
arg.push_back(DtoBitCast(ptr, getVoidPtrType(), ".tmp"));
|
||||
// call
|
||||
llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb());
|
||||
}
|
||||
|
||||
void DtoDeleteClass(llvm::Value* inst)
|
||||
{
|
||||
// get runtime function
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delclass");
|
||||
// build args
|
||||
llvm::SmallVector<llvm::Value*,1> arg;
|
||||
arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp"));
|
||||
// call
|
||||
llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb());
|
||||
}
|
||||
|
||||
void DtoDeleteArray(DValue* arr)
|
||||
{
|
||||
// get runtime function
|
||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delarray");
|
||||
// build args
|
||||
llvm::SmallVector<llvm::Value*,2> arg;
|
||||
arg.push_back(DtoArrayLen(arr));
|
||||
arg.push_back(DtoBitCast(DtoArrayPtr(arr), getVoidPtrType(), ".tmp"));
|
||||
// call
|
||||
llvm::CallInst::Create(fn, arg.begin(), arg.end(), "", gIR->scopebb());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoAssert(Loc* loc, DValue* msg)
|
||||
|
||||
@@ -61,6 +61,9 @@ llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::stri
|
||||
|
||||
// dynamic memory helpers
|
||||
llvm::Value* DtoNew(Type* newtype);
|
||||
void DtoDeleteMemory(llvm::Value* ptr);
|
||||
void DtoDeleteClass(llvm::Value* inst);
|
||||
void DtoDeleteArray(DValue* arr);
|
||||
|
||||
// assertion generator
|
||||
void DtoAssert(Loc* loc, DValue* msg);
|
||||
|
||||
@@ -760,6 +760,10 @@ tangotests/j.d
|
||||
tangotests/k.d
|
||||
tangotests/l.d
|
||||
tangotests/m.d
|
||||
tangotests/mem2.d
|
||||
tangotests/mem3.d
|
||||
tangotests/mem4.d
|
||||
tangotests/mem5.d
|
||||
tangotests/n.d
|
||||
tangotests/o.d
|
||||
tangotests/r.d
|
||||
|
||||
@@ -131,64 +131,60 @@ extern (C) Object _d_newclass(ClassInfo ci)
|
||||
return cast(Object) p;
|
||||
}
|
||||
|
||||
/+
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void _d_delinterface(void** p)
|
||||
extern (C) void _d_delinterface(void* p)
|
||||
{
|
||||
if (*p)
|
||||
if (p)
|
||||
{
|
||||
Interface* pi = **cast(Interface ***)*p;
|
||||
Object o = cast(Object)(*p - pi.offset);
|
||||
Interface* pi = **cast(Interface ***)p;
|
||||
Object o = cast(Object)(p - pi.offset);
|
||||
|
||||
_d_delclass(&o);
|
||||
*p = null;
|
||||
_d_delclass(o);
|
||||
//*p = null;
|
||||
}
|
||||
}
|
||||
|
||||
+/
|
||||
|
||||
// used for deletion
|
||||
private extern (D) alias void function(Object) fp_t;
|
||||
|
||||
/+
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void _d_delclass(Object* p)
|
||||
extern (C) void _d_delclass(Object p)
|
||||
{
|
||||
if (*p)
|
||||
if (p)
|
||||
{
|
||||
debug(PRINTF) printf("_d_delclass(%p)\n", *p);
|
||||
debug(PRINTF) printf("_d_delclass(%p)\n", p);
|
||||
|
||||
ClassInfo **pc = cast(ClassInfo **)*p;
|
||||
ClassInfo **pc = cast(ClassInfo **)p;
|
||||
if (*pc)
|
||||
{
|
||||
ClassInfo c = **pc;
|
||||
|
||||
rt_finalize(cast(void*) *p);
|
||||
rt_finalize(cast(void*) p);
|
||||
|
||||
if (c.deallocator)
|
||||
{
|
||||
fp_t fp = cast(fp_t)c.deallocator;
|
||||
(*fp)(*p); // call deallocator
|
||||
*p = null;
|
||||
(*fp)(p); // call deallocator
|
||||
//*p = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_finalize(cast(void*) *p);
|
||||
rt_finalize(cast(void*) p);
|
||||
}
|
||||
gc_free(cast(void*) *p);
|
||||
*p = null;
|
||||
gc_free(cast(void*) p);
|
||||
//*p = null;
|
||||
}
|
||||
}
|
||||
|
||||
/+
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -420,35 +416,31 @@ extern (C) void* _d_allocmemoryT(TypeInfo ti)
|
||||
return gc_malloc(ti.tsize(), (ti.flags() & 1) ? BlkAttr.NO_SCAN : 0);
|
||||
}
|
||||
|
||||
/+
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void _d_delarray(size_t plength, void* pdata)
|
||||
{
|
||||
// if (p)
|
||||
// {
|
||||
assert(!plength || pdata);
|
||||
|
||||
if (pdata)
|
||||
gc_free(pdata);
|
||||
// p.data = null;
|
||||
// p.length = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void _d_delarray(Array *p)
|
||||
extern (C) void _d_delmemory(void* p)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
assert(!p.length || p.data);
|
||||
|
||||
if (p.data)
|
||||
gc_free(p.data);
|
||||
p.data = null;
|
||||
p.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void _d_delmemory(void* *p)
|
||||
{
|
||||
if (*p)
|
||||
{
|
||||
gc_free(*p);
|
||||
*p = null;
|
||||
gc_free(p);
|
||||
//*p = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
tangotests/mem2.d
Normal file
11
tangotests/mem2.d
Normal file
@@ -0,0 +1,11 @@
|
||||
module tangotests.mem2;
|
||||
|
||||
void main()
|
||||
{
|
||||
int* ip = new int;
|
||||
assert(*ip == 0);
|
||||
*ip = 4;
|
||||
assert(*ip == 4);
|
||||
delete ip;
|
||||
assert(ip is null);
|
||||
}
|
||||
12
tangotests/mem3.d
Normal file
12
tangotests/mem3.d
Normal file
@@ -0,0 +1,12 @@
|
||||
module tangotests.mem3;
|
||||
|
||||
void main()
|
||||
{
|
||||
int[] arr;
|
||||
arr ~= [1,2,3];
|
||||
assert(arr[0] == 1);
|
||||
assert(arr[1] == 2);
|
||||
assert(arr[2] == 3);
|
||||
delete arr;
|
||||
assert(arr is null);
|
||||
}
|
||||
29
tangotests/mem4.d
Normal file
29
tangotests/mem4.d
Normal file
@@ -0,0 +1,29 @@
|
||||
module tangotests.mem4;
|
||||
|
||||
import tango.stdc.stdio;
|
||||
|
||||
class C {
|
||||
int* ptr;
|
||||
this() {
|
||||
printf("this()\n");
|
||||
ptr = new int;
|
||||
}
|
||||
~this() {
|
||||
printf("~this()\n");
|
||||
delete ptr;
|
||||
assert(ptr is null);
|
||||
}
|
||||
final void check()
|
||||
{
|
||||
printf("check()\n");
|
||||
assert(ptr !is null);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
C c = new C();
|
||||
c.check();
|
||||
delete c;
|
||||
assert(c is null);
|
||||
}
|
||||
24
tangotests/mem5.d
Normal file
24
tangotests/mem5.d
Normal file
@@ -0,0 +1,24 @@
|
||||
module tangotests.mem5;
|
||||
|
||||
class SC
|
||||
{
|
||||
int* ip;
|
||||
this()
|
||||
{
|
||||
ip = new int;
|
||||
}
|
||||
~this()
|
||||
{
|
||||
delete ip;
|
||||
}
|
||||
void check()
|
||||
{
|
||||
assert(ip !is null);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
scope sc = new SC;
|
||||
sc.check();
|
||||
}
|
||||
Reference in New Issue
Block a user