Fix segfault via strcmp(NULL) in numpy type detection

When PyObject_GetAttrString returns NULL (e.g., because __name__ or __module__ attribute access raises an exception on metaclass), PyUpb_GetStrData returns NULL. Passing NULL to strcmp previously caused a segmentation fault.

Check for NULL before calling PyUpb_GetStrData and strcmp, and call PyErr_Clear() when attribute lookup fails.

PiperOrigin-RevId: 938039167
This commit is contained in:
Runze Wang 2026-06-25 09:50:20 -07:00 committed by Copybara-Service
parent 089805f3ae
commit ae4f98fe70
3 changed files with 35 additions and 8 deletions

View file

@ -395,6 +395,21 @@ class MessageFactoryTest(unittest.TestCase):
self.assertEqual('hello', values[0].key)
self.assertEqual('welcome', values[0].value)
def testConvertNumpyDetectionNullAttribute(self):
class NamelessMeta(type):
def __getattribute__(cls, name):
if name == '__name__' or name == '__module__':
raise AttributeError('no attribute')
return super().__getattribute__(name)
class Nameless(metaclass=NamelessMeta):
def __index__(self):
return 42
msg = factory_test1_pb2.Factory1Message()
msg.scalar_value = Nameless()
self.assertEqual(msg.scalar_value, 42)
if __name__ == '__main__':
unittest.main()

View file

@ -121,8 +121,8 @@ class BoolValueChecker(object):
if not hasattr(proposed_value, '__index__'):
# Under NumPy 2.3, numpy.bool does not have an __index__ method.
if (
type(proposed_value).__module__ == 'numpy'
and type(proposed_value).__name__ == 'bool'
getattr(type(proposed_value), '__module__', None) == 'numpy'
and getattr(type(proposed_value), '__name__', None) == 'bool'
):
return bool(proposed_value)
message = '%.1024r has type %s, but expected one of: %s' % (
@ -133,8 +133,8 @@ class BoolValueChecker(object):
raise TypeError(message)
if (
type(proposed_value).__module__ == 'numpy'
and type(proposed_value).__name__ == 'ndarray'
getattr(type(proposed_value), '__module__', None) == 'numpy'
and getattr(type(proposed_value), '__name__', None) == 'ndarray'
):
message = '%.1024r has type %s, but expected one of: %s' % (
proposed_value,
@ -166,8 +166,8 @@ class IntValueChecker(object):
raise TypeError(message)
if not hasattr(proposed_value, '__index__') or (
type(proposed_value).__module__ == 'numpy'
and type(proposed_value).__name__ == 'ndarray'
getattr(type(proposed_value), '__module__', None) == 'numpy'
and getattr(type(proposed_value), '__name__', None) == 'ndarray'
):
message = '%.1024r has type %s, but expected one of: %s' % (
proposed_value,
@ -301,8 +301,8 @@ class DoubleValueChecker(object):
not hasattr(proposed_value, '__float__')
and not hasattr(proposed_value, '__index__')
) or (
type(proposed_value).__module__ == 'numpy'
and type(proposed_value).__name__ == 'ndarray'
getattr(type(proposed_value), '__module__', None) == 'numpy'
and getattr(type(proposed_value), '__name__', None) == 'ndarray'
):
message = '%.1024r has type %s, but expected one of: int, float' % (
proposed_value,