classification
Title: struct.pack("I", "foo"); struct.pack("L", "foo") should fail
Type: behavior Stage: resolved
Components: Extension Modules Versions: Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: mark.dickinson Nosy List: ajaksu2, mark.dickinson, theller, vdupras
Priority: normal Keywords: patch

Created on 2007-06-21 18:36 by theller, last changed 2009-07-05 10:08 by mark.dickinson. This issue is now closed.

Files
File name Uploaded Description Edit
fail_pack_non_int.diff ajaksu2, 2009-05-12 06:09 Check the type of the arg to pack(), with trivial tests.
issue1741130.patch mark.dickinson, 2009-07-04 21:48
Messages (8)
msg32377 - (view) Author: Thomas Heller (theller) * (Python committer) Date: 2007-06-21 18:36
The following code prints out "I L" when run with python 2.5 and current SVN trunk (if you silence the DeprecationWarnings):

"""
import struct

for c in "bBhHiIlLqQdf":
    try:
        struct.pack(c, "foo bar")
    except struct.error:
        pass
    else:
        print c
"""

It works correctly (prints nothing) in Python 2.4.
msg84737 - (view) Author: Daniel Diniz (ajaksu2) (Python triager) Date: 2009-03-31 01:19
Cannot confirm for trunk.
msg85043 - (view) Author: Virgil Dupras (vdupras) (Python triager) Date: 2009-04-01 16:27
While the behavior cannot be reproduced in the trunk, in can be 
reproduced in the 2.6 release:

$ python -W ignore
Python 2.6.1 (r261:67515, Dec  6 2008, 16:42:21) 
[GCC 4.0.1 (Apple Computer, Inc. build 5370)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import struct
>>> struct.pack('L', 'foobar')
'\x00\x00\x00\x00'
>>> struct.pack('I', 'foobar')
'\x00\x00\x00\x00'
>>> struct.pack('i', 'foobar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
struct.error: required argument is not an integer
>>>
msg86181 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-04-19 21:10
It looks as though this was sort-of fixed sometime between 2.6.1 and 
2.6.2.  In 2.6.2, I get the following (and results from trunk and 3.0.1 
are similar):

Python 2.6.2+ (release26-maint:71755, Apr 19 2009, 22:06:02) 
[GCC 4.0.1 (Apple Inc. build 5490)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import struct
>>> struct.pack('L', 'not an integer')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'str' and 'long'

That error message suggests that there's something nasty happening 
somewhere, though.  It looks as though we're getting the right type of 
exception, but for the wrong reasons.
msg87607 - (view) Author: Daniel Diniz (ajaksu2) (Python triager) Date: 2009-05-12 06:08
Mark, Virgil: Thanks for correcting my wrong assessment!

The lucky TypeError comes from rev 68120.

It looks like that error message in trunk is due to a "PyNumber_And(v,
pylong_ulong_mask)" when v isn't a PyNumber. I've added a "get_pylong(v)
== NULL" check in the attached patch, but my C is weak :)
msg90109 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-07-04 09:30
Thanks for the patch, Daniel!  It certainly fixes the problem.  I was 
planning something a little more drastic, though---I think the struct 
module could do with a bit of a cleanup in this area.

At the moment it's not clear exactly what types should be accepted by
struct.pack with an integer format.  Just ints and longs (and their 
subclases)?  Anything implementing an __index__ method?  Anything 
implementing an __int__ method (e.g., Decimal instances)?

I propose doing a little bit of rewriting so that

  (1) all attempted conversions of a PyObject to a C integer
      go through PyNumber_Index; thus anything with an __index__
      method can be packed.

  (2) If PY_STRUCT_FLOAT_COERCE is defined, instances of float or
      subclasses of float (i.e., everything that passes PyFloat_Check)
      are also accepted, for backwards compatibility.

Does this seem reasonable?
msg90129 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-07-04 21:48
Here's a patch that does some general cleanup of the object->integer 
helper functions in the struct module;  in the process, it fixes this 
bug.  With this patch, all conversions from a PyObject to a C integer go 
through get_pylong, so they're all treated the same way.  Currently 
(i.e., without the patch) there's a lack of consistency in the way the 
various integer codes are handled---some codes emit a warning for float 
conversions and some ('q', 'Q') don't;  some codes will happily convert 
a Decimal instance, and others won't.  Some codes produce this strange 
'unsupported operand types' message and some don't, etc.
msg90149 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-07-05 10:08
Strange TypeError message fixed in r73858: those pack operations now raise 
struct.error, like they do for all other integer codes.
History
Date User Action Args
2009-07-05 10:08:20mark.dickinsonsetstatus: open -> closed
resolution: fixed
messages: + msg90149

stage: patch review -> resolved
2009-07-04 21:48:12mark.dickinsonsetfiles: + issue1741130.patch

messages: + msg90129
versions: + Python 2.7, - Python 2.6
2009-07-04 09:30:47mark.dickinsonsetmessages: + msg90109
2009-05-15 02:34:11ajaksu2linkissue1530559 dependencies
2009-05-12 06:09:24ajaksu2setkeywords: + patch
files: + fail_pack_non_int.diff
messages: + msg87607

stage: test needed -> patch review
2009-04-19 21:10:46mark.dickinsonsetmessages: + msg86181
2009-04-02 13:48:04mark.dickinsonsetassignee: mark.dickinson
2009-04-01 16:27:45vduprassetnosy: + vdupras
messages: + msg85043
2009-03-31 01:19:42ajaksu2settype: behavior
components: + Extension Modules, - None
versions: + Python 2.6, - Python 2.5
nosy: + ajaksu2, mark.dickinson

messages: + msg84737
stage: test needed
2007-06-21 18:36:53thellercreate