8000 BUG: revert view safety checks · jaimefrio/numpy@aaa6579 · GitHub
[go: up one dir, main page]

Skip to content

Commit aaa6579

Browse files
ahaldanejaimefrio
authored andcommitted
BUG: revert view safety checks
Because of slowdowns caused by the view safety checks introduced in numpy#5548 they are removed here for 1.10. The plan is to reintroduce a better version of the checks in 1.11.
1 parent 19d3ba1 commit aaa6579

File tree

1 file changed

+13
-124
lines changed

1 file changed

+13
-124
lines changed

numpy/core/_internal.py

Lines changed: 13 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -306,94 +306,6 @@ def _copy_fields(ary):
306306
'formats': [dt.fields[name][0] for name in dt.names]}
307307
return array(ary, dtype=copy_dtype, copy=True)
308308

309-
def _get_all_field_offsets(dtype, base_offset=0):
310-
""" Returns the types and offsets of all fields in a (possibly structured)
311-
data type, including nested fields and subarrays.
312-
313-
Parameters
314-
----------
315-
dtype : data-type
316-
Data type to extract fields from.
317-
base_offset : int, optional
318-
Additional offset to add to all field offsets.
319-
320-
Returns
321-
-------
322-
fields : list of (data-type, int) pairs
323-
A flat list of (dtype, byte offset) pairs.
324-
325-
"""
326-
fields = []
327-
if dtype.fields is not None:
328-
for name in dtype.names:
329-
sub_dtype = dtype.fields[name][0]
330-
sub_offset = dtype.fields[name][1] + base_offset
331-
fields.extend(_get_all_field_offsets(sub_dtype, sub_offset))
332-
else:
333-
if dtype.shape:
334-
sub_offsets = _get_all_field_offsets(dtype.base, base_offset)
335-
count = 1
336-
for dim in dtype.shape:
337-
count *= dim
338-
fields.extend((typ, off + dtype.base.itemsize*j)
339-
for j in range(count) for (typ, off) in sub_offsets)
340-
else:
341-
fields.append((dtype, base_offset))
342-
return fields
343-
344-
def _check_field_overlap(new_fields, old_fields):
345-
""" Perform object memory overlap tests for two data-types (see
346-
_view_is_safe).
347-
348-
This function checks that new fields only access memory contained in old
349-
fields, and that non-object fields are not interpreted as objects and vice
350-
versa.
351-
352-
Parameters
353-
----------
354-
new_fields : list of (data-type, int) pairs
355-
Flat list of (dtype, byte offset) pairs for the new data type, as
356-
returned by _get_all_field_offsets.
357-
old_fields: list of (data-type, int) pairs
358-
Flat list of (dtype, byte offset) pairs for the old data type, as
359-
returned by _get_all_field_offsets.
360-
361-
Raises
362-
------
363-
TypeError
364-
If the new fields are incompatible with the old fields
365-
366-
"""
367-
368-
#first go byte by byte and check we do not access bytes not in old_fields
369-
new_bytes = set()
370-
for tp, off in new_fields:
371-
new_bytes.update(set(range(off, off+tp.itemsize)))
372-
old_bytes = set()
373-
for tp, off in old_fields:
374-
old_bytes.update(set(range(off, off+tp.itemsize)))
375-
if new_bytes.difference(old_bytes):
376-
raise TypeError("view would access data parent array doesn't own")
377-
378-
#next check that we do not interpret non-Objects as Objects, and vv
379-
obj_offsets = [off for (tp, off) in old_fields if tp.type is object_]
380-
obj_size = dtype(object_).itemsize
381-
382-
for fld_dtype, fld_offset in new_fields:
383-
if fld_dtype.type is object_:
384-
# check we do not create object views where
385-
# there are no objects.
386-
if fld_offset not in obj_offsets:
387-
raise TypeError("cannot view non-Object data as Object type")
388-
else:
389-
# next check we do not create non-object views
390-
# where there are already objects.
391-
# see validate_object_field_overlap for a similar computation.
392-
for obj_offset in obj_offsets:
393-
if (fld_offset < obj_offset + obj_size and
394-
obj_offset < fld_offset + fld_dtype.itemsize):
395-
raise TypeError("cannot view Object as non-Object type")
396-
397309
def _getfield_is_safe(oldtype, newtype, offset):
398310
""" Checks safety of getfield for object arrays.
399311
@@ -415,24 +327,23 @@ def _getfield_is_safe(oldtype, newtype, offset):
415327
If the field access is invalid
416328
417329
"""
418-
new_fields = _get_all_field_offsets(newtype, offset)
419-
old_fields = _get_all_field_offsets(oldtype)
420-
# raises if there is a problem
421-
_check_field_overlap(new_fields, old_fields)
330+
if newtype.hasobject or oldtype.hasobject:
331+
if offset == 0 and newtype == oldtype:
332+
return
333+
if oldtype.names:
334+
for name in oldtype.names:
335+
if (oldtype.fields[name][1] == offset and
336+
oldtype.fields[name][0] == newtype):
337+
return
338+
raise TypeError("Cannot get/set field of an object array")
339+
return
422340

423341
def _view_is_safe(oldtype, newtype):
424342
""" Checks safety of a view involving object arrays, for example when
425343
doing::
426344
427345
np.zeros(10, dtype=oldtype).view(newtype)
428346
429-
We need to check that
430-
1) No memory that is not an object will be interpreted as a object,
431-
2) No memory containing an object will be interpreted as an arbitrary type.
432-
Both cases can cause segfaults, eg in the case the view is written to.
433-
Strategy here is to also disallow views where newtype has any field in a
434-
place oldtype doesn't.
435-
436347
Parameters
437348
----------
438349
oldtype : data-type
@@ -452,31 +363,9 @@ def _view_is_safe(oldtype, newtype):
452363
if oldtype == newtype:
453364
return
454365

455-
new_fields = _get_all_field_offsets(newtype)
456-
new_size = newtype.itemsize
457-
458-
old_fields = _get_all_field_offsets(oldtype)
459-
old_size = oldtype.itemsize
460-
461-
# if the itemsizes are not equal, we need to check that all the
462-
# 'tiled positions' of the object match up. Here, we allow
463-
# for arbirary itemsizes (even those possibly disallowed
464-
# due to stride/data length issues).
465-
if old_size == new_size:
466-
new_num = old_num = 1
467-
else:
468-
gcd_new_old = _gcd(new_size, old_size)
469-
new_num = old_size // gcd_new_old
470-
old_num = new_size // gcd_new_old
471-
472-
# get position of fields within the tiling
473-
new_fieldtile = [(tp, off + new_size*j)
474-
for j in range(new_num) for (tp, off) in new_fields]
475-
old_fieldtile = [(tp, off + old_size*j)
476-
for j in range(old_num) for (tp, off) in old_fields]
477-
478-
# raises if there is a problem
479-
_check_field_overlap(new_fieldtile, old_fieldtile)
366+
if newtype.hasobject or oldtype.hasobject:
367+
raise TypeError("Cannot change data-type for object array.")
368+
return
480369

481370
# Given a string containing a PEP 3118 format specifier,
482371
# construct a Numpy dtype

0 commit comments

Comments
 (0)
0