From 65ee34e37b4decd37c8b85a25f6c36fcaf20f0fb Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 23 Oct 2024 10:36:27 -0400 Subject: [PATCH] Added object access check to delegate invocation --- BeefLibs/corlib/src/Delegate.bf | 8 +++++ IDE/dist/BeefDbgVis.toml | 4 +-- IDE/src/ui/BreakpointPanel.bf | 5 +++ IDEHelper/Compiler/BfExprEvaluator.cpp | 13 ++++++- IDEHelper/Compiler/BfModule.cpp | 47 ++++++++++++++++++++++++-- IDEHelper/Compiler/BfModule.h | 1 + IDEHelper/DbgExprEvaluator.cpp | 17 ++++++++-- IDEHelper/Tests/src/FuncRefs.bf | 4 +-- 8 files changed, 89 insertions(+), 10 deletions(-) diff --git a/BeefLibs/corlib/src/Delegate.bf b/BeefLibs/corlib/src/Delegate.bf index c587261b..c10427f9 100644 --- a/BeefLibs/corlib/src/Delegate.bf +++ b/BeefLibs/corlib/src/Delegate.bf @@ -31,7 +31,11 @@ namespace System public void* GetTarget() { +#if BF_64_BIT && BF_ENABLE_OBJECT_DEBUG_FLAGS + return (.)((int)mTarget & 0x7FFFFFFF'FFFFFFFF); +#else return mTarget; +#endif } public void SetFuncPtr(void* ptr, void* target = null) @@ -43,7 +47,11 @@ namespace System protected override void GCMarkMembers() { // Note- this is safe even if mTarget is not an object, because the GC does object address validation +#if BF_64_BIT && BF_ENABLE_OBJECT_DEBUG_FLAGS + GC.Mark(Internal.UnsafeCastToObject((.)((int)mTarget & 0x7FFFFFFF'FFFFFFFF))); +#else GC.Mark(Internal.UnsafeCastToObject(mTarget)); +#endif } public int GetHashCode() diff --git a/IDE/dist/BeefDbgVis.toml b/IDE/dist/BeefDbgVis.toml index ddde0d0f..94b42a37 100644 --- a/IDE/dist/BeefDbgVis.toml +++ b/IDE/dist/BeefDbgVis.toml @@ -23,11 +23,11 @@ ValuePointer = "/*(mMethodId < 0) ? &this :*/ __cast(\"_BF_DeferredData_\", mMet Name = "System.Event<*>" DisplayString = "{{ data={__cast(\"System.Object\", mData & sDataMask)} }}" [[Type.Expand.Item]] -Name = "[target]" +Name = "[Target]" Value = "__cast(\"System.Object\", mData)" Condition = "(mData & sIsEnumerating) == 0" [[Type.Expand.Item]] -Name = "[target]" +Name = "[Target]" Value = "((System.Event<$T1>.Enumerator*)(mData & sDataMask)).mTarget" Condition = "(mData & sIsEnumerating) != 0" [[Type.Expand.Item]] diff --git a/IDE/src/ui/BreakpointPanel.bf b/IDE/src/ui/BreakpointPanel.bf index 63ab3a9b..567a19e6 100644 --- a/IDE/src/ui/BreakpointPanel.bf +++ b/IDE/src/ui/BreakpointPanel.bf @@ -90,6 +90,11 @@ namespace IDE.ui SetScaleData(); } + public ~this() + { + IDEApp.sApp.mDebugger.mBreakpointsChangedDelegate.Remove(scope => BreakpointsChanged, true); + } + void SetScaleData() { mListView.mIconX = GS!(4); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index c46831ac..2820902f 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -14031,7 +14031,18 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) if ((implicitParamCount > 0) || (needsSplat)) // Point back to self, it contains capture data valPtr = mModule->mBfIRBuilder->CreateBitCast(mResult.mValue, mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr)); else if (bindResult.mTarget) - valPtr = mModule->mBfIRBuilder->CreateBitCast(target.mValue, mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr)); + { + if ((target.mType->IsObjectOrInterface()) && + (mModule->mCompiler->mOptions.mObjectHasDebugFlags) && (!mModule->mIsComptimeModule) && + (mModule->mCompiler->mSystem->mPtrSize == 8)) + { + auto numVal = mModule->mBfIRBuilder->CreatePtrToInt(target.mValue, BfTypeCode_UInt64); + auto orVal = mModule->mBfIRBuilder->CreateOr(numVal, mModule->mBfIRBuilder->CreateConst(BfTypeCode_UInt64, 0x8000000000000000ULL)); + valPtr = mModule->mBfIRBuilder->CreateIntToPtr(orVal, mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr)); + } + else + valPtr = mModule->mBfIRBuilder->CreateBitCast(target.mValue, mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr)); + } else valPtr = mModule->GetDefaultValue(mModule->GetPrimitiveType(BfTypeCode_NullPtr)); auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(baseDelegate, 0, 2); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index efd274bb..d55a2475 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -10472,6 +10472,24 @@ void BfModule::SkipObjectAccessCheck(BfTypedValue typedVal) mCurMethodState->mSkipObjectAccessChecks.Add(typedVal.mValue.mId); } +bool BfModule::WantsObjectAccessCheck(BfType* type) +{ + if ((mBfIRBuilder->mIgnoreWrites) || (!type->IsObjectOrInterface()) || (mCurMethodState == NULL) || (mCurMethodState->mIgnoreObjectAccessCheck)) + return false; + + if ((!mCompiler->mOptions.mObjectHasDebugFlags) || (mIsComptimeModule)) + return false; + + bool emitObjectAccessCheck = mCompiler->mOptions.mEmitObjectAccessCheck; + auto typeOptions = GetTypeOptions(); + if (typeOptions != NULL) + emitObjectAccessCheck = typeOptions->Apply(emitObjectAccessCheck, BfOptionFlags_EmitObjectAccessCheck); + if (!emitObjectAccessCheck) + return false; + + return true; +} + void BfModule::EmitObjectAccessCheck(BfTypedValue typedVal) { if ((mBfIRBuilder->mIgnoreWrites) || (!typedVal.mType->IsObjectOrInterface()) || (mCurMethodState == NULL) || (mCurMethodState->mIgnoreObjectAccessCheck)) @@ -16754,13 +16772,38 @@ void BfModule::CreateDelegateInvokeMethod() BfIRValue staticResult; auto callingConv = GetIRCallingConvention(mCurMethodInstance); - + auto trueEndBB = trueBB; + /// Non-static invocation { auto memberFuncPtr = mBfIRBuilder->GetPointerTo(mBfIRBuilder->MapMethod(mCurMethodInstance)); auto memberFuncPtrPtr = mBfIRBuilder->GetPointerTo(memberFuncPtr); mBfIRBuilder->SetInsertPoint(trueBB); + + BfIRValue numVal; + if ((mCompiler->mOptions.mObjectHasDebugFlags) && (!mIsComptimeModule) && (mCompiler->mSystem->mPtrSize == 8)) + { + numVal = mBfIRBuilder->CreatePtrToInt(fieldVal, BfTypeCode_UInt64); + auto andVal = mBfIRBuilder->CreateAnd(numVal, mBfIRBuilder->CreateConst(BfTypeCode_UInt64, ~0x8000000000000000ULL)); + fieldVal = andVal; + } + + if ((WantsObjectAccessCheck(mContext->mBfObjectType) && (mCompiler->mSystem->mPtrSize == 8))) + { + auto oacDoBB = mBfIRBuilder->CreateBlock("oac.do", true); + auto oacDoneBB = mBfIRBuilder->CreateBlock("oac.done"); + + auto checkGTE = mBfIRBuilder->CreateCmpGTE(numVal, mBfIRBuilder->CreateConst(BfTypeCode_UInt64, 0x8000000000000000ULL), false); + mBfIRBuilder->CreateCondBr(checkGTE, oacDoBB, oacDoneBB); + mBfIRBuilder->SetInsertPoint(oacDoBB); + mBfIRBuilder->CreateObjectAccessCheck(fieldVal, !IsOptimized()); + mBfIRBuilder->CreateBr(oacDoneBB); + mBfIRBuilder->AddBlock(oacDoneBB); + mBfIRBuilder->SetInsertPoint(oacDoneBB); + trueEndBB = oacDoneBB; + } + memberFuncArgs[thisIdx] = mBfIRBuilder->CreateBitCast(fieldVal, mBfIRBuilder->MapType(mCurTypeInstance)); auto fieldPtr = mBfIRBuilder->CreateInBoundsGEP(multicastDelegate, 0, 1); // Load 'delegate.mFuncPtr' auto funcPtrPtr = mBfIRBuilder->CreateBitCast(fieldPtr, memberFuncPtrPtr); @@ -16829,7 +16872,7 @@ void BfModule::CreateDelegateInvokeMethod() else loweredIRReturnType = mBfIRBuilder->MapType(mCurMethodInstance->mReturnType); auto phi = mBfIRBuilder->CreatePhi(loweredIRReturnType, 2); - mBfIRBuilder->AddPhiIncoming(phi, nonStaticResult, trueBB); + mBfIRBuilder->AddPhiIncoming(phi, nonStaticResult, trueEndBB); mBfIRBuilder->AddPhiIncoming(phi, staticResult, falseBB); mBfIRBuilder->CreateRet(phi); } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index f0bee551..4b97c07e 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1746,6 +1746,7 @@ public: bool HasCompiledOutput(); bool HasExecutedOutput(); void SkipObjectAccessCheck(BfTypedValue typedVal); + bool WantsObjectAccessCheck(BfType* type); void EmitObjectAccessCheck(BfTypedValue typedVal); bool WantsDebugHelpers(); void EmitEnsureInstructionAt(); diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index e74726e5..786604fa 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -7739,9 +7739,20 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue else if (methodName == "__funcTarget") { if (argValues.size() == 2) - { + { + auto funcTargetTyped = argValues[1]; + if ((sizeof(addr_target) == 8) && ((funcTargetTyped.mPtr & 0x8000000000000000LL) != 0)) + { + auto objectType = mDbgModule->FindType("System.Object", NULL, DbgLanguage_BeefUnfixed); + if (objectType != NULL) + objectType = mDbgModule->GetPointerType(objectType); + funcTargetTyped.mPtr &= 0x7FFFFFFFFFFFFFFFLL; + if (objectType != NULL) + funcTargetTyped.mType = objectType; + } + auto funcPtr = argValues[0].mPtr; - auto funcTarget = argValues[1].mPtr; + auto funcTarget = funcTargetTyped.mPtr; String symbolName; addr_target offset; @@ -7762,7 +7773,7 @@ DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue } } - return argValues[1]; + return funcTargetTyped; } } else if (methodName == "__stringView") diff --git a/IDEHelper/Tests/src/FuncRefs.bf b/IDEHelper/Tests/src/FuncRefs.bf index 961915ba..f1ecf2b5 100644 --- a/IDEHelper/Tests/src/FuncRefs.bf +++ b/IDEHelper/Tests/src/FuncRefs.bf @@ -408,10 +408,10 @@ namespace Tests Test.Assert(a == 10+10 + 30); Test.Assert(mA == 100+300+300 + 300); - bind.Dispose(); - Test.Assert(Use(scope => dlg, 10) == 400); + bind.Dispose(); + function int(int num) func = => StaticMethod; Test.Assert(Use(=> StaticMethod, 123) == 1123); Test.Assert(Use(func, 123) == 1123);