Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
a6f85eb9
Commit
a6f85eb9
authored
Oct 25, 2016
by
Wenzel Jakob
Committed by
GitHub
Oct 25, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #465 from jagerman/prevent-object-overwriting
Prevent overwriting previous declarations
parents
dd9bd777
6873c202
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
88 additions
and
5 deletions
+88
-5
include/pybind11/pybind11.h
+29
-5
tests/test_issues.cpp
+54
-0
tests/test_issues.py
+5
-0
No files found.
include/pybind11/pybind11.h
View file @
a6f85eb9
...
@@ -253,7 +253,8 @@ protected:
...
@@ -253,7 +253,8 @@ protected:
#endif
#endif
detail
::
function_record
*
chain
=
nullptr
,
*
chain_start
=
rec
;
detail
::
function_record
*
chain
=
nullptr
,
*
chain_start
=
rec
;
if
(
rec
->
sibling
&&
PyCFunction_Check
(
rec
->
sibling
.
ptr
()))
{
if
(
rec
->
sibling
)
{
if
(
PyCFunction_Check
(
rec
->
sibling
.
ptr
()))
{
capsule
rec_capsule
(
PyCFunction_GetSelf
(
rec
->
sibling
.
ptr
()),
true
);
capsule
rec_capsule
(
PyCFunction_GetSelf
(
rec
->
sibling
.
ptr
()),
true
);
chain
=
(
detail
::
function_record
*
)
rec_capsule
;
chain
=
(
detail
::
function_record
*
)
rec_capsule
;
/* Never append a method to an overload chain of a parent class;
/* Never append a method to an overload chain of a parent class;
...
@@ -261,6 +262,11 @@ protected:
...
@@ -261,6 +262,11 @@ protected:
if
(
chain
->
class_
!=
rec
->
class_
)
if
(
chain
->
class_
!=
rec
->
class_
)
chain
=
nullptr
;
chain
=
nullptr
;
}
}
// Don't trigger for things like the default __init__, which are wrapper_descriptors that we are intentionally replacing
else
if
(
!
rec
->
sibling
.
is_none
()
&&
rec
->
name
[
0
]
!=
'_'
)
pybind11_fail
(
"Cannot overload existing non-function object
\"
"
+
std
::
string
(
rec
->
name
)
+
"
\"
with a function of the same name"
);
}
if
(
!
chain
)
{
if
(
!
chain
)
{
/* No existing overload was found, create a new function object */
/* No existing overload was found, create a new function object */
...
@@ -546,8 +552,9 @@ public:
...
@@ -546,8 +552,9 @@ public:
module
&
def
(
const
char
*
name_
,
Func
&&
f
,
const
Extra
&
...
extra
)
{
module
&
def
(
const
char
*
name_
,
Func
&&
f
,
const
Extra
&
...
extra
)
{
cpp_function
func
(
std
::
forward
<
Func
>
(
f
),
name
(
name_
),
scope
(
*
this
),
cpp_function
func
(
std
::
forward
<
Func
>
(
f
),
name
(
name_
),
scope
(
*
this
),
sibling
(
getattr
(
*
this
,
name_
,
none
())),
extra
...);
sibling
(
getattr
(
*
this
,
name_
,
none
())),
extra
...);
/* PyModule_AddObject steals a reference to 'func' */
// NB: allow overwriting here because cpp_function sets up a chain with the intention of
PyModule_AddObject
(
ptr
(),
name_
,
func
.
inc_ref
().
ptr
());
// overwriting (and has already checked internally that it isn't overwriting non-functions).
add_object
(
name_
,
func
,
true
/* overwrite */
);
return
*
this
;
return
*
this
;
}
}
...
@@ -567,6 +574,20 @@ public:
...
@@ -567,6 +574,20 @@ public:
throw
import_error
(
"Module
\"
"
+
std
::
string
(
name
)
+
"
\"
not found!"
);
throw
import_error
(
"Module
\"
"
+
std
::
string
(
name
)
+
"
\"
not found!"
);
return
module
(
obj
,
false
);
return
module
(
obj
,
false
);
}
}
// Adds an object to the module using the given name. Throws if an object with the given name
// already exists.
//
// overwrite should almost always be false: attempting to overwrite objects that pybind11 has
// established will, in most cases, break things.
PYBIND11_NOINLINE
void
add_object
(
const
char
*
name
,
object
&
obj
,
bool
overwrite
=
false
)
{
if
(
!
overwrite
&&
hasattr
(
*
this
,
name
))
pybind11_fail
(
"Error during initialization: multiple incompatible definitions with name
\"
"
+
std
::
string
(
name
)
+
"
\"
"
);
obj
.
inc_ref
();
// PyModule_AddObject() steals a reference
PyModule_AddObject
(
ptr
(),
name
,
obj
.
ptr
());
}
};
};
NAMESPACE_BEGIN
(
detail
)
NAMESPACE_BEGIN
(
detail
)
...
@@ -614,6 +635,10 @@ protected:
...
@@ -614,6 +635,10 @@ protected:
object
name
(
PYBIND11_FROM_STRING
(
rec
->
name
),
false
);
object
name
(
PYBIND11_FROM_STRING
(
rec
->
name
),
false
);
object
scope_module
;
object
scope_module
;
if
(
rec
->
scope
)
{
if
(
rec
->
scope
)
{
if
(
hasattr
(
rec
->
scope
,
rec
->
name
))
pybind11_fail
(
"generic_type: cannot initialize type
\"
"
+
std
::
string
(
rec
->
name
)
+
"
\"
: an object with that name is already defined"
);
if
(
hasattr
(
rec
->
scope
,
"__module__"
))
{
if
(
hasattr
(
rec
->
scope
,
"__module__"
))
{
scope_module
=
rec
->
scope
.
attr
(
"__module__"
);
scope_module
=
rec
->
scope
.
attr
(
"__module__"
);
}
else
if
(
hasattr
(
rec
->
scope
,
"__name__"
))
{
}
else
if
(
hasattr
(
rec
->
scope
,
"__name__"
))
{
...
@@ -1357,8 +1382,7 @@ public:
...
@@ -1357,8 +1382,7 @@ public:
+
std
::
string
(
"."
)
+
name
;
+
std
::
string
(
"."
)
+
name
;
char
*
exception_name
=
const_cast
<
char
*>
(
full_name
.
c_str
());
char
*
exception_name
=
const_cast
<
char
*>
(
full_name
.
c_str
());
m_ptr
=
PyErr_NewException
(
exception_name
,
base
,
NULL
);
m_ptr
=
PyErr_NewException
(
exception_name
,
base
,
NULL
);
inc_ref
();
// PyModule_AddObject() steals a reference
m
.
add_object
(
name
.
c_str
(),
*
this
);
PyModule_AddObject
(
m
.
ptr
(),
name
.
c_str
(),
m_ptr
);
}
}
// Sets the current python exception to this exception object with the given message
// Sets the current python exception to this exception object with the given message
...
...
tests/test_issues.cpp
View file @
a6f85eb9
...
@@ -36,6 +36,18 @@ OpTest2 operator+(const OpTest2 &, const OpTest1 &) {
...
@@ -36,6 +36,18 @@ OpTest2 operator+(const OpTest2 &, const OpTest1 &) {
return
OpTest2
();
return
OpTest2
();
}
}
// #461
class
Dupe1
{
public
:
Dupe1
(
int
v
)
:
v_
{
v
}
{}
int
get_value
()
const
{
return
v_
;
}
private
:
int
v_
;
};
class
Dupe2
{};
class
Dupe3
{};
class
DupeException
:
public
std
::
runtime_error
{};
void
init_issues
(
py
::
module
&
m
)
{
void
init_issues
(
py
::
module
&
m
)
{
py
::
module
m2
=
m
.
def_submodule
(
"issues"
);
py
::
module
m2
=
m
.
def_submodule
(
"issues"
);
...
@@ -237,7 +249,49 @@ void init_issues(py::module &m) {
...
@@ -237,7 +249,49 @@ void init_issues(py::module &m) {
static
std
::
vector
<
int
>
list
=
{
1
,
2
,
3
};
static
std
::
vector
<
int
>
list
=
{
1
,
2
,
3
};
m2
.
def
(
"make_iterator_1"
,
[]()
{
return
py
::
make_iterator
<
py
::
return_value_policy
::
copy
>
(
list
);
});
m2
.
def
(
"make_iterator_1"
,
[]()
{
return
py
::
make_iterator
<
py
::
return_value_policy
::
copy
>
(
list
);
});
m2
.
def
(
"make_iterator_2"
,
[]()
{
return
py
::
make_iterator
<
py
::
return_value_policy
::
automatic
>
(
list
);
});
m2
.
def
(
"make_iterator_2"
,
[]()
{
return
py
::
make_iterator
<
py
::
return_value_policy
::
automatic
>
(
list
);
});
static
std
::
vector
<
std
::
string
>
nothrows
;
// Issue 461: registering two things with the same name:
py
::
class_
<
Dupe1
>
(
m2
,
"Dupe1"
)
.
def
(
"get_value"
,
&
Dupe1
::
get_value
)
;
m2
.
def
(
"dupe1_factory"
,
[](
int
v
)
{
return
new
Dupe1
(
v
);
});
py
::
class_
<
Dupe2
>
(
m2
,
"Dupe2"
);
py
::
exception
<
DupeException
>
(
m2
,
"DupeException"
);
try
{
m2
.
def
(
"Dupe1"
,
[](
int
v
)
{
return
new
Dupe1
(
v
);
});
nothrows
.
emplace_back
(
"Dupe1"
);
}
catch
(
std
::
runtime_error
&
)
{}
try
{
py
::
class_
<
Dupe3
>
(
m2
,
"dupe1_factory"
);
nothrows
.
emplace_back
(
"dupe1_factory"
);
}
catch
(
std
::
runtime_error
&
)
{}
try
{
py
::
exception
<
Dupe3
>
(
m2
,
"Dupe2"
);
nothrows
.
emplace_back
(
"Dupe2"
);
}
catch
(
std
::
runtime_error
&
)
{}
try
{
m2
.
def
(
"DupeException"
,
[]()
{
return
30
;
});
nothrows
.
emplace_back
(
"DupeException1"
);
}
catch
(
std
::
runtime_error
&
)
{}
try
{
py
::
class_
<
DupeException
>
(
m2
,
"DupeException"
);
nothrows
.
emplace_back
(
"DupeException2"
);
}
catch
(
std
::
runtime_error
&
)
{}
m2
.
def
(
"dupe_exception_failures"
,
[]()
{
py
::
list
l
;
for
(
auto
&
e
:
nothrows
)
l
.
append
(
py
::
cast
(
e
));
return
l
;
});
}
}
// MSVC workaround: trying to use a lambda here crashes MSCV
// MSVC workaround: trying to use a lambda here crashes MSCV
test_initializer
issues
(
&
init_issues
);
test_initializer
issues
(
&
init_issues
);
tests/test_issues.py
View file @
a6f85eb9
...
@@ -182,3 +182,8 @@ def test_iterator_rvpolicy():
...
@@ -182,3 +182,8 @@ def test_iterator_rvpolicy():
assert
list
(
make_iterator_1
())
==
[
1
,
2
,
3
]
assert
list
(
make_iterator_1
())
==
[
1
,
2
,
3
]
assert
list
(
make_iterator_2
())
==
[
1
,
2
,
3
]
assert
list
(
make_iterator_2
())
==
[
1
,
2
,
3
]
assert
(
type
(
make_iterator_1
())
!=
type
(
make_iterator_2
()))
assert
(
type
(
make_iterator_1
())
!=
type
(
make_iterator_2
()))
def
test_dupe_assignment
():
""" Issue 461: overwriting a class with a function """
from
pybind11_tests.issues
import
dupe_exception_failures
assert
dupe_exception_failures
()
==
[]
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