-
Notifications
You must be signed in to change notification settings - Fork 37
Add default convention to CallingConvention. #344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Ayuto
merged 24 commits into
Source-Python-Dev-Team:master
from
CookStar:add_default_callingconvention
Dec 11, 2020
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
3d0d875
Added default convention to ICallingConvention.
CookStar fb87d77
Changed constructor to create the default convention from MakeDynamic…
CookStar f2c403c
Removed "ICallingConventionWrapper *" from the held type.
CookStar 025a421
Fixed removal of setting null.
CookStar dd295d3
Changed m_pCallingConvention to m_pDefaultCallingConvention.
CookStar f39a6c4
Simplified CFunction destructor.
CookStar adbc65a
Fixed a crash introduced by removing "ICallingConventionWrapper *".
CookStar f3aa765
Removed the convention headers.
CookStar 854d96f
Fixed a crash on unloading Source.Python.
CookStar f275acc
Fix for VC++ 2010.
CookStar c47ca12
Fix2 for VC++ 2010.
CookStar 1ae3f1d
Merge branch 'master' into add_default_callingconvention
CookStar 0062175
Added an overload for C-type functions to CFunction::AddHook.
CookStar 3c4935b
Resolved conflicts.
CookStar 8aab63b
Fixed CallingConvention's leaks/issues.
jordanbriere 6b68369
Minor fixes.
jordanbriere 118070b
Merge pull request #2 from jordanbriere/add_default_callingconvention
CookStar b4cb2c0
Modified CFunction to initialize CallingConvention with default_conve…
CookStar 121a496
Added custom_convention(m_oCallingConvention) attribute to Function.
CookStar 282bf03
Added post-construction initialization support.
jordanbriere 6d26bca
Fixed built-in conventions leaking when they are being unhooked while…
jordanbriere 98d9853
Replaced the post-construction wrapper with stackable policies.
jordanbriere 958cb03
Merge pull request #3 from jordanbriere/add_default_callingconvention
CookStar f651f57
Fixed namespace issue.
CookStar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,14 @@ | |
// ============================================================================ | ||
// DynamicHooks | ||
#include "convention.h" | ||
#include "conventions/x86MsCdecl.h" | ||
#include "conventions/x86MsThiscall.h" | ||
#include "conventions/x86MsStdcall.h" | ||
#include "conventions/x86GccCdecl.h" | ||
#include "conventions/x86GccThiscall.h" | ||
|
||
// Memory | ||
#include "memory_function.h" | ||
|
||
// Utilities | ||
#include "memory_utilities.h" | ||
|
@@ -48,14 +56,55 @@ using namespace boost::python; | |
class ICallingConventionWrapper: public ICallingConvention, public wrapper<ICallingConvention> | ||
{ | ||
public: | ||
ICallingConventionWrapper(object oArgTypes, DataType_t returnType, int iAlignment=4) | ||
ICallingConventionWrapper(object oArgTypes, DataType_t returnType, int iAlignment=4, Convention_t eDefaultConv=CONV_CUSTOM) | ||
:ICallingConvention(ObjectToDataTypeVector(oArgTypes), returnType, iAlignment) | ||
{ | ||
#ifdef _WIN32 | ||
switch (eDefaultConv) | ||
{ | ||
case CONV_CUSTOM: | ||
break; | ||
case CONV_CDECL: | ||
m_pCallingConvention = new x86MsCdecl(m_vecArgTypes, m_returnType, m_iAlignment); | ||
break; | ||
case CONV_THISCALL: | ||
m_pCallingConvention = new x86MsThiscall(m_vecArgTypes, m_returnType, m_iAlignment); | ||
break; | ||
case CONV_STDCALL: | ||
m_pCallingConvention = new x86MsStdcall(m_vecArgTypes, m_returnType, m_iAlignment); | ||
break; | ||
default: | ||
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unsupported calling convention.") | ||
} | ||
#else | ||
switch (eDefaultConv) | ||
{ | ||
case CONV_CUSTOM: | ||
break; | ||
case CONV_CDECL: | ||
m_pCallingConvention = new x86GccCdecl(m_vecArgTypes, m_returnType, m_iAlignment); | ||
break; | ||
case CONV_THISCALL: | ||
m_pCallingConvention = new x86GccThiscall(m_vecArgTypes, m_returnType, m_iAlignment); | ||
break; | ||
default: | ||
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unsupported calling convention.") | ||
} | ||
#endif | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed! fb87d77 |
||
|
||
~ICallingConventionWrapper() | ||
{ | ||
delete m_pCallingConvention; | ||
m_pCallingConvention = nullptr; | ||
} | ||
|
||
virtual std::list<Register_t> GetRegisters() | ||
{ | ||
override get_registers = get_override("get_registers"); | ||
if (!get_registers && m_pCallingConvention) { | ||
return m_pCallingConvention->GetRegisters(); | ||
} | ||
CHECK_OVERRIDE(get_registers); | ||
|
||
object registers = get_registers(); | ||
|
@@ -71,47 +120,60 @@ class ICallingConventionWrapper: public ICallingConvention, public wrapper<ICall | |
virtual int GetPopSize() | ||
{ | ||
override get_pop_size = get_override("get_pop_size"); | ||
if (!get_pop_size && m_pCallingConvention) { | ||
return m_pCallingConvention->GetPopSize(); | ||
} | ||
CHECK_OVERRIDE(get_pop_size); | ||
|
||
return get_pop_size(); | ||
} | ||
|
||
virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters) | ||
{ | ||
CPointer* ptr = extract<CPointer*>(GetArgumentPtrWrapper(iIndex, pRegisters)); | ||
return (void *) ptr->m_ulAddr; | ||
} | ||
|
||
object GetArgumentPtrWrapper(int iIndex, CRegisters* pRegisters) | ||
virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters) | ||
{ | ||
override get_argument_ptr = get_override("get_argument_ptr"); | ||
if (!get_argument_ptr && m_pCallingConvention) { | ||
return m_pCallingConvention->GetArgumentPtr(iIndex, pRegisters); | ||
} | ||
CHECK_OVERRIDE(get_argument_ptr); | ||
return get_argument_ptr(iIndex, ptr(pRegisters)); | ||
|
||
object argument_ptr = get_argument_ptr(iIndex, ptr(pRegisters)); | ||
CPointer* _ptr = extract<CPointer*>(argument_ptr); | ||
return (void *) _ptr->m_ulAddr; | ||
} | ||
|
||
virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) | ||
{ | ||
override argument_ptr_changed = get_override("argument_ptr_changed"); | ||
if (!argument_ptr_changed && m_pCallingConvention) { | ||
m_pCallingConvention->ArgumentPtrChanged(iIndex, pRegisters, pArgumentPtr); | ||
return; | ||
} | ||
CHECK_OVERRIDE(argument_ptr_changed); | ||
argument_ptr_changed(iIndex, ptr(pRegisters), CPointer((unsigned long) pArgumentPtr)); | ||
} | ||
|
||
virtual void* GetReturnPtr(CRegisters* pRegisters) | ||
{ | ||
CPointer* ptr = extract<CPointer*>(GetReturnPtrWrapper(pRegisters)); | ||
return (void *) ptr->m_ulAddr; | ||
} | ||
|
||
object GetReturnPtrWrapper(CRegisters* pRegisters) | ||
{ | ||
override get_return_ptr = get_override("get_return_ptr"); | ||
CHECK_OVERRIDE(get_return_ptr); | ||
return get_return_ptr(ptr(pRegisters)); | ||
if (!get_return_ptr && m_pCallingConvention) { | ||
return m_pCallingConvention->GetReturnPtr(pRegisters); | ||
} | ||
CHECK_OVERRIDE(get_return_ptr) | ||
|
||
object return_ptr = get_return_ptr(ptr(pRegisters)); | ||
CPointer* _ptr = extract<CPointer*>(return_ptr); | ||
return (void *) _ptr->m_ulAddr; | ||
} | ||
|
||
virtual void ReturnPtrChanged(CRegisters* pRegisters, void* pReturnPtr) | ||
{ | ||
override return_ptr_changed = get_override("return_ptr_changed"); | ||
if (!return_ptr_changed && m_pCallingConvention) { | ||
m_pCallingConvention->ReturnPtrChanged(pRegisters, pReturnPtr); | ||
return; | ||
} | ||
CHECK_OVERRIDE(return_ptr_changed); | ||
|
||
return_ptr_changed(ptr(pRegisters), CPointer((unsigned long) pReturnPtr)); | ||
} | ||
|
||
|
@@ -125,6 +187,9 @@ class ICallingConventionWrapper: public ICallingConvention, public wrapper<ICall | |
|
||
return tuple(argumentTypes); | ||
} | ||
|
||
public: | ||
ICallingConvention* m_pCallingConvention = nullptr; | ||
}; | ||
|
||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this part is required. Boost should take care of deleting it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, m_oCallingConvention will never be released, so it needs to Py_DECREF to release it when function is unhooked.
Source.Python/src/core/modules/memory/memory_function.cpp
Lines 158 to 166 in 3d0d875
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Py_DECREF call is valid, but I actually meant the rest.
m_oCallingConvention
is created by Boost and when the reference counter reaches 0, Boost will take care of deleting its C++ instance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my initial tests, Boost.Python did not call the destructor.
Also, in the test to verify the behavior, the destructor was not called if a pointer was passed to class_.
C++:
Python:
Output:
I looked at the behavior of passing a pointer to class_ in the Boost.Python documentation and code, but I couldn't find a definitive answer.
I assumed that object's call policy would act like reference_existing_object when passing a pointer to class_, is this not the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not fully sure why we added
ICallingConventionWrapper *
as the held type. I guess this was done to have full control over the deletion of the C++ instance.I would remove the held type and make sure we decref only the instances that are not used by DynamicHooks.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a little question, why are you checking
ICallingConventionWrapper
here?https://github.com/jordanbriere/Source.Python/blob/6d26bca14429b498e5862ccbbfbae57fd0bb7c8a/src/core/modules/memory/memory_function.cpp#L199-L200
I understand completely now, I think this is the proper implementation.
For the record, in the first implementation, instead of using the existing
ICallingConventionWrapper
, I made a separate class template forICallingConvention
and created a class that inherits the default Calling Convention(x86MsCdecl
, etc.). However, I thought that the binary would become too big for the functionality, so I implemented it as it is now, but I think this post-construction initialization is a necessary feature in any case.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking
m_eCallingConvention
should be enough, but since it is declared as public, it could end up being externally mutated at some point which would potentially introduce hard to diagnose issues if the convention is being managed by both;DeleteHook
andICallingConventionWrapper
. Thedynamic_cast
really just add extra security to ensure we are indeed working with a built-in convention.Yes, I think this is a great addition in general. Though I don't really like the current implementation as it adds an extra layer and force us to re-pack the arguments twice. I think stackable policies could probably be better. 🤔
EDIT: This sure sounds like a better approach: 98d9853
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay.
Nice! One small error is that in my environment, I get an ambiguous error if I don't have boost::python with
detail
andmake_tuple
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to add them, it is likely an header that includes
wrap_macros.h
while also including [in]directly from aboost/python/detail/*
's file that defines into thedetail
scope consequently clashing with ourusing nam...
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okey. f651f57
I think the default convention now works perfectly! Thank you @jordanbriere!