Is this a Python 3.x.x bug?

Following my OSX bash bug discovery the other week what about this baby.

Just to let you guys know, since my post Sinclair Spectrum days where it was impossible to do a syntax error I do a great deal of syntax juggling to see what works on the few languages that I know, and I have done it for years, a form of hacking if you like......

I found this and mentioned it to someone I know on a python list.
NOTE: The help in the second code snippet. It seems that the string length is printed to sys.stderr .
The guy said it was part of the standard library in Version 3.x.x, NOT in Version 2.7.x and lower.

This IS actually in Python 3.x's standard library!? <Shock!>

I don't know about the latest Python 3.6.1 as I have not installed it yet.
The use of Python's exit function here is none standard but it does NOT give an error.
INSTEAD it gives a return code of the string length.
Surely this HAS to be a bug?

Last login: Wed Jun  7 13:16:13 on ttys000
AMIGA:amiga~> python3.5
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> help(sys.stdout.write)

>>> sys.stdout.write("Hello World!\n")
Hello World!
13
>>> exit(sys.stdout.write("Hello World!\n"))
Hello World!
AMIGA:amiga~> echo "$?"
13
AMIGA:amiga~> _

OUCH!
The help(sys.stdout.write) on python3.5.x

Help on built-in function write:

write(text, /) method of _io.TextIOWrapper instance
    Write string to stream.
    Returns the number of characters written (which is always equal to
    the length of the string).
(END)

Comments anyone?

EDIT:
OSX 10.12.5, default bash terminal running Python 3.5.2 in interactive mode.

Oh dear this is even worse!
It even does it in a called script from a bash script...

#!/bin/bash
echo "Hello World!"
python3.5 "$HOME/Desktop/Code/Python/PythonRC.py"
echo "Return code is $?..."
import sys
print("Now in Python script!")
sys.exit(sys.stdout.write("Goodbye World!\n"))

Results, same system as before...

Last login: Thu Jun  8 14:33:04 on ttys000
AMIGA:amiga~> cd Desktop/Code/Shell
AMIGA:amiga~/Desktop/Code/Shell> chmod 755 PythonRC.sh
AMIGA:amiga~/Desktop/Code/Shell> ./PythonRC.sh
Hello World!
Now in Python script!
Goodbye World!
Return code is 15...
AMIGA:amiga~/Desktop/Code/Shell> _

EDIT:
Makes one wonder what a string greater than 255 characters would give, (wrap around the 255 bash shell boundary). What about returning these values to other languages and OSes?

For me, python is a large snake, or a flying circus, but what you show above would be the expected behaviour and absolutely makes sense to me. In the languages I know, exit (or similar) can take a value, even from a variable or a function, which becomes the program's "exit code". Why not deploy write 's return value of 15? awk example:

awk 'END {X=7; exit X}'
echo $?
7

For values greater than 255, usually the lower byte is evaluated.

I seem to recall you making a thread about this before, and it was determined that printing the return values to stderr was a feature Python does in interactive mode.

As for it returning 15? It's actually very standard to give exit() a code in most languages, if Python didn't it'd be the weird one. And it is documented, here:

Yes, the exit value is communicated to BASH, the calling process, that is its function, to tell it whether the program succeeded or failed.

@ RudiC...
How about this then?

#!/bin/bash
echo "Inside bash shell here."
python3.5 "$HOME/Desktop/Code/Python/exit_malicious.py"
echo "Back inside bash shell with exit code $?..."
import os
print("Inside the Python script.")
text=10
text=input("Enter your text:- ")
exit(os.system(text))
print("This will never be reached...")

Result:-

Last login: Thu Jun  8 18:43:20 on ttys000
AMIGA:amiga~> cd Desktop/Code/Shell
AMIGA:amiga~/Desktop/Code/Shell> chmod 755 exit_malicious.sh
AMIGA:amiga~/Desktop/Code/Shell> ./exit_malicious.sh
Inside bash shell here.
Inside the Python script.
Enter your text:- echo "Launch my malicious code here whilst exiting Python..."
Launch my malicious code here whilst exiting Python...
Back inside bash shell with exit code 0...
AMIGA:amiga~/Desktop/Code/Shell> _

@Corona688...
No that was something entirely different using the shell's exit, it is on here I will find the pointer.

EDIT:
I appreciate this is hypothetical but if I can create this then a deep professional would know fully how to exploit it.

---------- Post updated at 07:36 PM ---------- Previous update was at 06:58 PM ----------

'END' just hangs on this machine so 'BEGIN' instead.
Hmmm, so this is normal proceedure?

Last login: Thu Jun  8 19:21:58 on ttys000
AMIGA:amiga~> awk --version
awk version 20070501
AMIGA:amiga~> awk 'BEGIN { x=13; x=system("ls -l"); exit x; }'
total 2120
-rwxr-xr-x   1 amiga  staff  217121 20 May 14:23 06500.sh.txt
-rw-r--r--   1 amiga  staff    5128 22 May 14:16 06500.txt
drwxr-xr-x   3 amiga  staff     102  2 Jan 15:42 Applications
-rw-r--r--   1 amiga  staff   20715  3 Jun 13:47 AudioScope.Circuits
-rw-r--r--   1 amiga  staff     315  3 Jun 13:47 AudioScope.Config
-rw-r--r--   1 amiga  staff  118305  3 Jun 13:47 AudioScope.Manual
-rwxr-xr-x   1 amiga  staff  220419  3 Jun 12:00 AudioScope.sh
-rwxr-xr-x   1 amiga  staff  220418  3 Jun 11:45 AudioScope.sh~
-rw-r--r--   1 amiga  staff  220047 24 May 18:35 AudioScope24-05-2017.sh
-rw-r--r--   1 amiga  staff    6307  3 Jun 13:47 AudioScope_Quick_Start.Notes
drwx------+ 12 amiga  staff     408  3 Jun 20:25 Desktop
drwx------+  8 amiga  staff     272 31 Dec 15:23 Documents
drwx------+ 22 amiga  staff     748  7 Jun 13:12 Downloads
drwx------@ 58 amiga  staff    1972 18 May 18:08 Library
drwx------+  3 amiga  staff     102 24 Oct  2016 Movies
drwx------+  6 amiga  staff     204 14 Dec 22:16 Music
-rwxr-xr-x   1 amiga  staff     751 18 May 17:39 NewCLI
drwx------+  6 amiga  staff     204 16 May 14:23 Pictures
drwxr-xr-x   3 amiga  staff     102 11 Dec 17:34 Programs
drwxr-xr-x+  6 amiga  staff     204 18 May 18:36 Public
drwxr-xr-x  56 amiga  staff    1904 18 May 17:45 Scope
drwxr-xr-x  27 amiga  staff     918  3 Jun 12:01 Temp
drwxr-xr-x   4 amiga  staff     136 14 Oct  2016 URL
-rw-r--r--   1 amiga  staff   28518 31 May 20:00 sample.txt
drwxr-xr-x@ 14 amiga  staff     476  7 Nov  2016 sox-14.4.2
-rwxr-xr-x   1 amiga  staff     751 20 May 09:07 xterm
AMIGA:amiga~> echo "Return code, $?..."
Return code, 0...
AMIGA:amiga~> _

I can't tell what value os.system.text will return. Is it a function returning successfully? Certainly not an integer value. I ponder a pointer of which the low order byte is 0.

It doesn't "hang", it reads from stdin / tty, so hit a <CTRL>-D as an EOF char.

Yes, exactly ls -l completed successfully and returned a 0.

Hi RudiC...

So one is allowed to execute code AFTER exit has been called even if it is an ASCII string inside a variable, from awk AND Python and I thought Python was strict, what about Perl and others?
Awk's exit is a statement and Python's is a function.

Maybe it is just me but this should never be allowed to happen if the RC is not an integer. BTW thanks for the Ctrl-D heads up, I had forgotten all about that, however 'ls -l' is still executed.

Hi Corona688...
It was this, it always needs a redirection to a file for it to work however, so nothing like the other two and technically MUCH safer:-

Last login: Thu Jun  8 21:10:58 on ttys000
AMIGA:amiga~> exit 10 $( ls -l /tmp/ > /tmp/text )
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

Last login: Thu Jun  8 21:11:40 on ttys000
AMIGA:amiga~> cat /tmp/text
total 0
drwx------  3 amiga  wheel  102  8 Jun 18:27 com.apple.launchd.QBBc1cRjqo
drwx------  3 amiga  wheel  102  8 Jun 18:27 com.apple.launchd.iC1FUcCphs
-rw-r--r--  1 amiga  wheel    0  8 Jun 21:12 text
AMIGA:amiga~> _

And yes, I know why the 'text' file_length reads zero, 0.

You don't "execute code AFTER exit" - you add one (or more) routines to the sequence of tasks the programme has to perform before giving control back to the caller, e.g. closing files, releasing locks, freeing allocated memory. If it is a write , you'd mayhap do it before stdout is closed, if it is just a number, you reference it just on exiting.

Both - whatever they are - start quitting the programme.

Pascal wouldn't allow non-integers, C mayhap would - python might be somewhere in between.

1 Like

Huh? That program is nonsense... Safer than what? And how?