-
Notifications
You must be signed in to change notification settings - Fork 31
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
Fixed ExtractAddress causing Segmentation fault if it received None object. (#481) #482
base: master
Are you sure you want to change the base?
Fixed ExtractAddress causing Segmentation fault if it received None object. (#481) #482
Conversation
I don't think this should raise unless |
I thought the same thing at first, but there is one thing that clearly breaks consistency, and that is when you override the hooked function. from entities.hooks import EntityCondition, EntityPreHook
@EntityPreHook(EntityCondition.is_player, 'give_named_item')
def pre_give_named_item(args):
return None # None cannot override the function, nor can it return NULL. And those who do not clearly know the following behavior will create unnecessary confusion, unable to understand why None returns NULL elsewhere, but not with a function override. Source.Python/src/core/modules/memory/memory_hooks.cpp Lines 129 to 132 in bcea09e
|
That's a callback, not a function. And that's by design, because When you call any functions exported from C++, Moreover, you are likely to get the same crash if |
I am not talking about the callback, I'm talking about the function that is expected to return DataType.POINTER, If NULL exists to serve as NULL, then everything should align with NULL. If not, then why does NULL exist?
|
It's by design. Calling a Python function that does not return anything, for example: def pre_give_named_item(args):
do_whatever_but_does_not_return_anything() Automatically return Regardless, there is a clear distinction between a function and a callback. When EDIT: As mentioned above, this crash: class Foo:
def _ptr(self):
return None
ptr.set_pointer(Foo()) # Crash This is inconsistent: ptr.set_string_pointer(None) # Work
ptr.set_pointer(None) # ValueError: None was passed, expected Pointer(0) or NULL. This is also inconsistent: player.give_named_item('weapon_awp', econ_item_view=None) # Work
@EntityPreHook(EntityCondition.is_player, 'give_named_item')
def pre_give_named_item(args):
args[3] = None # ValueError: None was passed, expected Pointer(0) or NULL. Etc. The fix for this should really be as simple as ensuring inline unsigned long ExtractAddress(object oPtr, bool bValidate = false)
{
CPointer* pPtr;
extract<CPointer *> extractor(oPtr);
if (!extractor.check())
{
oPtr = oPtr.attr(GET_PTR_NAME)();
pPtr = extract<CPointer *>(oPtr);
}
else
{
pPtr = extractor();
}
if (!pPtr)
{
if (bValidate)
BOOST_RAISE_EX...
else
return 0;
}
if (bValidate)
pPtr->Validate();
return pPtr->m_ulAddr;
} The same should also be done there: Source.Python/src/core/sp_python.cpp Lines 339 to 340 in 12a24f4
|
It is not by design, both are just compromises made due to the constraints imposed by The function arguments provided by make_object(Vector, None) # Crash!
Entity.create(None) # Crash!
ptr.set_string_array(None) # Crash! It should be considered an exception to the function provided by Boost.Python and should not get users into the habit of setting NULL with None. NULL should be used in situations where NULL(Pointer(0)) can be used. |
#481