self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('i'))
self.assertGreaterEqual(struct.calcsize('n'), struct.calcsize('P'))
+ def test_cache_bytes_vs_str_bb(self):
+ # Mixing str and bytes formats must not raise BytesWarning under -bb.
+ code = (
+ 'import struct\n'
+ 'struct.calcsize(b"!d"); struct.calcsize("!d")\n'
+ 'struct.calcsize(">d"); struct.calcsize(b">d")\n'
+ 'struct.Struct(b"i"); struct.Struct("i")\n'
+ )
+ assert_python_ok('-bb', '-c', code)
+
def test_integers(self):
# Integer tests (bBhHiIlLqQnN).
import binascii
static int
cache_struct_converter(PyObject *module, PyObject *fmt, PyStructObject **ptr)
{
- PyObject * s_object;
+ PyObject *s_object;
+ PyObject *key;
_structmodulestate *state = get_struct_state(module);
if (fmt == NULL) {
return 1;
}
- if (PyDict_GetItemRef(state->cache, fmt, &s_object) < 0) {
+ /* Use a str cache key: an equal str and bytes would collide and be
+ compared, raising BytesWarning under -bb. */
+ if (PyBytes_Check(fmt)) {
+ key = PyUnicode_DecodeASCII(PyBytes_AS_STRING(fmt),
+ PyBytes_GET_SIZE(fmt), "surrogateescape");
+ if (key == NULL) {
+ return 0;
+ }
+ }
+ else {
+ key = Py_NewRef(fmt);
+ }
+
+ if (PyDict_GetItemRef(state->cache, key, &s_object) < 0) {
+ Py_DECREF(key);
return 0;
}
if (s_object != NULL) {
+ Py_DECREF(key);
*ptr = PyStructObject_CAST(s_object);
return Py_CLEANUP_SUPPORTED;
}
- s_object = PyObject_CallOneArg(state->PyStructType, fmt);
+ s_object = PyObject_CallOneArg(state->PyStructType, key);
if (s_object != NULL) {
if (PyDict_GET_SIZE(state->cache) >= MAXCACHE)
PyDict_Clear(state->cache);
/* Attempt to cache the result */
- if (PyDict_SetItem(state->cache, fmt, s_object) == -1)
+ if (PyDict_SetItem(state->cache, key, s_object) == -1)
PyErr_Clear();
+ Py_DECREF(key);
*ptr = (PyStructObject *)s_object;
return Py_CLEANUP_SUPPORTED;
}
+ Py_DECREF(key);
return 0;
}