[issue29131] Calling printf from the cdll does not print the full string

2017-01-02 Thread Eryk Sun

Eryk Sun added the comment:

> I am following the "Gray Hat Python - Python Programming for Hackers and 
> Reverse Engineers"

>From what I've seen in Stack Overflow questions asked by people reading that 
>book, its ctypes code is generally of poor quality. It only works in 32-bit 
>Python 2 because the author has lazy habits about strings and pointers. 
>Anyway, this issue is closed. There's no bug in Python here. If you have 
>additional questions related to porting old ctypes code to work in Python 3 
>and 64-bit Windows, please ask on ctypes-users [1] or python-list [2]. Many 
>people will be happy to help you.

[1]: https://lists.sourceforge.net/lists/listinfo/ctypes-users
[2]: https://mail.python.org/mailman/listinfo/python-list

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-02 Thread mike peremsky

mike peremsky added the comment:

I appreciate the feedback, but as I had originally mentioned. I am following 
the "Gray Hat Python - Python Programming for Hackers and Reverse Engineers" 
book and was attempting to use Python 3 instead of Python 2 (as was used in the 
book). The cdll code is taken from the book itself. There is nothing that I 
personally plan on doing with this cdll other than to follow along in the book 
and become educated.

"Though if you do really want to use the (very) old msvcrt DLL rather than the 
proper functionality"

If there are better libraries to use I would be interested in knowing what 
those are. What is the "proper functionality"?. I like to educate myself and 
would like to attempt to follow the book using Python 3 and current libraries.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-02 Thread Eryk Sun

Eryk Sun added the comment:

> from ctypes import *
> msvcrt = cdll.msvcrt
> message_string = "Hello World!\n"
> msvcrt.printf("Testing: %s", message_string)

Avoid using libraries as attributes of cdll and windll. They get cached, and in 
turn they cache function pointers. Thus all modules contend for cdll and windll 
function prototype definitions (i.e. argtypes, restype, errcheck), and the last 
one to modify the definition wins. Even if you're not setting prototypes (in 
which case you must really like segfaults, data corruption, and 
difficult-to-diagnose errors), your code will still be at the mercy of 
whichever module does set them. Instead use the following:

msvcrt = ctypes.CDLL('msvcrt', use_errno=True)
msvcrt.printf.argtypes = (ctypes.c_char_p,)

CDLL uses the cdecl calling convention. This convention uses caller stack 
cleanup, so we allow passing a variable number of arguments even though the 
above argtypes definition only checks the first argument.

Examples

You'll get an exception if the first argument isn't bytes:

>>> msvcrt.printf("spam and %d %s\n", 42, "eggs")
Traceback (most recent call last):
  File "", line 1, in 
ctypes.ArgumentError: argument 1: : wrong type

Since we're not checking additional arguments, you might accidentally pass a 
wide-character string. In that case of course the output will be wrong:

>>> msvcrt.printf(b"spam and %d %s\n", 42, "eggs")
spam and 42 e
14

Here we get it right:

>>> msvcrt.printf(b"spam and %d %s\n", 42, b"eggs")
spam and 42 eggs
17

Or maybe you need to print a wide-character string, i.e. "%ls" or "%S":

>>> msvcrt.printf(b"spam and %d %ls\n", 42, "eggs")
spam and 42 eggs
17

or

>>> msvcrt.printf(b"spam and %d %S\n", 42, "eggs")
spam and 42 eggs
17

The "%s" and "%S" convention in MSVC predates standard C. In Microsoft's 
printf, "%s" expects a char pointer and "%S" expects a wchar_t pointer, but in 
their wprintf it's the other way around. In standard C "%s" and "%ls" are 
always a char string and a wchar_t string, respectively. MSVC also supports the 
standard "%ls" for wide-character strings, but its non-standard use of "%s" 
requires the introduction of a non-standard "%hs" for char strings.

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-02 Thread Eryk Sun

Changes by Eryk Sun :


--
Removed message: http://bugs.python.org/msg284525

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-02 Thread Eryk Sun

Eryk Sun added the comment:

> from ctypes import *
> msvcrt = cdll.msvcrt
> message_string = "Hello World!\n"
> msvcrt.printf("Testing: %s", message_string)

Avoid using libraries as attributes of cdll and windll. They get cached, and in 
turn they cache function pointers. Thus all modules contend for cdll and windll 
function prototype definitions (i.e. argtypes, restype, errcheck), and the last 
one to modify the definition wins. Even if you're not setting prototypes (in 
which case you must really like segfaults, data corruption, and 
difficult-to-diagnose errors), your code will still be at the mercy of 
whichever module does set them. Instead use the following:

msvcrt = ctypes.CDLL('msvcrt', use_errno=True)
msvcrt.printf.argtypes = (ctypes.c_char_p,)

CDLL uses the cdecl calling convention. This convention uses callee stack 
cleanup, so we allow passing a variable number of arguments even though the 
above argtypes definition only checks the first argument.

Examples

You'll get an exception if the first argument isn't bytes:

>>> msvcrt.printf("spam and %d %s\n", 42, "eggs")
Traceback (most recent call last):
  File "", line 1, in 
ctypes.ArgumentError: argument 1: : wrong type

Since we're not checking additional arguments, you might accidentally pass a 
wide-character string. In that case of course the output will be wrong:

>>> msvcrt.printf(b"spam and %d %s\n", 42, "eggs")
spam and 42 e
14

Here we get it right:

>>> msvcrt.printf(b"spam and %d %s\n", 42, b"eggs")
spam and 42 eggs
17

Or maybe you need to print a wide-character string, i.e. "%ls" or "%S":

>>> msvcrt.printf(b"spam and %d %ls\n", 42, "eggs")
spam and 42 eggs
17

or

>>> msvcrt.printf(b"spam and %d %S\n", 42, "eggs")
spam and 42 eggs
17

The "%s" and "%S" convention in MSVC predates standard C. In Microsoft's 
printf, "%s" expects a char pointer and "%S" expects a wchar_t pointer, but in 
their wprintf it's the other way around. In standard C "%s" and "%ls" are 
always a char string and a wchar_t string, respectively. MSVC also supports the 
standard "%ls" for wide-character strings, but its non-standard use of "%s" 
requires the introduction of a non-standard "%hs" for char strings.

--
nosy: +eryksun

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-02 Thread R. David Murray

Changes by R. David Murray :


--
resolution:  -> not a bug
stage:  -> resolved
status: open -> closed

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-01 Thread Steve Dower

Steve Dower added the comment:

Though if you do really want to use the (very) old msvcrt DLL rather than the 
proper functionality, calling cdd.msvcrt.wprintf will behave as you expect, or 
prefixing the strings with b (e.g. b"Testing") will pass it as bytes rather 
than wchar_t.

But unless all these suggestions make perfect sense to you, starting with the 
tutorial is probably best :)

--

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-01 Thread Steve Dower

Steve Dower added the comment:

In Python 3, this passes a wchar_t* string, but printf('%s') expects a char* 
string.

You may want to start by looking at the tutorial at 
https://docs.python.org/3/tutorial/index.html to get a feel for what builtins 
are available. Using ctypes is fairly advanced functionality that very rarely 
needs to be used.

--
nosy: +steve.dower

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29131] Calling printf from the cdll does not print the full string

2017-01-01 Thread mike peremsky

New submission from mike peremsky:

I am going throught he Gray Hat Python book and installed Python 3.7 (32-bit) 
on a windows x64 machine. The following code will only print the first 
character of the passed string argument. The same code run on Python 2.7 will 
print the correct string value.


from ctypes import *
 
msvcrt = cdll.msvcrt
 
message_string = "Hello World!\n"
msvcrt.printf("Testing: %s", message_string)
 
Output:
T

--
components: ctypes
messages: 284464
nosy: mperemsky
priority: normal
severity: normal
status: open
title: Calling printf from the cdll does not print the full string
type: behavior
versions: Python 3.3, Python 3.4, Python 3.5, Python 3.6, Python 3.7

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com