diff --git a/Demo/embed/Makefile b/Demo/embed/Makefile index 857b5e51690..711b95bbf74 100644 --- a/Demo/embed/Makefile +++ b/Demo/embed/Makefile @@ -22,7 +22,7 @@ CPPFLAGS= $(INCLUDES) LIBPYTHON= $(blddir)/libpython$(VERSION).a # XXX edit LIBS (in particular) to match $(blddir)/Modules/Makefile -LIBS= -lnsl -ldl -lreadline -ltermcap -lieee -lpthread -lutil +LIBS= -lnsl -ldl -lreadline -lieee -lpthread -lutil LDFLAGS= -Xlinker -export-dynamic SYSLIBS= -lm MODLIBS= diff --git a/Demo/embed/demo.c b/Demo/embed/demo.c index 22bfaff4fd2..99d39ca6e33 100644 --- a/Demo/embed/demo.c +++ b/Demo/embed/demo.c @@ -22,8 +22,17 @@ main(int argc, char **argv) /* Define sys.argv. It is up to the application if you want this; you can also let it undefined (since the Python code is generally not a main program it has no business - touching sys.argv...) */ - PySys_SetArgv(2, args); + touching sys.argv...) + + If the third argument is true, sys.path is modified to include + either the directory containing the script named by argv[0], or + the current working directory. This can be risky; if you run + an application embedding Python in a directory controlled by + someone else, attackers could put a Trojan-horse module in the + directory (say, a file named os.py) that your application would + then import and run. + */ + PySys_SetArgvEx(2, args, 0); /* Do some application specific code */ printf("Hello, brave new world\n\n"); diff --git a/Demo/embed/loop.c b/Demo/embed/loop.c index 2f7fe621c93..4a341fdf522 100644 --- a/Demo/embed/loop.c +++ b/Demo/embed/loop.c @@ -19,7 +19,7 @@ main(int argc, char **argv) count = atoi(argv[2]); } - Py_SetProgramName(argv[0]); + Py_SetProgramName(L"loop"); /* uncomment this if you don't want to load site.py */ /* Py_NoSiteFlag = 1; */ diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 9cb80b99230..e584396caf7 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -439,19 +439,21 @@ class Morsel(dict): # _LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]" -_CookiePattern = re.compile( - r"(?x)" # This is a Verbose pattern - r"(?P" # Start of group 'key' - ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy - r")" # End of group 'key' - r"\s*=\s*" # Equal Sign - r"(?P" # Start of group 'val' - r'"(?:[^\\"]|\\.)*"' # Any doublequoted string - r"|" # or - ""+ _LegalCharsPatt +"*" # Any word or empty string - r")" # End of group 'val' - r"\s*;?" # Probably ending in a semi-colon - , re.ASCII) # May be removed if safe. +_CookiePattern = re.compile(r""" + (?x) # This is a verbose pattern + (?P # Start of group 'key' + """ + _LegalCharsPatt + r"""+? # Any word of at least one letter + ) # End of group 'key' + \s*=\s* # Equal Sign + (?P # Start of group 'val' + "(?:[^\\"]|\\.)*" # Any doublequoted string + | # or + \w{3},\s[\w\d-]{9,11}\s[\d:]{8}\sGMT # Special case for "expires" attr + | # or + """ + _LegalCharsPatt + r"""* # Any word or empty string + ) # End of group 'val' + \s*;? # Probably ending in a semi-colon + """, re.ASCII) # May be removed if safe. # At long last, here is the cookie class. diff --git a/Lib/posixpath.py b/Lib/posixpath.py index aace2b203d3..d317cebd9b7 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -197,6 +197,9 @@ def samestat(s1, s2): def ismount(path): """Test whether a path is a mount point""" + if islink(path): + # A symlink can never be a mount point + return False try: s1 = os.lstat(path) if isinstance(path, bytes): diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index 158dd634b0b..99133f79290 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -65,6 +65,36 @@ class CookieTests(unittest.TestCase): """) + def test_special_attrs(self): + # 'expires' + C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') + C['Customer']['expires'] = 0 + # can't test exact output, it always depends on current date/time + self.assertTrue(C.output().endswith('GMT')) + + # loading 'expires' + C = cookies.SimpleCookie() + C.load('Customer="W"; expires=Wed, 01-Jan-2010 00:00:00 GMT') + self.assertEqual(C['Customer']['expires'], + 'Wed, 01-Jan-2010 00:00:00 GMT') + C = cookies.SimpleCookie() + C.load('Customer="W"; expires=Wed, 01-Jan-98 00:00:00 GMT') + self.assertEqual(C['Customer']['expires'], + 'Wed, 01-Jan-98 00:00:00 GMT') + + # 'max-age' + C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') + C['Customer']['max-age'] = 10 + self.assertEqual(C.output(), + 'Set-Cookie: Customer="WILE_E_COYOTE"; Max-Age=10') + + # others + C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') + C['Customer']['secure'] = True + C['Customer']['httponly'] = True + self.assertEqual(C.output(), + 'Set-Cookie: Customer="WILE_E_COYOTE"; httponly; secure') + def test_quoted_meta(self): # Try cookie with quoted meta-data C = cookies.SimpleCookie() diff --git a/Lib/timeit.py b/Lib/timeit.py index 7b9b72c82e9..c3f6753c665 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -9,7 +9,7 @@ the Python Cookbook, published by O'Reilly. Library usage: see the Timer class. Command line usage: - python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement] + python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [--] [statement] Options: -n/--number N: how many times to execute 'statement' (default: see below) @@ -19,6 +19,7 @@ Options: -c/--clock: use time.clock() (default on Windows) -v/--verbose: print raw timing results; repeat for more digits precision -h/--help: print this usage message and exit + --: separate options from statement, use when statement starts with - statement: statement to be timed (default 'pass') A multi-line statement may be given by specifying each line as a diff --git a/Lib/trace.py b/Lib/trace.py index 49ad7a8cb78..f408705a692 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -192,11 +192,13 @@ def fullmodname(path): base = path[len(longest) + 1:] else: base = path + # the drive letter is never part of the module name + drive, base = os.path.splitdrive(base) base = base.replace(os.sep, ".") if os.altsep: base = base.replace(os.altsep, ".") filename, ext = os.path.splitext(base) - return filename + return filename.lstrip(".") class CoverageResults: def __init__(self, counts=None, calledfuncs=None, infile=None, @@ -799,7 +801,14 @@ def main(argv=None): try: with open(progname) as fp: code = compile(fp.read(), progname, 'exec') - t.run(code) + # try to emulate __main__ namespace as much as possible + globs = { + '__file__': progname, + '__name__': '__main__', + '__package__': None, + '__cached__': None, + } + t.runctx(code, globs, globs) except IOError as err: _err_exit("Cannot run file %r because: %s" % (sys.argv[0], err)) except SystemExit: diff --git a/Misc/NEWS b/Misc/NEWS index 6e52ecb1047..3637754fe1a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -84,6 +84,13 @@ C-API Library ------- +- Issue #1713: Fix os.path.ismount(), which returned true for symbolic links + across devices. + +- Issue #8826: Properly load old-style "expires" attribute in http.cookies. + +- Issue #1690103: Fix initial namespace for code run with trace.main(). + - Issue #9448: Fix a leak of OS resources (mutexes or semaphores) when re-initializing a buffered IO object by calling its ``__init__`` method.