Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Xavier Thompson
cython
Commits
f5984db3
Commit
f5984db3
authored
Dec 08, 2020
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement runtime isolation check on consuming non 'iso' cypclass
parent
44056f33
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
129 additions
and
18 deletions
+129
-18
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+13
-13
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+43
-4
Cython/Utility/CyObjects.cpp
Cython/Utility/CyObjects.cpp
+73
-1
No files found.
Cython/Compiler/ExprNodes.py
View file @
f5984db3
...
...
@@ -11356,10 +11356,11 @@ class ConsumeNode(ExprNode):
# Consume expression
#
# operand ExprNode
#
# generate_runtime_check boolean used internally
# operand_is_named boolean used internally
subexprs
=
[
'operand'
]
generate_runtime_check
=
True
operand_is_named
=
True
def
infer_type
(
self
,
env
):
operand_type
=
self
.
operand
.
infer_type
(
env
)
...
...
@@ -11375,10 +11376,6 @@ class ConsumeNode(ExprNode):
error
(
self
.
pos
,
"Can only consume cypclass"
)
self
.
type
=
PyrexTypes
.
error_type
return
self
if
self
.
operand
.
is_name
or
self
.
operand
.
is_attribute
:
self
.
is_temp
=
self
.
operand_is_named
=
True
# We steal the reference of the operand.
self
.
use_managed_ref
=
False
if
operand_type
.
is_qualified_cyp_class
:
if
operand_type
.
qualifier
==
'iso!'
:
error
(
self
.
pos
,
"Cannot consume iso!"
)
...
...
@@ -11390,7 +11387,13 @@ class ConsumeNode(ExprNode):
else
:
self
.
type
=
PyrexTypes
.
cyp_class_qualified_type
(
operand_type
.
qual_base_type
,
'iso~'
)
else
:
self
.
generate_runtime_check
=
True
self
.
type
=
PyrexTypes
.
cyp_class_qualified_type
(
operand_type
,
'iso~'
)
self
.
operand_is_named
=
self
.
operand
.
is_name
or
self
.
operand
.
is_attribute
self
.
is_temp
=
self
.
operand_is_named
or
self
.
generate_runtime_check
if
self
.
is_temp
:
# We steal the reference of the operand.
self
.
use_managed_ref
=
False
return
self
def
may_be_none
(
self
):
...
...
@@ -11404,19 +11407,16 @@ class ConsumeNode(ExprNode):
pass
def
calculate_result_code
(
self
):
if
self
.
generate_runtime_check
:
# TODO: generate runtime check for isolation
return
self
.
operand
.
result
()
else
:
return
self
.
operand
.
result
()
return
self
.
operand
.
result
()
def
generate_result_code
(
self
,
code
):
if
self
.
is_temp
:
operand_result
=
self
.
operand
.
result
()
code
.
putln
(
"%s = %s;"
%
(
self
.
result
(),
operand_result
))
if
self
.
generate_runtime_check
:
# TODO: generate runtime check for isolation
pass
code
.
putln
(
"if (!%s->CyObject_iso()) {"
%
self
.
result
())
code
.
putln
(
"std::terminate();"
)
code
.
putln
(
"}"
)
# We steal the reference of the operand.
code
.
putln
(
"%s = NULL;"
%
operand_result
)
if
self
.
operand
.
is_temp
:
...
...
Cython/Compiler/ModuleNode.py
View file @
f5984db3
...
...
@@ -937,6 +937,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self
.
generate_cyp_class_activated_methods
(
entry
,
code
)
# Generate cypclass attr destructor
self
.
generate_cyp_class_attrs_destructor_definition
(
entry
,
code
)
# Generate cypclass traverse method and isolation check method
self
.
generate_cyp_class_traverse_and_iso_definition
(
entry
,
code
)
# Generate wrapper constructor
wrapper
=
scope
.
lookup_here
(
"<constructor>"
)
constructor
=
scope
.
lookup_here
(
"<init>"
)
...
...
@@ -967,6 +969,41 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code
.
putln
(
"Cy_XDECREF(this->%s);"
%
attr
.
cname
)
code
.
putln
(
"}"
)
def
generate_cyp_class_traverse_and_iso_definition
(
self
,
entry
,
code
):
"""
Generate traverse method and isolation check method definition for the given cypclass entry.
"""
scope
=
entry
.
type
.
scope
all_cypclass_attrs
=
[
e
for
e
in
scope
.
entries
.
values
()
if
e
.
type
.
is_cyp_class
and
not
e
.
name
==
"this"
and
not
e
.
is_type
]
# potential template
if
entry
.
type
.
templates
:
templates_code
=
"template <typename %s>"
%
", typename "
.
join
(
t
.
name
for
t
in
entry
.
type
.
templates
)
else
:
templates_code
=
None
# traverse method
namespace
=
entry
.
type
.
empty_declaration_code
()
if
templates_code
:
code
.
putln
(
templates_code
)
code
.
putln
(
"int %s::CyObject_traverse(void *(*visit)(const CyObject *o, void *arg), void *arg) const"
%
namespace
)
code
.
putln
(
"{"
)
for
attr
in
all_cypclass_attrs
:
code
.
putln
(
"if (void *ret = visit(this->%s, arg)) return (int) (intptr_t) ret;"
%
attr
.
cname
)
code
.
putln
(
"return 0;"
)
code
.
putln
(
"}"
)
# isolation check method
if
templates_code
:
code
.
putln
(
templates_code
)
code
.
putln
(
"int %s::CyObject_iso() const"
%
namespace
)
code
.
putln
(
"{"
)
if
all_cypclass_attrs
:
code
.
putln
(
"return __Pyx_CyObject_owning(this) == 1;"
)
else
:
code
.
putln
(
"return this->CyObject_GETREF() == 1;"
)
code
.
putln
(
"}"
)
def
generate_cyp_class_activated_methods
(
self
,
entry
,
code
):
"""
Generate activated cypclass methods.
...
...
@@ -1459,10 +1496,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code
.
putln
(
"Py_TYPE(wrapper) = %s;"
%
wrapper_type
.
typeptr_cname
)
code
.
putln
(
"}"
)
def
generate_typedef
(
self
,
entry
,
code
):
base_type
=
entry
.
type
.
typedef_base_type
enclosing_scope
=
entry
.
scope
...
...
@@ -1632,6 +1665,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
arg_names
=
[]
generate_cpp_constructor_code
(
arg_decls
,
arg_names
,
is_implementing
,
py_attrs
,
constructor
)
if
type
.
is_cyp_class
:
# Declare the method to check isolation
code
.
putln
(
"virtual int CyObject_iso() const;"
)
# Declare the traverse method
code
.
putln
(
"virtual int CyObject_traverse(void *(*visit)(const CyObject *o, void *arg), void *arg) const;"
)
if
type
.
is_cyp_class
and
cypclass_attrs
:
# Declaring a small destruction handler which will always try to Cy_XDECREF
# every cypclass attribute. This handler is defined after all class definition.
...
...
Cython/Utility/CyObjects.cpp
View file @
f5984db3
...
...
@@ -83,10 +83,21 @@
private:
mutable
std
::
atomic_int
nogil_ob_refcnt
;
mutable
CyLock
ob_lock
;
public:
CyObject
()
:
nogil_ob_refcnt
(
1
)
{}
mutable
const
CyObject
*
__next
;
mutable
int
__refcnt
;
CyObject
()
:
nogil_ob_refcnt
(
1
),
__next
(
NULL
),
__refcnt
(
0
)
{}
virtual
~
CyObject
()
{}
/* Object graph inspection methods */
virtual
int
CyObject_iso
()
const
{
return
this
->
nogil_ob_refcnt
==
1
;
}
virtual
int
CyObject_traverse
(
void
*
(
*
visit
)(
const
CyObject
*
o
,
void
*
arg
),
void
*
arg
)
const
{
return
0
;
}
/* Locking methods */
void
CyObject_RLOCK
(
const
char
*
context
)
const
;
void
CyObject_WLOCK
(
const
char
*
context
)
const
;
...
...
@@ -475,6 +486,67 @@
return
ob
;
}
/*
* Visit callback to collect reachable fields.
*/
static
void
*
__Pyx_CyObject_visit_collect
(
const
CyObject
*
ob
,
void
*
arg
)
{
if
(
!
ob
)
return
0
;
if
(
ob
->
__refcnt
)
return
0
;
ob
->
__refcnt
=
ob
->
CyObject_GETREF
();
const
CyObject
*
head
=
reinterpret_cast
<
CyObject
*>
(
arg
);
const
CyObject
*
tmp
=
head
->
__next
;
ob
->
__next
=
tmp
;
head
->
__next
=
ob
;
return
0
;
}
/*
* Visit callback to decref reachable fields.
*/
static
void
*
__Pyx_CyObject_visit_decref
(
const
CyObject
*
ob
,
void
*
arg
)
{
(
void
)
arg
;
if
(
!
ob
)
return
0
;
ob
->
__refcnt
-=
1
;
return
0
;
}
/*
* Check if a CyObject is owning.
*/
static
inline
int
__Pyx_CyObject_owning
(
const
CyObject
*
root
)
{
const
CyObject
*
current
;
bool
owning
=
true
;
int
owners
;
/* Mark the root as already visited */
root
->
__refcnt
=
root
->
CyObject_GETREF
();
/* Collect the reachable objects */
for
(
current
=
root
;
current
!=
NULL
;
current
=
current
->
__next
)
{
current
->
CyObject_traverse
(
__Pyx_CyObject_visit_collect
,
(
void
*
)
current
);
}
/* Decref the reachable objects */
for
(
current
=
root
;
current
!=
NULL
;
current
=
current
->
__next
)
{
current
->
CyObject_traverse
(
__Pyx_CyObject_visit_decref
,
(
void
*
)
current
);
}
/* Search for externally reachable object */
for
(
current
=
root
->
__next
;
current
!=
NULL
;
current
=
current
->
__next
)
{
if
(
current
->
__refcnt
)
owning
=
false
;
}
/* Count external potential owners */
owners
=
root
->
__refcnt
;
/* Cleanup */
for
(
current
=
root
;
current
!=
NULL
;)
{
current
->
__refcnt
=
0
;
const
CyObject
*
next
=
current
->
__next
;
current
->
__next
=
NULL
;
current
=
next
;
}
return
owning
?
owners
:
0
;
}
/*
* Cast from CyObject to PyObject:
* - borrow an atomic reference
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment