@@ -285,6 +285,15 @@ static int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
285
285
CT_PRIMITIVE_FLOAT | \
286
286
CT_PRIMITIVE_COMPLEX)
287
287
288
+ /* flags that are mutable at runtime, stored separately in ct_flags_mut to avoid
289
+ races with ct_flags
290
+
291
+ these are read and set without using atomic operations because a lock is held
292
+ while mutating ct_flags_mut
293
+ */
294
+ #define CT_CUSTOM_FIELD_POS 0x00000001
295
+ #define CT_WITH_VAR_ARRAY 0x00000002 /* with open-ended array, anywhere */
296
+ #define CT_WITH_PACKED_CHANGE 0x00000004
288
297
289
298
typedef struct _ctypedescr {
290
299
PyObject_VAR_HEAD
@@ -309,13 +318,11 @@ typedef struct _ctypedescr {
309
318
or alignment of primitive and struct types;
310
319
always -1 for pointers */
311
320
int ct_flags ; /* Immutable CT_xxx flags */
321
+ int ct_flags_mut ; /* Mutable CT_xxx flags */
312
322
uint8_t ct_under_construction ;
313
323
uint8_t ct_under_realization ;
314
324
uint8_t ct_lazy_field_list ;
315
325
uint8_t ct_unrealized_struct_or_union ;
316
- uint8_t ct_custom_field_pos ;
317
- uint8_t ct_with_packed_change ;
318
- uint8_t ct_with_var_array ; /* with open-ended array, anywhere */
319
326
int ct_name_position ; /* index in ct_name of where to put a var name */
320
327
char ct_name [1 ]; /* string, e.g. "int *" for pointers to ints */
321
328
} CTypeDescrObject ;
@@ -474,9 +481,7 @@ ctypedescr_new(int name_size)
474
481
ct -> ct_under_realization = 0 ;
475
482
ct -> ct_under_construction = 0 ;
476
483
ct -> ct_unrealized_struct_or_union = 0 ;
477
- ct -> ct_custom_field_pos = 0 ;
478
- ct -> ct_with_packed_change = 0 ;
479
- ct -> ct_with_var_array = 0 ;
484
+ ct -> ct_flags_mut = 0 ;
480
485
PyObject_GC_Track (ct );
481
486
return ct ;
482
487
}
@@ -1513,8 +1518,7 @@ convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value,
1513
1518
if (optvarsize == NULL ) {
1514
1519
return convert_field_from_object (data , cf , value );
1515
1520
}
1516
- else if (cffi_check_flag (cf -> cf_type -> ct_with_var_array ) != 0 &&
1517
- !CData_Check (value )) {
1521
+ else if ((cf -> cf_type -> ct_flags_mut & CT_WITH_VAR_ARRAY ) && !CData_Check (value )) {
1518
1522
Py_ssize_t subsize = cf -> cf_type -> ct_size ;
1519
1523
if (convert_struct_from_object (NULL , cf -> cf_type , value , & subsize ) < 0 )
1520
1524
return -1 ;
@@ -2268,7 +2272,7 @@ static Py_ssize_t _cdata_var_byte_size(CDataObject *cd)
2268
2272
if (cd -> c_type -> ct_flags & CT_IS_PTR_TO_OWNED ) {
2269
2273
cd = (CDataObject * )((CDataObject_own_structptr * )cd )-> structobj ;
2270
2274
}
2271
- if (cffi_check_flag ( cd -> c_type -> ct_with_var_array ) ) {
2275
+ if (cd -> c_type -> ct_flags_mut & CT_WITH_VAR_ARRAY ) {
2272
2276
return ((CDataObject_own_length * )cd )-> length ;
2273
2277
}
2274
2278
return -1 ;
@@ -3858,7 +3862,7 @@ convert_struct_to_owning_object(char *data, CTypeDescrObject *ct)
3858
3862
"return type is an opaque structure or union" );
3859
3863
return NULL ;
3860
3864
}
3861
- if (cffi_check_flag ( ct -> ct_with_var_array ) ) {
3865
+ if (ct -> ct_flags_mut & CT_WITH_VAR_ARRAY ) {
3862
3866
PyErr_SetString (PyExc_TypeError ,
3863
3867
"return type is a struct/union with a varsize array member" );
3864
3868
return NULL ;
@@ -3967,7 +3971,7 @@ static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init,
3967
3971
datasize *= 2 ; /* forcefully add another character: a null */
3968
3972
3969
3973
if (ctitem -> ct_flags & (CT_STRUCT | CT_UNION )) {
3970
- if (cffi_check_flag ( ctitem -> ct_with_var_array ) ) {
3974
+ if (ctitem -> ct_flags_mut & CT_WITH_VAR_ARRAY ) {
3971
3975
assert (ct -> ct_flags & CT_IS_PTR_TO_OWNED );
3972
3976
dataoffset = offsetof(CDataObject_own_length , alignment );
3973
3977
@@ -5282,7 +5286,7 @@ static int detect_custom_layout(CTypeDescrObject *ct, int sflags,
5282
5286
ct -> ct_name );
5283
5287
return -1 ;
5284
5288
}
5285
- cffi_set_flag ( ct -> ct_custom_field_pos , 1 ) ;
5289
+ ct -> ct_flags_mut |= CT_CUSTOM_FIELD_POS ;
5286
5290
}
5287
5291
return 0 ;
5288
5292
}
@@ -5320,8 +5324,8 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
5320
5324
"first arg must be a non-initialized struct or union ctype" );
5321
5325
goto finally ;
5322
5326
}
5323
- cffi_set_flag ( ct -> ct_custom_field_pos , 0 ) ;
5324
- cffi_set_flag ( ct -> ct_with_packed_change , 0 ) ;
5327
+ ct -> ct_flags_mut &= ~ CT_CUSTOM_FIELD_POS ;
5328
+ ct -> ct_flags_mut &= ~ CT_WITH_PACKED_CHANGE ;
5325
5329
5326
5330
alignment = 1 ;
5327
5331
byteoffset = 0 ; /* the real value is 'byteoffset+bitoffset*8', which */
@@ -5359,7 +5363,7 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
5359
5363
if (cffi_get_size (ftype ) < 0 ) {
5360
5364
if ((ftype -> ct_flags & CT_ARRAY ) && fbitsize < 0
5361
5365
&& (i == nb_fields - 1 || foffset != -1 )) {
5362
- cffi_set_flag ( ct -> ct_with_var_array , 1 ) ;
5366
+ ct -> ct_flags_mut |= CT_WITH_VAR_ARRAY ;
5363
5367
}
5364
5368
else {
5365
5369
PyErr_Format (PyExc_TypeError ,
@@ -5373,11 +5377,11 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
5373
5377
/* GCC (or maybe C99) accepts var-sized struct fields that are not
5374
5378
the last field of a larger struct. That's why there is no
5375
5379
check here for "last field": we propagate the flag
5376
- ct_with_var_array to any struct that contains either an open-
5380
+ CT_WITH_VAR_ARRAY to any struct that contains either an open-
5377
5381
ended array or another struct that recursively contains an
5378
5382
open-ended array. */
5379
- if (cffi_check_flag ( ftype -> ct_with_var_array ) ) {
5380
- cffi_set_flag ( ct -> ct_with_var_array , 1 ) ;
5383
+ if (ftype -> ct_flags_mut & CT_WITH_VAR_ARRAY ) {
5384
+ ct -> ct_flags_mut |= CT_WITH_VAR_ARRAY ;
5381
5385
}
5382
5386
}
5383
5387
@@ -5426,12 +5430,12 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
5426
5430
byteoffset = (byteoffset + falign - 1 ) & ~(falign - 1 );
5427
5431
5428
5432
if (byteoffsetorg != byteoffset ) {
5429
- cffi_set_flag ( ct -> ct_with_packed_change , 1 ) ;
5433
+ ct -> ct_flags_mut |= CT_WITH_PACKED_CHANGE ;
5430
5434
}
5431
5435
5432
5436
if (foffset >= 0 ) {
5433
5437
/* a forced field position: ignore the offset just computed,
5434
- except to know if we must set ct_custom_field_pos */
5438
+ except to know if we must set CT_CUSTOM_FIELD_POS */
5435
5439
if (detect_custom_layout (ct , sflags , byteoffset , foffset ,
5436
5440
"wrong offset for field '" ,
5437
5441
PyText_AS_UTF8 (fname ), "'" ) < 0 )
@@ -5459,7 +5463,7 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
5459
5463
previous = & (* previous )-> cf_next ;
5460
5464
}
5461
5465
/* always forbid such structures from being passed by value */
5462
- cffi_set_flag ( ct -> ct_custom_field_pos , 1 ) ;
5466
+ ct -> ct_flags_mut |= CT_CUSTOM_FIELD_POS ;
5463
5467
}
5464
5468
else {
5465
5469
* previous = _add_field (interned_fields , fname , ftype ,
@@ -5760,15 +5764,15 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
5760
5764
differently: e.g. on x86-64, "b" ends up in register "rsi" in
5761
5765
the first case and "rdi" in the second case.
5762
5766
5763
- Another reason for ct_custom_field_pos would be anonymous
5767
+ Another reason for CT_CUSTOM_FIELD_POS would be anonymous
5764
5768
nested structures: we lost the information about having it
5765
5769
here, so better safe (and forbid it) than sorry (and maybe
5766
5770
crash). Note: it seems we only get in this case with
5767
5771
ffi.verify().
5768
5772
*/
5769
5773
if (force_lazy_struct (ct ) < 0 )
5770
5774
return NULL ;
5771
- if (cffi_check_flag ( ct -> ct_custom_field_pos ) ) {
5775
+ if (ct -> ct_flags_mut & CT_CUSTOM_FIELD_POS ) {
5772
5776
/* these NotImplementedErrors may be caught and ignored until
5773
5777
a real call is made to a function of this type */
5774
5778
return fb_unsupported (ct , place ,
@@ -5778,7 +5782,7 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
5778
5782
}
5779
5783
/* Another reason: __attribute__((packed)) is not supported by libffi.
5780
5784
*/
5781
- if (cffi_check_flag ( ct -> ct_with_packed_change ) ) {
5785
+ if (ct -> ct_flags_mut & CT_WITH_PACKED_CHANGE ) {
5782
5786
return fb_unsupported (ct , place ,
5783
5787
"It is a 'packed' structure, with a different layout than "
5784
5788
"expected by libffi" );
@@ -6760,9 +6764,6 @@ static PyObject *b_new_enum_type(PyObject *self, PyObject *args)
6760
6764
td -> ct_length = basetd -> ct_length ; /* alignment */
6761
6765
td -> ct_extra = basetd -> ct_extra ; /* ffi type */
6762
6766
td -> ct_flags = basetd -> ct_flags | CT_IS_ENUM ;
6763
- td -> ct_custom_field_pos = cffi_check_flag (basetd -> ct_custom_field_pos );
6764
- td -> ct_with_packed_change = cffi_check_flag (basetd -> ct_with_packed_change );
6765
- td -> ct_with_var_array = cffi_check_flag (basetd -> ct_with_var_array );
6766
6767
td -> ct_name_position = name_size - 1 ;
6767
6768
return (PyObject * )td ;
6768
6769
0 commit comments