@@ -528,7 +528,7 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
528528 // Until https://github.com/Vector35/binaryninja-api/issues/5982 is fixed
529529 auto vftSize = virtualFunctions.size () * addrSize;
530530 vftBuilder.SetWidth (vftSize);
531-
531+
532532 if (baseClassInfo.has_value () && baseClassInfo->vft .has_value ())
533533 {
534534 if (baseClassInfo->vft ->virtualFunctions .size () <= virtualFunctions.size ())
@@ -572,6 +572,15 @@ std::optional<VirtualFunctionTableInfo> MicrosoftRTTIProcessor::ProcessVFT(uint6
572572 auto vFuncOffset = vFuncIdx * addrSize;
573573 // We have access to a backing function type, use it, otherwise void!
574574 auto vFuncType = vFunc.has_value () ? vFunc.value ()->GetType () : Type::VoidType ();
575+ // A pure-virtual vtable slot may point to _purecall, whose analyzed type is parameterless and
576+ // no-return. That is the type of the placeholder target, not the virtual method the slot
577+ // represents: a slot should describe the polymorphic operation, not the concrete function
578+ // currently occupying it. Propagating that type into the vtable would wrongly make dispatch
579+ // through the slot no-return. This heuristically recognizes the characteristic _purecall shape
580+ // (empty parameters, no-return) and treats it as unknown; it does not prove the target is
581+ // _purecall.
582+ if (vFuncType && vFuncType->GetClass () == FunctionTypeClass && vFuncType->GetParameters ().empty () && !vFuncType->CanReturn ().GetValue ())
583+ vFuncType = Type::VoidType ();
575584 vftBuilder.AddMemberAtOffset (
576585 Type::PointerType (addrSize, vFuncType, true ), vFuncName, vFuncOffset);
577586 vFuncIdx++;
0 commit comments