New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: add check_size option to ctypedef class for external classes #2627
Conversation
Of course, we can fix the original issue by using this in |
Test failures from cpp, did I cause that?
|
Yes, it seems filename.pxd creates a filename_api.h without the proto section, so it misses the declaration of the enum I tried to create. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nicely written PR, sorry for the load of comments. I think we should still get this into 0.29.
The travis failure is just some whitespace left-over, found by the style checker.
* check_size tells what to do if tp_basicsize is different from size: | ||
* 0 - Error (originates in check_size=True) | ||
* 1 - Error if tp_basicsize is smaller, warn if larger (originates in check_size='min') | ||
* 2 - Error if tp_basicsize is smaller (originates in check_size=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this doesn't look like what I'd expect a check_size=False
to do … I mean, it's probably the right behaviour, but then False
is not the right setting. (Open for debate, I guess …)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we always need to error if tp_basicsize
is smaller than the C struct declared as the object, see the _check_size1.pyx
test where I define a C struct that is bigger. Accessing f2
would touch invalid memory.
So I claim even if using False we need to error on the side of caution.Open to other suggestions for the name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the options correctly, we always error fo smaller structs, but either ignore, warn, or error for larger structs. This doesn't map obviously to the True/False/'min' options provided here--maybe literally call then None, 'warn,' and 'error'? (As an aside, maybe it'd be better to use an enum than 0, 1, 2 as well).
(I actually wonder if instead we'd be better off doing a stricter check using offsetof for declared fields, even for non-extern classes, but that may have issues...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about "extend", "warn" (default) and "error" ? None
doesn't tell me much either.
Agreed that offset checks would be nice, but that's a separate feature (and not for 0.29).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe it'd be better to use an enum than 0, 1, 2
I tried that, but an enum just before the __Pyx_ImportType
declaration in the TypeImport.proto
section was not exported to the generated code. Is there an example of such an enum?
@@ -736,6 +736,14 @@ built-in complex object.:: | |||
... | |||
} PyComplexObject; | |||
|
|||
At runtime, a check will be performed when importing the cython | |||
c-extension module that ``__builtin__.complex``'s ``tp_basicsize`` | |||
matches ``sizeof(`PyComplexObject)``. This check can fail if in the cython |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No "in", just "if the Cython …".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
@@ -736,6 +736,14 @@ built-in complex object.:: | |||
... | |||
} PyComplexObject; | |||
|
|||
At runtime, a check will be performed when importing the cython |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please spell the name "Cython" with a capital "C". (You are not referring to the command line utility here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
c-extension module that ``__builtin__.complex``'s ``tp_basicsize`` | ||
matches ``sizeof(`PyComplexObject)``. This check can fail if in the cython | ||
c-extension module was compiled with one version of the | ||
``complexobject.h`` header but imported into a python with a changed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing, I think you are referring to a "Python" runtime here, not the "python" executable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Cython/Compiler/Parsing.py
Outdated
in_pxd = ctx.level == 'module_pxd', | ||
doc = doc, | ||
body = body) | ||
|
||
def p_c_class_options(s): | ||
objstruct_name = None | ||
typeobj_name = None | ||
check_size = b'min' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to have this a normal text string rather than a bytes string. Comparison to bytes might fail then parsed from Py3 code with unicode literals.
One way to do that might be to use the identifier min
instead of the string literal "min"
. Or check the literal node type and decode at need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is messy since we want min, True, or False. Changing from p_atom(s) to p_ident(s) makes True and False into strings not booleans, is that OK? In any case, that enables removing the b
(as long as we use a bare min
not 'min'
. Changed documentation (which was missing quotes anyway) and test too.
- ``type_object_name`` is the name to assume for the type's statically | ||
declared type object. | ||
- ``cs_option`` is ``'min'`` (the default), ``True``, or ``False`` and is only | ||
used for external extension types. If ``True``, ``sizeof(object_struct)`` must |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"only used for external extension types" - does the patch check that it's not used in other contexts? (And, are there actually other contexts?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was relating to the if not type.is_external or type.is_subclassed
check done in ModuleNode.py
, which I admit I don't really understand. See last comment below. A suggestion for rephrasing that better catches the logic is welcome
runtests.py
Outdated
command, self._try_decode(out), self._try_decode(err))) | ||
for c, o, e in zip(cmd, out, err): | ||
sys.stderr.write("%s\n%s\n%s\n\n" % ( | ||
c, self._try_decode(o), self._try_decode(e))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was already part of the other PR, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, sorry. Removing.
type.typeptr_cname, | ||
error_code)) | ||
# check_size | ||
if not type.is_external or type.is_subclassed: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better to raise a compiler error here if check_size
was set. Or at least warn that the value was ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what these values mean. It is from the original code and the source of the documentation problem you pointed out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check added, test needed. Suggestion for ctypedef
stanza that will trigger the failure welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"is_external" = defined in a "cdef extern" block. False if a type is cimported from another module via a .pxd file.
"is_subclassed" = we found a subtype of the type, i.e. it is definitely not a leaf class of the hierarchy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or do we want to allow this for non-extern classes? (We need to take care that the vtable doesn't change either...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the type is cimport
ed, how would we set check_size
? Is there an example in the tests that redefines a cimport
ed type?
Maybe worth adding some additional tests for failures and corner cases? Can we somehow write them as non-srctree tests? |
Don't think so. You need at least two files in order to cimport from the other. |
type.typeptr_cname, | ||
error_code)) | ||
# check_size | ||
if not type.is_external or type.is_subclassed: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"is_external" = defined in a "cdef extern" block. False if a type is cimported from another module via a .pxd file.
"is_subclassed" = we found a subtype of the type, i.e. it is definitely not a leaf class of the hierarchy.
Thanks for merging. Now on to using this in the numpy pxd ... |
Could you quickly write up a PR for that? I'd like to get the second RC out today. |
Actually, I'll just enable |
Thanks @scoder |
…ous: "warn" warns, "error" fails, and "extend" silently allows extending. Closes #2627.
I changed the available options to "extend", "warn" and "error". The boolean values really were everything but obvious. |
Perhaps the options should be "ignore", "error", and "warn"?
Not sure why putting an enum right before the __Pyx_ImportType declaration
didn't work, that's what I would have done.
As for non-extern classes, it would help if one compiled against an an
older version of a pxd. One would still have to ensure the vtables are
compatible, and of course it would have to be final. Just a half-baked
thought there, something we could always flesh out and enable later if
there was a need.
Speaking of which, are we marking these no-size-check classes as final?
…On Sat, Sep 29, 2018 at 7:21 PM Matti Picus ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In Cython/Utility/ImportExport.c
<#2627 (comment)>:
> {
+ /*
+ * check_size tells what to do if tp_basicsize is different from size:
+ * 0 - Error (originates in check_size=True)
+ * 1 - Error if tp_basicsize is smaller, warn if larger (originates in check_size='min')
+ * 2 - Error if tp_basicsize is smaller (originates in check_size=False)
maybe it'd be better to use an enum than 0, 1, 2
I tried that, but an enum just before the __Pyx_ImportType declaration in
the TypeImport.proto section was not exported to the generated code. Is
there an example of such an enum?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2627 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAdqgRynXi1GQm9sgpT_f_ZJnQNP60iZks5uf6wTgaJpZM4W3mSh>
.
|
Perhaps the options should be "ignore", "error", and "warn"?
Works for me, feel free to change it. I already reduced the number of places that need to be adapted.
|
Address #2221 by adding a new
check_size
clause toctypedef class
definitions. This will allow suppressing the warning.The srctree test actually comprises a few tests, but they are reported as one pass/fail. I am not sure how to break them into separate tests.
I think 'min', True, and False were the proposed values, but maybe I misunderstood.