1from test.test_support import (TESTFN, run_unittest, import_module, unlink, 2 requires, _2G, _4G, gc_collect, cpython_only) 3import unittest 4import os, re, itertools, socket, sys 5 6mmap = import_module('mmap') 7 8PAGESIZE = mmap.PAGESIZE 9 10class MmapTests(unittest.TestCase): 11 12 def setUp(self): 13 if os.path.exists(TESTFN): 14 os.unlink(TESTFN) 15 16 def tearDown(self): 17 try: 18 os.unlink(TESTFN) 19 except OSError: 20 pass 21 22 def test_basic(self): 23 # Test mmap module on Unix systems and Windows 24 25 # Create a file to be mmap'ed. 26 f = open(TESTFN, 'w+') 27 try: 28 # Write 2 pages worth of data to the file 29 f.write('\0'* PAGESIZE) 30 f.write('foo') 31 f.write('\0'* (PAGESIZE-3) ) 32 f.flush() 33 m = mmap.mmap(f.fileno(), 2 * PAGESIZE) 34 f.close() 35 36 # Simple sanity checks 37 38 tp = str(type(m)) # SF bug 128713: segfaulted on Linux 39 self.assertEqual(m.find('foo'), PAGESIZE) 40 41 self.assertEqual(len(m), 2*PAGESIZE) 42 43 self.assertEqual(m[0], '\0') 44 self.assertEqual(m[0:3], '\0\0\0') 45 46 # Shouldn't crash on boundary (Issue #5292) 47 self.assertRaises(IndexError, m.__getitem__, len(m)) 48 self.assertRaises(IndexError, m.__setitem__, len(m), '\0') 49 50 # Modify the file's content 51 m[0] = '3' 52 m[PAGESIZE +3: PAGESIZE +3+3] = 'bar' 53 54 # Check that the modification worked 55 self.assertEqual(m[0], '3') 56 self.assertEqual(m[0:3], '3\0\0') 57 self.assertEqual(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0') 58 59 m.flush() 60 61 # Test doing a regular expression match in an mmap'ed file 62 match = re.search('[A-Za-z]+', m) 63 if match is None: 64 self.fail('regex match on mmap failed!') 65 else: 66 start, end = match.span(0) 67 length = end - start 68 69 self.assertEqual(start, PAGESIZE) 70 self.assertEqual(end, PAGESIZE + 6) 71 72 # test seeking around (try to overflow the seek implementation) 73 m.seek(0,0) 74 self.assertEqual(m.tell(), 0) 75 m.seek(42,1) 76 self.assertEqual(m.tell(), 42) 77 m.seek(0,2) 78 self.assertEqual(m.tell(), len(m)) 79 80 # Try to seek to negative position... 81 self.assertRaises(ValueError, m.seek, -1) 82 83 # Try to seek beyond end of mmap... 84 self.assertRaises(ValueError, m.seek, 1, 2) 85 86 # Try to seek to negative position... 87 self.assertRaises(ValueError, m.seek, -len(m)-1, 2) 88 89 # Try resizing map 90 try: 91 m.resize(512) 92 except SystemError: 93 # resize() not supported 94 # No messages are printed, since the output of this test suite 95 # would then be different across platforms. 96 pass 97 else: 98 # resize() is supported 99 self.assertEqual(len(m), 512) 100 # Check that we can no longer seek beyond the new size. 101 self.assertRaises(ValueError, m.seek, 513, 0) 102 103 # Check that the underlying file is truncated too 104 # (bug #728515) 105 f = open(TESTFN) 106 f.seek(0, 2) 107 self.assertEqual(f.tell(), 512) 108 f.close() 109 self.assertEqual(m.size(), 512) 110 111 m.close() 112 113 finally: 114 try: 115 f.close() 116 except OSError: 117 pass 118 119 def test_access_parameter(self): 120 # Test for "access" keyword parameter 121 mapsize = 10 122 open(TESTFN, "wb").write("a"*mapsize) 123 f = open(TESTFN, "rb") 124 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ) 125 self.assertEqual(m[:], 'a'*mapsize, "Readonly memory map data incorrect.") 126 127 # Ensuring that readonly mmap can't be slice assigned 128 try: 129 m[:] = 'b'*mapsize 130 except TypeError: 131 pass 132 else: 133 self.fail("Able to write to readonly memory map") 134 135 # Ensuring that readonly mmap can't be item assigned 136 try: 137 m[0] = 'b' 138 except TypeError: 139 pass 140 else: 141 self.fail("Able to write to readonly memory map") 142 143 # Ensuring that readonly mmap can't be write() to 144 try: 145 m.seek(0,0) 146 m.write('abc') 147 except TypeError: 148 pass 149 else: 150 self.fail("Able to write to readonly memory map") 151 152 # Ensuring that readonly mmap can't be write_byte() to 153 try: 154 m.seek(0,0) 155 m.write_byte('d') 156 except TypeError: 157 pass 158 else: 159 self.fail("Able to write to readonly memory map") 160 161 # Ensuring that readonly mmap can't be resized 162 try: 163 m.resize(2*mapsize) 164 except SystemError: # resize is not universally supported 165 pass 166 except TypeError: 167 pass 168 else: 169 self.fail("Able to resize readonly memory map") 170 f.close() 171 del m, f 172 self.assertEqual(open(TESTFN, "rb").read(), 'a'*mapsize, 173 "Readonly memory map data file was modified") 174 175 # Opening mmap with size too big 176 import sys 177 f = open(TESTFN, "r+b") 178 try: 179 m = mmap.mmap(f.fileno(), mapsize+1) 180 except ValueError: 181 # we do not expect a ValueError on Windows 182 # CAUTION: This also changes the size of the file on disk, and 183 # later tests assume that the length hasn't changed. We need to 184 # repair that. 185 if sys.platform.startswith('win'): 186 self.fail("Opening mmap with size+1 should work on Windows.") 187 else: 188 # we expect a ValueError on Unix, but not on Windows 189 if not sys.platform.startswith('win'): 190 self.fail("Opening mmap with size+1 should raise ValueError.") 191 m.close() 192 f.close() 193 if sys.platform.startswith('win'): 194 # Repair damage from the resizing test. 195 f = open(TESTFN, 'r+b') 196 f.truncate(mapsize) 197 f.close() 198 199 # Opening mmap with access=ACCESS_WRITE 200 f = open(TESTFN, "r+b") 201 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE) 202 # Modifying write-through memory map 203 m[:] = 'c'*mapsize 204 self.assertEqual(m[:], 'c'*mapsize, 205 "Write-through memory map memory not updated properly.") 206 m.flush() 207 m.close() 208 f.close() 209 f = open(TESTFN, 'rb') 210 stuff = f.read() 211 f.close() 212 self.assertEqual(stuff, 'c'*mapsize, 213 "Write-through memory map data file not updated properly.") 214 215 # Opening mmap with access=ACCESS_COPY 216 f = open(TESTFN, "r+b") 217 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY) 218 # Modifying copy-on-write memory map 219 m[:] = 'd'*mapsize 220 self.assertEqual(m[:], 'd' * mapsize, 221 "Copy-on-write memory map data not written correctly.") 222 m.flush() 223 self.assertEqual(open(TESTFN, "rb").read(), 'c'*mapsize, 224 "Copy-on-write test data file should not be modified.") 225 # Ensuring copy-on-write maps cannot be resized 226 self.assertRaises(TypeError, m.resize, 2*mapsize) 227 f.close() 228 del m, f 229 230 # Ensuring invalid access parameter raises exception 231 f = open(TESTFN, "r+b") 232 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4) 233 f.close() 234 235 if os.name == "posix": 236 # Try incompatible flags, prot and access parameters. 237 f = open(TESTFN, "r+b") 238 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, 239 flags=mmap.MAP_PRIVATE, 240 prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE) 241 f.close() 242 243 # Try writing with PROT_EXEC and without PROT_WRITE 244 prot = mmap.PROT_READ | getattr(mmap, 'PROT_EXEC', 0) 245 with open(TESTFN, "r+b") as f: 246 m = mmap.mmap(f.fileno(), mapsize, prot=prot) 247 self.assertRaises(TypeError, m.write, b"abcdef") 248 self.assertRaises(TypeError, m.write_byte, 0) 249 m.close() 250 251 def test_bad_file_desc(self): 252 # Try opening a bad file descriptor... 253 self.assertRaises(mmap.error, mmap.mmap, -2, 4096) 254 255 def test_tougher_find(self): 256 # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2, 257 # searching for data with embedded \0 bytes didn't work. 258 f = open(TESTFN, 'w+') 259 260 data = 'aabaac\x00deef\x00\x00aa\x00' 261 n = len(data) 262 f.write(data) 263 f.flush() 264 m = mmap.mmap(f.fileno(), n) 265 f.close() 266 267 for start in range(n+1): 268 for finish in range(start, n+1): 269 slice = data[start : finish] 270 self.assertEqual(m.find(slice), data.find(slice)) 271 self.assertEqual(m.find(slice + 'x'), -1) 272 m.close() 273 274 def test_find_end(self): 275 # test the new 'end' parameter works as expected 276 f = open(TESTFN, 'w+') 277 data = 'one two ones' 278 n = len(data) 279 f.write(data) 280 f.flush() 281 m = mmap.mmap(f.fileno(), n) 282 f.close() 283 284 self.assertEqual(m.find('one'), 0) 285 self.assertEqual(m.find('ones'), 8) 286 self.assertEqual(m.find('one', 0, -1), 0) 287 self.assertEqual(m.find('one', 1), 8) 288 self.assertEqual(m.find('one', 1, -1), 8) 289 self.assertEqual(m.find('one', 1, -2), -1) 290 291 292 def test_rfind(self): 293 # test the new 'end' parameter works as expected 294 f = open(TESTFN, 'w+') 295 data = 'one two ones' 296 n = len(data) 297 f.write(data) 298 f.flush() 299 m = mmap.mmap(f.fileno(), n) 300 f.close() 301 302 self.assertEqual(m.rfind('one'), 8) 303 self.assertEqual(m.rfind('one '), 0) 304 self.assertEqual(m.rfind('one', 0, -1), 8) 305 self.assertEqual(m.rfind('one', 0, -2), 0) 306 self.assertEqual(m.rfind('one', 1, -1), 8) 307 self.assertEqual(m.rfind('one', 1, -2), -1) 308 309 310 def test_double_close(self): 311 # make sure a double close doesn't crash on Solaris (Bug# 665913) 312 f = open(TESTFN, 'w+') 313 314 f.write(2**16 * 'a') # Arbitrary character 315 f.close() 316 317 f = open(TESTFN) 318 mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ) 319 mf.close() 320 mf.close() 321 f.close() 322 323 @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()") 324 def test_entire_file(self): 325 # test mapping of entire file by passing 0 for map length 326 f = open(TESTFN, "w+") 327 328 f.write(2**16 * 'm') # Arbitrary character 329 f.close() 330 331 f = open(TESTFN, "rb+") 332 mf = mmap.mmap(f.fileno(), 0) 333 self.assertEqual(len(mf), 2**16, "Map size should equal file size.") 334 self.assertEqual(mf.read(2**16), 2**16 * "m") 335 mf.close() 336 f.close() 337 338 @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()") 339 def test_length_0_offset(self): 340 # Issue #10916: test mapping of remainder of file by passing 0 for 341 # map length with an offset doesn't cause a segfault. 342 # NOTE: allocation granularity is currently 65536 under Win64, 343 # and therefore the minimum offset alignment. 344 with open(TESTFN, "wb") as f: 345 f.write((65536 * 2) * b'm') # Arbitrary character 346 347 with open(TESTFN, "rb") as f: 348 mf = mmap.mmap(f.fileno(), 0, offset=65536, access=mmap.ACCESS_READ) 349 try: 350 self.assertRaises(IndexError, mf.__getitem__, 80000) 351 finally: 352 mf.close() 353 354 @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()") 355 def test_length_0_large_offset(self): 356 # Issue #10959: test mapping of a file by passing 0 for 357 # map length with a large offset doesn't cause a segfault. 358 with open(TESTFN, "wb") as f: 359 f.write(115699 * b'm') # Arbitrary character 360 361 with open(TESTFN, "w+b") as f: 362 self.assertRaises(ValueError, mmap.mmap, f.fileno(), 0, 363 offset=2147418112) 364 365 def test_move(self): 366 # make move works everywhere (64-bit format problem earlier) 367 f = open(TESTFN, 'w+') 368 369 f.write("ABCDEabcde") # Arbitrary character 370 f.flush() 371 372 mf = mmap.mmap(f.fileno(), 10) 373 mf.move(5, 0, 5) 374 self.assertEqual(mf[:], "ABCDEABCDE", "Map move should have duplicated front 5") 375 mf.close() 376 f.close() 377 378 # more excessive test 379 data = "0123456789" 380 for dest in range(len(data)): 381 for src in range(len(data)): 382 for count in range(len(data) - max(dest, src)): 383 expected = data[:dest] + data[src:src+count] + data[dest+count:] 384 m = mmap.mmap(-1, len(data)) 385 m[:] = data 386 m.move(dest, src, count) 387 self.assertEqual(m[:], expected) 388 m.close() 389 390 # segfault test (Issue 5387) 391 m = mmap.mmap(-1, 100) 392 offsets = [-100, -1, 0, 1, 100] 393 for source, dest, size in itertools.product(offsets, offsets, offsets): 394 try: 395 m.move(source, dest, size) 396 except ValueError: 397 pass 398 399 offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1), 400 (-1, 0, 0), (0, -1, 0), (0, 0, -1)] 401 for source, dest, size in offsets: 402 self.assertRaises(ValueError, m.move, source, dest, size) 403 404 m.close() 405 406 m = mmap.mmap(-1, 1) # single byte 407 self.assertRaises(ValueError, m.move, 0, 0, 2) 408 self.assertRaises(ValueError, m.move, 1, 0, 1) 409 self.assertRaises(ValueError, m.move, 0, 1, 1) 410 m.move(0, 0, 1) 411 m.move(0, 0, 0) 412 413 414 def test_anonymous(self): 415 # anonymous mmap.mmap(-1, PAGE) 416 m = mmap.mmap(-1, PAGESIZE) 417 for x in xrange(PAGESIZE): 418 self.assertEqual(m[x], '\0', "anonymously mmap'ed contents should be zero") 419 420 for x in xrange(PAGESIZE): 421 m[x] = ch = chr(x & 255) 422 self.assertEqual(m[x], ch) 423 424 def test_extended_getslice(self): 425 # Test extended slicing by comparing with list slicing. 426 s = "".join(chr(c) for c in reversed(range(256))) 427 m = mmap.mmap(-1, len(s)) 428 m[:] = s 429 self.assertEqual(m[:], s) 430 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) 431 for start in indices: 432 for stop in indices: 433 # Skip step 0 (invalid) 434 for step in indices[1:]: 435 self.assertEqual(m[start:stop:step], 436 s[start:stop:step]) 437 438 def test_extended_set_del_slice(self): 439 # Test extended slicing by comparing with list slicing. 440 s = "".join(chr(c) for c in reversed(range(256))) 441 m = mmap.mmap(-1, len(s)) 442 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) 443 for start in indices: 444 for stop in indices: 445 # Skip invalid step 0 446 for step in indices[1:]: 447 m[:] = s 448 self.assertEqual(m[:], s) 449 L = list(s) 450 # Make sure we have a slice of exactly the right length, 451 # but with different data. 452 data = L[start:stop:step] 453 data = "".join(reversed(data)) 454 L[start:stop:step] = data 455 m[start:stop:step] = data 456 self.assertEqual(m[:], "".join(L)) 457 458 def make_mmap_file (self, f, halfsize): 459 # Write 2 pages worth of data to the file 460 f.write ('\0' * halfsize) 461 f.write ('foo') 462 f.write ('\0' * (halfsize - 3)) 463 f.flush () 464 return mmap.mmap (f.fileno(), 0) 465 466 def test_empty_file (self): 467 f = open (TESTFN, 'w+b') 468 f.close() 469 with open(TESTFN, "rb") as f : 470 self.assertRaisesRegexp(ValueError, 471 "cannot mmap an empty file", 472 mmap.mmap, f.fileno(), 0, 473 access=mmap.ACCESS_READ) 474 475 def test_offset (self): 476 f = open (TESTFN, 'w+b') 477 478 try: # unlink TESTFN no matter what 479 halfsize = mmap.ALLOCATIONGRANULARITY 480 m = self.make_mmap_file (f, halfsize) 481 m.close () 482 f.close () 483 484 mapsize = halfsize * 2 485 # Try invalid offset 486 f = open(TESTFN, "r+b") 487 for offset in [-2, -1, None]: 488 try: 489 m = mmap.mmap(f.fileno(), mapsize, offset=offset) 490 self.assertEqual(0, 1) 491 except (ValueError, TypeError, OverflowError): 492 pass 493 else: 494 self.assertEqual(0, 0) 495 f.close() 496 497 # Try valid offset, hopefully 8192 works on all OSes 498 f = open(TESTFN, "r+b") 499 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize) 500 self.assertEqual(m[0:3], 'foo') 501 f.close() 502 503 # Try resizing map 504 try: 505 m.resize(512) 506 except SystemError: 507 pass 508 else: 509 # resize() is supported 510 self.assertEqual(len(m), 512) 511 # Check that we can no longer seek beyond the new size. 512 self.assertRaises(ValueError, m.seek, 513, 0) 513 # Check that the content is not changed 514 self.assertEqual(m[0:3], 'foo') 515 516 # Check that the underlying file is truncated too 517 f = open(TESTFN) 518 f.seek(0, 2) 519 self.assertEqual(f.tell(), halfsize + 512) 520 f.close() 521 self.assertEqual(m.size(), halfsize + 512) 522 523 m.close() 524 525 finally: 526 f.close() 527 try: 528 os.unlink(TESTFN) 529 except OSError: 530 pass 531 532 def test_subclass(self): 533 class anon_mmap(mmap.mmap): 534 def __new__(klass, *args, **kwargs): 535 return mmap.mmap.__new__(klass, -1, *args, **kwargs) 536 anon_mmap(PAGESIZE) 537 538 @unittest.skipUnless(hasattr(mmap, 'PROT_READ'), "needs mmap.PROT_READ") 539 def test_prot_readonly(self): 540 mapsize = 10 541 open(TESTFN, "wb").write("a"*mapsize) 542 f = open(TESTFN, "rb") 543 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ) 544 self.assertRaises(TypeError, m.write, "foo") 545 f.close() 546 547 def test_error(self): 548 self.assertTrue(issubclass(mmap.error, EnvironmentError)) 549 self.assertIn("mmap.error", str(mmap.error)) 550 551 def test_io_methods(self): 552 data = "0123456789" 553 open(TESTFN, "wb").write("x"*len(data)) 554 f = open(TESTFN, "r+b") 555 m = mmap.mmap(f.fileno(), len(data)) 556 f.close() 557 # Test write_byte() 558 for i in xrange(len(data)): 559 self.assertEqual(m.tell(), i) 560 m.write_byte(data[i]) 561 self.assertEqual(m.tell(), i+1) 562 self.assertRaises(ValueError, m.write_byte, "x") 563 self.assertEqual(m[:], data) 564 # Test read_byte() 565 m.seek(0) 566 for i in xrange(len(data)): 567 self.assertEqual(m.tell(), i) 568 self.assertEqual(m.read_byte(), data[i]) 569 self.assertEqual(m.tell(), i+1) 570 self.assertRaises(ValueError, m.read_byte) 571 # Test read() 572 m.seek(3) 573 self.assertEqual(m.read(3), "345") 574 self.assertEqual(m.tell(), 6) 575 # Test write() 576 m.seek(3) 577 m.write("bar") 578 self.assertEqual(m.tell(), 6) 579 self.assertEqual(m[:], "012bar6789") 580 m.seek(8) 581 self.assertRaises(ValueError, m.write, "bar") 582 583 @unittest.skipUnless(os.name == 'nt', 'requires Windows') 584 def test_tagname(self): 585 data1 = "0123456789" 586 data2 = "abcdefghij" 587 assert len(data1) == len(data2) 588 589 # Test same tag 590 m1 = mmap.mmap(-1, len(data1), tagname="foo") 591 m1[:] = data1 592 m2 = mmap.mmap(-1, len(data2), tagname="foo") 593 m2[:] = data2 594 self.assertEqual(m1[:], data2) 595 self.assertEqual(m2[:], data2) 596 m2.close() 597 m1.close() 598 599 # Test different tag 600 m1 = mmap.mmap(-1, len(data1), tagname="foo") 601 m1[:] = data1 602 m2 = mmap.mmap(-1, len(data2), tagname="boo") 603 m2[:] = data2 604 self.assertEqual(m1[:], data1) 605 self.assertEqual(m2[:], data2) 606 m2.close() 607 m1.close() 608 609 @cpython_only 610 @unittest.skipUnless(os.name == 'nt', 'requires Windows') 611 def test_sizeof(self): 612 m1 = mmap.mmap(-1, 100) 613 tagname = "foo" 614 m2 = mmap.mmap(-1, 100, tagname=tagname) 615 self.assertEqual(sys.getsizeof(m2), 616 sys.getsizeof(m1) + len(tagname) + 1) 617 618 @unittest.skipUnless(os.name == 'nt', 'requires Windows') 619 def test_crasher_on_windows(self): 620 # Should not crash (Issue 1733986) 621 m = mmap.mmap(-1, 1000, tagname="foo") 622 try: 623 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size 624 except: 625 pass 626 m.close() 627 628 # Should not crash (Issue 5385) 629 open(TESTFN, "wb").write("x"*10) 630 f = open(TESTFN, "r+b") 631 m = mmap.mmap(f.fileno(), 0) 632 f.close() 633 try: 634 m.resize(0) # will raise WindowsError 635 except: 636 pass 637 try: 638 m[:] 639 except: 640 pass 641 m.close() 642 643 @unittest.skipUnless(os.name == 'nt', 'requires Windows') 644 def test_invalid_descriptor(self): 645 # socket file descriptors are valid, but out of range 646 # for _get_osfhandle, causing a crash when validating the 647 # parameters to _get_osfhandle. 648 s = socket.socket() 649 try: 650 with self.assertRaises(mmap.error): 651 m = mmap.mmap(s.fileno(), 10) 652 finally: 653 s.close() 654 655 @unittest.skipIf(os.name == 'nt', 'cannot resize anonymous mmaps on Windows') 656 def test_resize_past_pos(self): 657 m = mmap.mmap(-1, 8192) 658 self.addCleanup(m.close) 659 m.read(5000) 660 try: 661 m.resize(4096) 662 except SystemError: 663 self.skipTest("resizing not supported") 664 self.assertEqual(m.read(14), '') 665 self.assertRaises(ValueError, m.read_byte) 666 self.assertRaises(ValueError, m.write_byte, 'b') 667 self.assertRaises(ValueError, m.write, 'abc') 668 669 def test_concat_repeat_exception(self): 670 m = mmap.mmap(-1, 16) 671 with self.assertRaises(TypeError): 672 m + m 673 with self.assertRaises(TypeError): 674 m * 2 675 676 677class LargeMmapTests(unittest.TestCase): 678 679 def setUp(self): 680 unlink(TESTFN) 681 682 def tearDown(self): 683 unlink(TESTFN) 684 685 def _make_test_file(self, num_zeroes, tail): 686 if sys.platform[:3] == 'win' or sys.platform == 'darwin': 687 requires('largefile', 688 'test requires %s bytes and a long time to run' % str(0x180000000)) 689 f = open(TESTFN, 'w+b') 690 try: 691 f.seek(num_zeroes) 692 f.write(tail) 693 f.flush() 694 except (IOError, OverflowError): 695 f.close() 696 raise unittest.SkipTest("filesystem does not have largefile support") 697 return f 698 699 def test_large_offset(self): 700 with self._make_test_file(0x14FFFFFFF, b" ") as f: 701 m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ) 702 try: 703 self.assertEqual(m[0xFFFFFFF], b" ") 704 finally: 705 m.close() 706 707 def test_large_filesize(self): 708 with self._make_test_file(0x17FFFFFFF, b" ") as f: 709 if sys.maxsize < 0x180000000: 710 # On 32 bit platforms the file is larger than sys.maxsize so 711 # mapping the whole file should fail -- Issue #16743 712 with self.assertRaises(OverflowError): 713 mmap.mmap(f.fileno(), 0x180000000, access=mmap.ACCESS_READ) 714 with self.assertRaises(ValueError): 715 mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) 716 m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ) 717 try: 718 self.assertEqual(m.size(), 0x180000000) 719 finally: 720 m.close() 721 722 # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X. 723 724 def _test_around_boundary(self, boundary): 725 tail = b' DEARdear ' 726 start = boundary - len(tail) // 2 727 end = start + len(tail) 728 with self._make_test_file(start, tail) as f: 729 m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) 730 try: 731 self.assertEqual(m[start:end], tail) 732 finally: 733 m.close() 734 735 @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") 736 def test_around_2GB(self): 737 self._test_around_boundary(_2G) 738 739 @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems") 740 def test_around_4GB(self): 741 self._test_around_boundary(_4G) 742 743 744def test_main(): 745 run_unittest(MmapTests, LargeMmapTests) 746 747if __name__ == '__main__': 748 test_main() 749