blob: fbc34ed7894c230a5c67d1faeb3f4713cb826eb6 [file] [log] [blame]
Nadeem Vawdaced10562011-05-07 13:01:50 +02001from test.support import (TESTFN, run_unittest, import_module, unlink,
2 requires, _2G, _4G)
Thomas Wouters89f507f2006-12-13 04:49:30 +00003import unittest
Antoine Pitrou9e719b62011-02-28 23:48:16 +00004import os, re, itertools, socket, sys
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +00005
R. David Murraya21e4ca2009-03-31 23:16:50 +00006# Skip test if we can't import mmap.
7mmap = import_module('mmap')
8
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +00009PAGESIZE = mmap.PAGESIZE
10
Thomas Wouters89f507f2006-12-13 04:49:30 +000011class MmapTests(unittest.TestCase):
Fred Drake004d5e62000-10-23 17:22:08 +000012
Thomas Wouters89f507f2006-12-13 04:49:30 +000013 def setUp(self):
14 if os.path.exists(TESTFN):
15 os.unlink(TESTFN)
Fred Drake004d5e62000-10-23 17:22:08 +000016
Thomas Wouters89f507f2006-12-13 04:49:30 +000017 def tearDown(self):
Tim Petersfd692082001-05-10 20:03:04 +000018 try:
Fred Drake62787992001-05-11 14:29:21 +000019 os.unlink(TESTFN)
Tim Petersfd692082001-05-10 20:03:04 +000020 except OSError:
21 pass
22
Thomas Wouters89f507f2006-12-13 04:49:30 +000023 def test_basic(self):
24 # Test mmap module on Unix systems and Windows
25
26 # Create a file to be mmap'ed.
Guido van Rossumb358a2c2007-07-16 19:29:02 +000027 f = open(TESTFN, 'bw+')
Thomas Wouters89f507f2006-12-13 04:49:30 +000028 try:
29 # Write 2 pages worth of data to the file
Guido van Rossumb358a2c2007-07-16 19:29:02 +000030 f.write(b'\0'* PAGESIZE)
31 f.write(b'foo')
32 f.write(b'\0'* (PAGESIZE-3) )
Thomas Wouters89f507f2006-12-13 04:49:30 +000033 f.flush()
34 m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000035 finally:
Thomas Wouters89f507f2006-12-13 04:49:30 +000036 f.close()
37
Guido van Rossum456fe5d2007-07-16 19:42:05 +000038 # Simple sanity checks
Thomas Wouters89f507f2006-12-13 04:49:30 +000039
Guido van Rossum456fe5d2007-07-16 19:42:05 +000040 tp = str(type(m)) # SF bug 128713: segfaulted on Linux
Benjamin Petersone099b372009-04-04 17:09:35 +000041 self.assertEqual(m.find(b'foo'), PAGESIZE)
Thomas Wouters89f507f2006-12-13 04:49:30 +000042
Guido van Rossum456fe5d2007-07-16 19:42:05 +000043 self.assertEqual(len(m), 2*PAGESIZE)
Thomas Wouters89f507f2006-12-13 04:49:30 +000044
Guido van Rossum98297ee2007-11-06 21:34:58 +000045 self.assertEqual(m[0], 0)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000046 self.assertEqual(m[0:3], b'\0\0\0')
Thomas Wouters89f507f2006-12-13 04:49:30 +000047
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +000048 # Shouldn't crash on boundary (Issue #5292)
49 self.assertRaises(IndexError, m.__getitem__, len(m))
50 self.assertRaises(IndexError, m.__setitem__, len(m), b'\0')
51
Guido van Rossum456fe5d2007-07-16 19:42:05 +000052 # Modify the file's content
Guido van Rossum98297ee2007-11-06 21:34:58 +000053 m[0] = b'3'[0]
Guido van Rossum456fe5d2007-07-16 19:42:05 +000054 m[PAGESIZE +3: PAGESIZE +3+3] = b'bar'
Thomas Wouters89f507f2006-12-13 04:49:30 +000055
Guido van Rossum456fe5d2007-07-16 19:42:05 +000056 # Check that the modification worked
Guido van Rossum98297ee2007-11-06 21:34:58 +000057 self.assertEqual(m[0], b'3'[0])
Guido van Rossum456fe5d2007-07-16 19:42:05 +000058 self.assertEqual(m[0:3], b'3\0\0')
59 self.assertEqual(m[PAGESIZE-1 : PAGESIZE + 7], b'\0foobar\0')
Thomas Wouters89f507f2006-12-13 04:49:30 +000060
Guido van Rossum456fe5d2007-07-16 19:42:05 +000061 m.flush()
Thomas Wouters89f507f2006-12-13 04:49:30 +000062
Guido van Rossum456fe5d2007-07-16 19:42:05 +000063 # Test doing a regular expression match in an mmap'ed file
Antoine Pitroufd036452008-08-19 17:56:33 +000064 match = re.search(b'[A-Za-z]+', m)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000065 if match is None:
66 self.fail('regex match on mmap failed!')
67 else:
68 start, end = match.span(0)
69 length = end - start
Thomas Wouters89f507f2006-12-13 04:49:30 +000070
Guido van Rossum456fe5d2007-07-16 19:42:05 +000071 self.assertEqual(start, PAGESIZE)
72 self.assertEqual(end, PAGESIZE + 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +000073
Guido van Rossum456fe5d2007-07-16 19:42:05 +000074 # test seeking around (try to overflow the seek implementation)
75 m.seek(0,0)
76 self.assertEqual(m.tell(), 0)
77 m.seek(42,1)
78 self.assertEqual(m.tell(), 42)
79 m.seek(0,2)
80 self.assertEqual(m.tell(), len(m))
Thomas Wouters89f507f2006-12-13 04:49:30 +000081
Guido van Rossum456fe5d2007-07-16 19:42:05 +000082 # Try to seek to negative position...
83 self.assertRaises(ValueError, m.seek, -1)
Thomas Wouters89f507f2006-12-13 04:49:30 +000084
Guido van Rossum456fe5d2007-07-16 19:42:05 +000085 # Try to seek beyond end of mmap...
86 self.assertRaises(ValueError, m.seek, 1, 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +000087
Guido van Rossum456fe5d2007-07-16 19:42:05 +000088 # Try to seek to negative position...
89 self.assertRaises(ValueError, m.seek, -len(m)-1, 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +000090
Guido van Rossum456fe5d2007-07-16 19:42:05 +000091 # Try resizing map
92 try:
93 m.resize(512)
94 except SystemError:
95 # resize() not supported
96 # No messages are printed, since the output of this test suite
97 # would then be different across platforms.
98 pass
99 else:
100 # resize() is supported
101 self.assertEqual(len(m), 512)
102 # Check that we can no longer seek beyond the new size.
103 self.assertRaises(ValueError, m.seek, 513, 0)
104
105 # Check that the underlying file is truncated too
106 # (bug #728515)
107 f = open(TESTFN)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000108 try:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000109 f.seek(0, 2)
110 self.assertEqual(f.tell(), 512)
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000111 finally:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000112 f.close()
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000113 self.assertEqual(m.size(), 512)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000114
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000115 m.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000116
117 def test_access_parameter(self):
118 # Test for "access" keyword parameter
Tim Peters5ebfd362001-11-13 23:11:19 +0000119 mapsize = 10
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000120 open(TESTFN, "wb").write(b"a"*mapsize)
Tim Peters5ebfd362001-11-13 23:11:19 +0000121 f = open(TESTFN, "rb")
122 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000123 self.assertEqual(m[:], b'a'*mapsize, "Readonly memory map data incorrect.")
Tim Peters5ebfd362001-11-13 23:11:19 +0000124
Thomas Wouters89f507f2006-12-13 04:49:30 +0000125 # Ensuring that readonly mmap can't be slice assigned
Tim Peters5ebfd362001-11-13 23:11:19 +0000126 try:
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000127 m[:] = b'b'*mapsize
Tim Peters5ebfd362001-11-13 23:11:19 +0000128 except TypeError:
129 pass
130 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000131 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000132
Thomas Wouters89f507f2006-12-13 04:49:30 +0000133 # Ensuring that readonly mmap can't be item assigned
Tim Peters5ebfd362001-11-13 23:11:19 +0000134 try:
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000135 m[0] = b'b'
Tim Peters5ebfd362001-11-13 23:11:19 +0000136 except TypeError:
137 pass
138 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000139 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000140
Thomas Wouters89f507f2006-12-13 04:49:30 +0000141 # Ensuring that readonly mmap can't be write() to
Tim Peters5ebfd362001-11-13 23:11:19 +0000142 try:
143 m.seek(0,0)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000144 m.write(b'abc')
Tim Peters5ebfd362001-11-13 23:11:19 +0000145 except TypeError:
146 pass
147 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000148 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000149
Thomas Wouters89f507f2006-12-13 04:49:30 +0000150 # Ensuring that readonly mmap can't be write_byte() to
Tim Peters5ebfd362001-11-13 23:11:19 +0000151 try:
152 m.seek(0,0)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000153 m.write_byte(b'd')
Tim Peters5ebfd362001-11-13 23:11:19 +0000154 except TypeError:
155 pass
156 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000157 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000158
Thomas Wouters89f507f2006-12-13 04:49:30 +0000159 # Ensuring that readonly mmap can't be resized
Tim Peters5ebfd362001-11-13 23:11:19 +0000160 try:
161 m.resize(2*mapsize)
162 except SystemError: # resize is not universally supported
163 pass
164 except TypeError:
165 pass
166 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000167 self.fail("Able to resize readonly memory map")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000168 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000169 del m, f
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000170 self.assertEqual(open(TESTFN, "rb").read(), b'a'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000171 "Readonly memory map data file was modified")
172
Thomas Wouters89f507f2006-12-13 04:49:30 +0000173 # Opening mmap with size too big
Neal Norwitzb5673922002-09-05 21:48:07 +0000174 import sys
175 f = open(TESTFN, "r+b")
176 try:
177 m = mmap.mmap(f.fileno(), mapsize+1)
178 except ValueError:
179 # we do not expect a ValueError on Windows
Tim Peters4f4f4d72002-09-10 20:49:15 +0000180 # CAUTION: This also changes the size of the file on disk, and
181 # later tests assume that the length hasn't changed. We need to
182 # repair that.
Neal Norwitzb5673922002-09-05 21:48:07 +0000183 if sys.platform.startswith('win'):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000184 self.fail("Opening mmap with size+1 should work on Windows.")
Neal Norwitzb5673922002-09-05 21:48:07 +0000185 else:
186 # we expect a ValueError on Unix, but not on Windows
187 if not sys.platform.startswith('win'):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000188 self.fail("Opening mmap with size+1 should raise ValueError.")
Barry Warsawccd9e752002-09-11 02:56:42 +0000189 m.close()
Tim Peters4f4f4d72002-09-10 20:49:15 +0000190 f.close()
191 if sys.platform.startswith('win'):
192 # Repair damage from the resizing test.
193 f = open(TESTFN, 'r+b')
194 f.truncate(mapsize)
195 f.close()
Neal Norwitzb5673922002-09-05 21:48:07 +0000196
Thomas Wouters89f507f2006-12-13 04:49:30 +0000197 # Opening mmap with access=ACCESS_WRITE
Tim Peters5ebfd362001-11-13 23:11:19 +0000198 f = open(TESTFN, "r+b")
199 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000200 # Modifying write-through memory map
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000201 m[:] = b'c'*mapsize
202 self.assertEqual(m[:], b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000203 "Write-through memory map memory not updated properly.")
204 m.flush()
Tim Peters1b5112a2002-09-10 21:19:55 +0000205 m.close()
206 f.close()
Tim Peters4f4f4d72002-09-10 20:49:15 +0000207 f = open(TESTFN, 'rb')
208 stuff = f.read()
209 f.close()
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000210 self.assertEqual(stuff, b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000211 "Write-through memory map data file not updated properly.")
212
Thomas Wouters89f507f2006-12-13 04:49:30 +0000213 # Opening mmap with access=ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +0000214 f = open(TESTFN, "r+b")
215 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000216 # Modifying copy-on-write memory map
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000217 m[:] = b'd'*mapsize
218 self.assertEqual(m[:], b'd' * mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000219 "Copy-on-write memory map data not written correctly.")
220 m.flush()
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000221 self.assertEqual(open(TESTFN, "rb").read(), b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000222 "Copy-on-write test data file should not be modified.")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000223 # Ensuring copy-on-write maps cannot be resized
224 self.assertRaises(TypeError, m.resize, 2*mapsize)
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000225 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000226 del m, f
Thomas Wouters89f507f2006-12-13 04:49:30 +0000227
228 # Ensuring invalid access parameter raises exception
229 f = open(TESTFN, "r+b")
230 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
231 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000232
233 if os.name == "posix":
Tim Peters00cafa02001-11-13 23:39:47 +0000234 # Try incompatible flags, prot and access parameters.
235 f = open(TESTFN, "r+b")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000236 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
237 flags=mmap.MAP_PRIVATE,
Tim Peters5ebfd362001-11-13 23:11:19 +0000238 prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
Tim Peters5379dea2002-04-18 04:30:18 +0000239 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000240
Antoine Pitrou7b50c2c2011-03-06 01:47:18 +0100241 # Try writing with PROT_EXEC and without PROT_WRITE
242 prot = mmap.PROT_READ | getattr(mmap, 'PROT_EXEC', 0)
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +0100243 with open(TESTFN, "r+b") as f:
Antoine Pitrou7b50c2c2011-03-06 01:47:18 +0100244 m = mmap.mmap(f.fileno(), mapsize, prot=prot)
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +0100245 self.assertRaises(TypeError, m.write, b"abcdef")
246 self.assertRaises(TypeError, m.write_byte, 0)
247 m.close()
248
Thomas Wouters89f507f2006-12-13 04:49:30 +0000249 def test_bad_file_desc(self):
250 # Try opening a bad file descriptor...
251 self.assertRaises(mmap.error, mmap.mmap, -2, 4096)
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000252
Thomas Wouters89f507f2006-12-13 04:49:30 +0000253 def test_tougher_find(self):
254 # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2,
255 # searching for data with embedded \0 bytes didn't work.
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000256 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000257
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000258 data = b'aabaac\x00deef\x00\x00aa\x00'
Tim Petersc9ffa062002-03-08 05:43:32 +0000259 n = len(data)
260 f.write(data)
Tim Peters5379dea2002-04-18 04:30:18 +0000261 f.flush()
Tim Petersc9ffa062002-03-08 05:43:32 +0000262 m = mmap.mmap(f.fileno(), n)
263 f.close()
264
265 for start in range(n+1):
266 for finish in range(start, n+1):
267 slice = data[start : finish]
Thomas Wouters89f507f2006-12-13 04:49:30 +0000268 self.assertEqual(m.find(slice), data.find(slice))
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000269 self.assertEqual(m.find(slice + b'x'), -1)
Tim Petersddc82ea2003-01-13 21:38:45 +0000270 m.close()
Tim Petersc9ffa062002-03-08 05:43:32 +0000271
Georg Brandlfceab5a2008-01-19 20:08:23 +0000272 def test_find_end(self):
273 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000274 f = open(TESTFN, 'wb+')
275 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000276 n = len(data)
277 f.write(data)
278 f.flush()
279 m = mmap.mmap(f.fileno(), n)
280 f.close()
281
Benjamin Petersone099b372009-04-04 17:09:35 +0000282 self.assertEqual(m.find(b'one'), 0)
283 self.assertEqual(m.find(b'ones'), 8)
284 self.assertEqual(m.find(b'one', 0, -1), 0)
285 self.assertEqual(m.find(b'one', 1), 8)
286 self.assertEqual(m.find(b'one', 1, -1), 8)
287 self.assertEqual(m.find(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000288
289
290 def test_rfind(self):
291 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000292 f = open(TESTFN, 'wb+')
293 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000294 n = len(data)
295 f.write(data)
296 f.flush()
297 m = mmap.mmap(f.fileno(), n)
298 f.close()
299
Benjamin Petersone099b372009-04-04 17:09:35 +0000300 self.assertEqual(m.rfind(b'one'), 8)
301 self.assertEqual(m.rfind(b'one '), 0)
302 self.assertEqual(m.rfind(b'one', 0, -1), 8)
303 self.assertEqual(m.rfind(b'one', 0, -2), 0)
304 self.assertEqual(m.rfind(b'one', 1, -1), 8)
305 self.assertEqual(m.rfind(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000306
307
Thomas Wouters89f507f2006-12-13 04:49:30 +0000308 def test_double_close(self):
309 # make sure a double close doesn't crash on Solaris (Bug# 665913)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000310 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000311
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000312 f.write(2**16 * b'a') # Arbitrary character
Neal Norwitze604c022003-01-10 20:52:16 +0000313 f.close()
314
315 f = open(TESTFN)
Tim Petersddc82ea2003-01-13 21:38:45 +0000316 mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
Neal Norwitze604c022003-01-10 20:52:16 +0000317 mf.close()
318 mf.close()
319 f.close()
320
Thomas Wouters89f507f2006-12-13 04:49:30 +0000321 def test_entire_file(self):
322 # test mapping of entire file by passing 0 for map length
323 if hasattr(os, "stat"):
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000324 f = open(TESTFN, "wb+")
Tim Petersc9ffa062002-03-08 05:43:32 +0000325
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000326 f.write(2**16 * b'm') # Arbitrary character
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000327 f.close()
328
329 f = open(TESTFN, "rb+")
Tim Peterseba28be2005-03-28 01:08:02 +0000330 mf = mmap.mmap(f.fileno(), 0)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000331 self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000332 self.assertEqual(mf.read(2**16), 2**16 * b"m")
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000333 mf.close()
334 f.close()
335
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +0000336 def test_length_0_offset(self):
337 # Issue #10916: test mapping of remainder of file by passing 0 for
338 # map length with an offset doesn't cause a segfault.
339 if not hasattr(os, "stat"):
340 self.skipTest("needs os.stat")
Antoine Pitrou50dc65f2011-01-15 17:31:19 +0000341 # NOTE: allocation granularity is currently 65536 under Win64,
342 # and therefore the minimum offset alignment.
343 with open(TESTFN, "wb") as f:
344 f.write((65536 * 2) * b'm') # Arbitrary character
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +0000345
346 with open(TESTFN, "rb") as f:
Antoine Pitrou50dc65f2011-01-15 17:31:19 +0000347 mf = mmap.mmap(f.fileno(), 0, offset=65536, access=mmap.ACCESS_READ)
348 try:
349 self.assertRaises(IndexError, mf.__getitem__, 80000)
350 finally:
351 mf.close()
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +0000352
Antoine Pitrou6107a4e2011-01-20 21:11:13 +0000353 def test_length_0_large_offset(self):
354 # Issue #10959: test mapping of a file by passing 0 for
355 # map length with a large offset doesn't cause a segfault.
356 if not hasattr(os, "stat"):
357 self.skipTest("needs os.stat")
358
359 with open(TESTFN, "wb") as f:
360 f.write(115699 * b'm') # Arbitrary character
361
362 with open(TESTFN, "w+b") as f:
363 self.assertRaises(ValueError, mmap.mmap, f.fileno(), 0,
364 offset=2147418112)
365
Thomas Wouters89f507f2006-12-13 04:49:30 +0000366 def test_move(self):
367 # make move works everywhere (64-bit format problem earlier)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000368 f = open(TESTFN, 'wb+')
Tim Peterseba28be2005-03-28 01:08:02 +0000369
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000370 f.write(b"ABCDEabcde") # Arbitrary character
Neal Norwitz8856fb72005-12-18 03:34:22 +0000371 f.flush()
372
373 mf = mmap.mmap(f.fileno(), 10)
374 mf.move(5, 0, 5)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000375 self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000376 mf.close()
377 f.close()
378
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000379 # more excessive test
380 data = b"0123456789"
381 for dest in range(len(data)):
382 for src in range(len(data)):
383 for count in range(len(data) - max(dest, src)):
384 expected = data[:dest] + data[src:src+count] + data[dest+count:]
385 m = mmap.mmap(-1, len(data))
386 m[:] = data
387 m.move(dest, src, count)
388 self.assertEqual(m[:], expected)
389 m.close()
390
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +0000391 # segfault test (Issue 5387)
392 m = mmap.mmap(-1, 100)
393 offsets = [-100, -1, 0, 1, 100]
394 for source, dest, size in itertools.product(offsets, offsets, offsets):
395 try:
396 m.move(source, dest, size)
397 except ValueError:
398 pass
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000399
400 offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1),
401 (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
402 for source, dest, size in offsets:
403 self.assertRaises(ValueError, m.move, source, dest, size)
404
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000405 m.close()
406
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000407 m = mmap.mmap(-1, 1) # single byte
408 self.assertRaises(ValueError, m.move, 0, 0, 2)
409 self.assertRaises(ValueError, m.move, 1, 0, 1)
410 self.assertRaises(ValueError, m.move, 0, 1, 1)
411 m.move(0, 0, 1)
412 m.move(0, 0, 0)
413
414
Thomas Wouters89f507f2006-12-13 04:49:30 +0000415 def test_anonymous(self):
416 # anonymous mmap.mmap(-1, PAGE)
417 m = mmap.mmap(-1, PAGESIZE)
Guido van Rossum805365e2007-05-07 22:24:25 +0000418 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000419 self.assertEqual(m[x], 0,
420 "anonymously mmap'ed contents should be zero")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000421
Guido van Rossum805365e2007-05-07 22:24:25 +0000422 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000423 b = x & 0xff
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000424 m[x] = b
425 self.assertEqual(m[x], b)
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000426
Thomas Woutersed03b412007-08-28 21:37:11 +0000427 def test_extended_getslice(self):
428 # Test extended slicing by comparing with list slicing.
429 s = bytes(reversed(range(256)))
430 m = mmap.mmap(-1, len(s))
431 m[:] = s
432 self.assertEqual(m[:], s)
433 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
434 for start in indices:
435 for stop in indices:
436 # Skip step 0 (invalid)
437 for step in indices[1:]:
438 self.assertEqual(m[start:stop:step],
439 s[start:stop:step])
440
441 def test_extended_set_del_slice(self):
442 # Test extended slicing by comparing with list slicing.
443 s = bytes(reversed(range(256)))
444 m = mmap.mmap(-1, len(s))
445 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
446 for start in indices:
447 for stop in indices:
448 # Skip invalid step 0
449 for step in indices[1:]:
450 m[:] = s
451 self.assertEqual(m[:], s)
452 L = list(s)
453 # Make sure we have a slice of exactly the right length,
454 # but with different data.
455 data = L[start:stop:step]
456 data = bytes(reversed(data))
457 L[start:stop:step] = data
458 m[start:stop:step] = data
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000459 self.assertEqual(m[:], bytes(L))
Thomas Woutersed03b412007-08-28 21:37:11 +0000460
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000461 def make_mmap_file (self, f, halfsize):
462 # Write 2 pages worth of data to the file
463 f.write (b'\0' * halfsize)
464 f.write (b'foo')
465 f.write (b'\0' * (halfsize - 3))
466 f.flush ()
467 return mmap.mmap (f.fileno(), 0)
468
469 def test_offset (self):
470 f = open (TESTFN, 'w+b')
471
472 try: # unlink TESTFN no matter what
473 halfsize = mmap.ALLOCATIONGRANULARITY
474 m = self.make_mmap_file (f, halfsize)
475 m.close ()
476 f.close ()
477
478 mapsize = halfsize * 2
479 # Try invalid offset
480 f = open(TESTFN, "r+b")
481 for offset in [-2, -1, None]:
482 try:
483 m = mmap.mmap(f.fileno(), mapsize, offset=offset)
484 self.assertEqual(0, 1)
485 except (ValueError, TypeError, OverflowError):
486 pass
487 else:
488 self.assertEqual(0, 0)
489 f.close()
490
491 # Try valid offset, hopefully 8192 works on all OSes
492 f = open(TESTFN, "r+b")
493 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
494 self.assertEqual(m[0:3], b'foo')
495 f.close()
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000496
497 # Try resizing map
498 try:
499 m.resize(512)
500 except SystemError:
501 pass
502 else:
503 # resize() is supported
504 self.assertEqual(len(m), 512)
505 # Check that we can no longer seek beyond the new size.
506 self.assertRaises(ValueError, m.seek, 513, 0)
507 # Check that the content is not changed
508 self.assertEqual(m[0:3], b'foo')
509
510 # Check that the underlying file is truncated too
511 f = open(TESTFN)
512 f.seek(0, 2)
513 self.assertEqual(f.tell(), halfsize + 512)
514 f.close()
515 self.assertEqual(m.size(), halfsize + 512)
516
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000517 m.close()
518
519 finally:
520 f.close()
521 try:
522 os.unlink(TESTFN)
523 except OSError:
524 pass
525
Christian Heimes1af737c2008-01-23 08:24:23 +0000526 def test_subclass(self):
527 class anon_mmap(mmap.mmap):
528 def __new__(klass, *args, **kwargs):
529 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
530 anon_mmap(PAGESIZE)
531
Christian Heimesa156e092008-02-16 07:38:31 +0000532 def test_prot_readonly(self):
Christian Heimes18c66892008-02-17 13:31:39 +0000533 if not hasattr(mmap, 'PROT_READ'):
534 return
Christian Heimesa156e092008-02-16 07:38:31 +0000535 mapsize = 10
536 open(TESTFN, "wb").write(b"a"*mapsize)
537 f = open(TESTFN, "rb")
538 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
539 self.assertRaises(TypeError, m.write, "foo")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000540 f.close()
Christian Heimes1af737c2008-01-23 08:24:23 +0000541
Christian Heimes7131fd92008-02-19 14:21:46 +0000542 def test_error(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000543 self.assertTrue(issubclass(mmap.error, EnvironmentError))
544 self.assertTrue("mmap.error" in str(mmap.error))
Christian Heimes7131fd92008-02-19 14:21:46 +0000545
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000546 def test_io_methods(self):
547 data = b"0123456789"
548 open(TESTFN, "wb").write(b"x"*len(data))
549 f = open(TESTFN, "r+b")
550 m = mmap.mmap(f.fileno(), len(data))
551 f.close()
552 # Test write_byte()
553 for i in range(len(data)):
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000554 self.assertEqual(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000555 m.write_byte(data[i])
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000556 self.assertEqual(m.tell(), i+1)
Benjamin Petersone099b372009-04-04 17:09:35 +0000557 self.assertRaises(ValueError, m.write_byte, b"x"[0])
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000558 self.assertEqual(m[:], data)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000559 # Test read_byte()
560 m.seek(0)
561 for i in range(len(data)):
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000562 self.assertEqual(m.tell(), i)
563 self.assertEqual(m.read_byte(), data[i])
564 self.assertEqual(m.tell(), i+1)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000565 self.assertRaises(ValueError, m.read_byte)
566 # Test read()
567 m.seek(3)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000568 self.assertEqual(m.read(3), b"345")
569 self.assertEqual(m.tell(), 6)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000570 # Test write()
571 m.seek(3)
572 m.write(b"bar")
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000573 self.assertEqual(m.tell(), 6)
574 self.assertEqual(m[:], b"012bar6789")
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000575 m.seek(8)
576 self.assertRaises(ValueError, m.write, b"bar")
577
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000578 def test_non_ascii_byte(self):
579 for b in (129, 200, 255): # > 128
580 m = mmap.mmap(-1, 1)
581 m.write_byte(b)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000582 self.assertEqual(m[0], b)
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000583 m.seek(0)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000584 self.assertEqual(m.read_byte(), b)
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000585 m.close()
586
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000587 if os.name == 'nt':
588 def test_tagname(self):
589 data1 = b"0123456789"
590 data2 = b"abcdefghij"
591 assert len(data1) == len(data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000592
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000593 # Test same tag
594 m1 = mmap.mmap(-1, len(data1), tagname="foo")
595 m1[:] = data1
596 m2 = mmap.mmap(-1, len(data2), tagname="foo")
597 m2[:] = data2
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000598 self.assertEqual(m1[:], data2)
599 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000600 m2.close()
601 m1.close()
602
Ezio Melotti13925002011-03-16 11:05:33 +0200603 # Test different tag
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000604 m1 = mmap.mmap(-1, len(data1), tagname="foo")
605 m1[:] = data1
606 m2 = mmap.mmap(-1, len(data2), tagname="boo")
607 m2[:] = data2
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000608 self.assertEqual(m1[:], data1)
609 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000610 m2.close()
611 m1.close()
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000612
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000613 def test_crasher_on_windows(self):
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000614 # Should not crash (Issue 1733986)
615 m = mmap.mmap(-1, 1000, tagname="foo")
616 try:
617 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
618 except:
619 pass
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000620 m.close()
621
622 # Should not crash (Issue 5385)
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000623 open(TESTFN, "wb").write(b"x"*10)
624 f = open(TESTFN, "r+b")
625 m = mmap.mmap(f.fileno(), 0)
626 f.close()
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000627 try:
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000628 m.resize(0) # will raise WindowsError
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000629 except:
630 pass
631 try:
632 m[:]
633 except:
634 pass
635 m.close()
636
Brian Curtin686ee4f2010-08-01 15:44:11 +0000637 def test_invalid_descriptor(self):
638 # socket file descriptors are valid, but out of range
639 # for _get_osfhandle, causing a crash when validating the
640 # parameters to _get_osfhandle.
641 s = socket.socket()
642 try:
643 with self.assertRaises(mmap.error):
644 m = mmap.mmap(s.fileno(), 10)
645 finally:
646 s.close()
Christian Heimes7131fd92008-02-19 14:21:46 +0000647
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000648
649class LargeMmapTests(unittest.TestCase):
650
651 def setUp(self):
652 unlink(TESTFN)
653
654 def tearDown(self):
655 unlink(TESTFN)
656
Nadeem Vawdaced10562011-05-07 13:01:50 +0200657 def _create_test_file(self, num_zeroes, tail):
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000658 if sys.platform[:3] == 'win' or sys.platform == 'darwin':
659 requires('largefile',
660 'test requires %s bytes and a long time to run' % str(0x180000000))
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000661 with open(TESTFN, 'wb') as f:
Nadeem Vawdaced10562011-05-07 13:01:50 +0200662 try:
663 f.seek(num_zeroes)
664 f.write(tail)
665 f.flush()
666 except (IOError, OverflowError):
667 raise unittest.SkipTest("filesystem does not have largefile support")
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000668
Nadeem Vawdaced10562011-05-07 13:01:50 +0200669 def test_large_offset(self):
670 self._create_test_file(0x14FFFFFFF, b" ")
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000671 with open(TESTFN, 'rb') as f:
672 m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ)
673 try:
674 self.assertEqual(m[0xFFFFFFF], 32)
675 finally:
676 m.close()
677
678 def test_large_filesize(self):
Nadeem Vawdaced10562011-05-07 13:01:50 +0200679 self._create_test_file(0x17FFFFFFF, b" ")
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000680 with open(TESTFN, 'rb') as f:
681 m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ)
682 try:
683 self.assertEqual(m.size(), 0x180000000)
684 finally:
685 m.close()
686
Nadeem Vawdaced10562011-05-07 13:01:50 +0200687 # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X.
688
689 def _test_around_boundary(self, boundary):
690 tail = b' DEARdear '
691 start = boundary - len(tail) // 2
692 end = start + len(tail)
693 self._create_test_file(start, tail)
694 with open(TESTFN, 'rb') as f:
695 m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
696 try:
697 self.assertEqual(m[start:end], tail)
698 finally:
699 m.close()
700
701 @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems")
702 def test_around_2GB(self):
703 self._test_around_boundary(_2G)
704
705 @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems")
706 def test_around_4GB(self):
707 self._test_around_boundary(_4G)
708
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000709
Thomas Wouters89f507f2006-12-13 04:49:30 +0000710def test_main():
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000711 run_unittest(MmapTests, LargeMmapTests)
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +0000712
Thomas Wouters89f507f2006-12-13 04:49:30 +0000713if __name__ == '__main__':
714 test_main()