Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(43129)

Side by Side Diff: Lib/uuid.py

Issue 20519: ctypes.create_string_buffer creates reference cycles
Patch Set: Created 3 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Lib/test/test_uuid.py ('k') | Modules/_uuidmodule.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 r"""UUID objects (universally unique identifiers) according to RFC 4122. 1 r"""UUID objects (universally unique identifiers) according to RFC 4122.
2 2
3 This module provides immutable UUID objects (class UUID) and the functions 3 This module provides immutable UUID objects (class UUID) and the functions
4 uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5 4 uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
5 UUIDs as specified in RFC 4122. 5 UUIDs as specified in RFC 4122.
6 6
7 If all you want is a unique ID, you should probably call uuid1() or uuid4(). 7 If all you want is a unique ID, you should probably call uuid1() or uuid4().
8 Note that uuid1() may compromise privacy since it creates a UUID containing 8 Note that uuid1() may compromise privacy since it creates a UUID containing
9 the computer's network address. uuid4() creates a random UUID. 9 the computer's network address. uuid4() creates a random UUID.
10 10
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 status._unpack() 418 status._unpack()
419 bytes = status.adapter_address 419 bytes = status.adapter_address
420 return ((bytes[0]<<40) + (bytes[1]<<32) + (bytes[2]<<24) + 420 return ((bytes[0]<<40) + (bytes[1]<<32) + (bytes[2]<<24) +
421 (bytes[3]<<16) + (bytes[4]<<8) + bytes[5]) 421 (bytes[3]<<16) + (bytes[4]<<8) + bytes[5])
422 422
423 # Thanks to Thomas Heller for ctypes and for his help with its use here. 423 # Thanks to Thomas Heller for ctypes and for his help with its use here.
424 424
425 # If ctypes is available, use it to find system routines for UUID generation. 425 # If ctypes is available, use it to find system routines for UUID generation.
426 # XXX This makes the module non-thread-safe! 426 # XXX This makes the module non-thread-safe!
427 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None 427 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None
428 try:
429 import ctypes, ctypes.util
430 428
431 # The uuid_generate_* routines are provided by libuuid on at least
432 # Linux and FreeBSD, and provided by libc on Mac OS X.
433 for libname in ['uuid', 'c']:
434 try:
435 lib = ctypes.CDLL(ctypes.util.find_library(libname))
436 except:
437 continue
438 if hasattr(lib, 'uuid_generate_random'):
439 _uuid_generate_random = lib.uuid_generate_random
440 if hasattr(lib, 'uuid_generate_time'):
441 _uuid_generate_time = lib.uuid_generate_time
442 if _uuid_generate_random is not None:
443 break # found everything we were looking for
444 429
430 import sys
431 import os
432
433 if sys.platform == "darwin" and int(os.uname().release.split('.')[0]) < 9:
445 # The uuid_generate_* functions are broken on MacOS X 10.5, as noted 434 # The uuid_generate_* functions are broken on MacOS X 10.5, as noted
446 # in issue #8621 the function generates the same sequence of values 435 # in issue #8621 the function generates the same sequence of values
447 # in the parent process and all children created using fork (unless 436 # in the parent process and all children created using fork (unless
448 # those children use exec as well). 437 # those children use exec as well).
449 # 438 #
450 # Assume that the uuid_generate functions are broken from 10.5 onward, 439 # Assume that the uuid_generate functions are broken from 10.5 onward,
451 # the test can be adjusted when a later version is fixed. 440 # the test can be adjusted when a later version is fixed.
452 import sys 441 _uuid = None
453 if sys.platform == 'darwin': 442 else:
454 import os 443 try:
455 if int(os.uname().release.split('.')[0]) >= 9: 444 import _uuid
456 _uuid_generate_random = _uuid_generate_time = None 445 except ImportError:
446 _uuid = None
457 447
458 # On Windows prior to 2000, UuidCreate gives a UUID containing the 448 if _uuid is None:
459 # hardware address. On Windows 2000 and later, UuidCreate makes a
460 # random UUID and UuidCreateSequential gives a UUID containing the
461 # hardware address. These routines are provided by the RPC runtime.
462 # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
463 # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
464 # to bear any relationship to the MAC address of any network device
465 # on the box.
466 try: 449 try:
467 lib = ctypes.windll.rpcrt4 450 # If we couldn't find an extension module, try ctypes
468 except: 451 import ctypes
469 lib = None 452 import ctypes.util
470 _UuidCreate = getattr(lib, 'UuidCreateSequential', 453
471 getattr(lib, 'UuidCreate', None)) 454 # The uuid_generate_* routines are provided by libuuid on at least
472 except: 455 # Linux and FreeBSD, and provided by libc on Mac OS X.
473 pass 456 for libname in ['uuid', 'c']:
457 try:
458 lib = ctypes.CDLL(ctypes.util.find_library(libname))
459 except:
460 continue
461 if hasattr(lib, 'uuid_generate_random'):
462 _uuid_generate_random = lib.uuid_generate_random
463 if hasattr(lib, 'uuid_generate_time'):
464 _uuid_generate_time = lib.uuid_generate_time
465 if _uuid_generate_random is not None:
466 break # found everything we were looking for
467
468 # The uuid_generate_* functions are broken on MacOS X 10.5, as noted
469 # in issue #8621 the function generates the same sequence of values
470 # in the parent process and all children created using fork (unless
471 # those children use exec as well).
472 #
473 # Assume that the uuid_generate functions are broken from 10.5 onward,
474 # the test can be adjusted when a later version is fixed.
475 if sys.platform == 'darwin':
476 if int(os.uname().release.split('.')[0]) >= 9:
477 _uuid_generate_random = _uuid_generate_time = None
478
479 # On Windows prior to 2000, UuidCreate gives a UUID containing the
480 # hardware address. On Windows 2000 and later, UuidCreate makes a
481 # random UUID and UuidCreateSequential gives a UUID containing the
482 # hardware address. These routines are provided by the RPC runtime.
483 # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
484 # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
485 # to bear any relationship to the MAC address of any network device
486 # on the box.
487 try:
488 lib = ctypes.windll.rpcrt4
489 except:
490 lib = None
491 _UuidCreate = getattr(lib, 'UuidCreateSequential',
492 getattr(lib, 'UuidCreate', None))
493 except Exception as ex:
494 import warnings
495 warnings.warn("Could not find fallback ctypes uuid functions: {}"
496 .format(ex),
497 ImportWarning)
498
474 499
475 def _unixdll_getnode(): 500 def _unixdll_getnode():
476 """Get the hardware address on Unix using ctypes.""" 501 """Get the hardware address on Unix using ctypes."""
477 _buffer = ctypes.create_string_buffer(16) 502 _buffer = ctypes.create_string_buffer(16)
478 _uuid_generate_time(_buffer) 503 _uuid_generate_time(_buffer)
479 return UUID(bytes=bytes_(_buffer.raw)).node 504 return UUID(bytes=bytes_(_buffer.raw)).node
505
506
507 def _unix_extmod_getnode():
508 """Get the hardware address on Unix using the _uuid extension module."""
509 uuid_time = _uuid.generate_time()
510 return UUID(bytes=uuid_time).node
511
480 512
481 def _windll_getnode(): 513 def _windll_getnode():
482 """Get the hardware address on Windows using ctypes.""" 514 """Get the hardware address on Windows using ctypes."""
483 _buffer = ctypes.create_string_buffer(16) 515 _buffer = ctypes.create_string_buffer(16)
484 if _UuidCreate(_buffer) == 0: 516 if _UuidCreate(_buffer) == 0:
485 return UUID(bytes=bytes_(_buffer.raw)).node 517 return UUID(bytes=bytes_(_buffer.raw)).node
486 518
519
487 def _random_getnode(): 520 def _random_getnode():
488 """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" 521 """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
489 import random 522 import random
490 return random.randrange(0, 1<<48) | 0x010000000000 523 return random.randrange(0, 1<<48) | 0x010000000000
491 524
492 _node = None 525 _node = None
526
493 527
494 def getnode(): 528 def getnode():
495 """Get the hardware address as a 48-bit positive integer. 529 """Get the hardware address as a 48-bit positive integer.
496 530
497 The first time this runs, it may launch a separate program, which could 531 The first time this runs, it may launch a separate program, which could
498 be quite slow. If all attempts to obtain the hardware address fail, we 532 be quite slow. If all attempts to obtain the hardware address fail, we
499 choose a random 48-bit number with its eighth bit set to 1 as recommended 533 choose a random 48-bit number with its eighth bit set to 1 as recommended
500 in RFC 4122. 534 in RFC 4122.
501 """ 535 """
502 536
503 global _node 537 global _node
504 if _node is not None: 538 if _node is not None:
505 return _node 539 return _node
506 540
507 import sys 541 import sys
508 if sys.platform == 'win32': 542 if sys.platform == 'win32':
509 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] 543 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
510 else: 544 else:
511 getters = [_unixdll_getnode, _ifconfig_getnode] 545 getters = [_unix_extmod_getnode, _unixdll_getnode, _ifconfig_getnode]
512 546
513 for getter in getters + [_random_getnode]: 547 for getter in getters + [_random_getnode]:
514 try: 548 try:
515 _node = getter() 549 _node = getter()
516 except: 550 except:
517 continue 551 continue
518 if _node is not None: 552 if _node is not None:
519 return _node 553 return _node
520 554
521 _last_timestamp = None 555 _last_timestamp = None
556
522 557
523 def uuid1(node=None, clock_seq=None): 558 def uuid1(node=None, clock_seq=None):
524 """Generate a UUID from a host ID, sequence number, and the current time. 559 """Generate a UUID from a host ID, sequence number, and the current time.
525 If 'node' is not given, getnode() is used to obtain the hardware 560 If 'node' is not given, getnode() is used to obtain the hardware
526 address. If 'clock_seq' is given, it is used as the sequence number; 561 address. If 'clock_seq' is given, it is used as the sequence number;
527 otherwise a random 14-bit sequence number is chosen.""" 562 otherwise a random 14-bit sequence number is chosen."""
528 563
529 # When the system provides a version-1 UUID generator, use it (but don't 564 # When the system provides a version-1 UUID generator, use it (but don't
530 # use UuidCreate here because its UUIDs don't conform to RFC 4122). 565 # use UuidCreate here because its UUIDs don't conform to RFC 4122).
566 if _uuid is not None and node is clock_seq is None:
567 return UUID(bytes=_uuid.generate_time())
531 if _uuid_generate_time and node is clock_seq is None: 568 if _uuid_generate_time and node is clock_seq is None:
532 _buffer = ctypes.create_string_buffer(16) 569 _buffer = ctypes.create_string_buffer(16)
533 _uuid_generate_time(_buffer) 570 _uuid_generate_time(_buffer)
534 return UUID(bytes=bytes_(_buffer.raw)) 571 return UUID(bytes=bytes_(_buffer.raw))
535 572
536 global _last_timestamp 573 global _last_timestamp
537 import time 574 import time
538 nanoseconds = int(time.time() * 1e9) 575 nanoseconds = int(time.time() * 1e9)
539 # 0x01b21dd213814000 is the number of 100-ns intervals between the 576 # 0x01b21dd213814000 is the number of 100-ns intervals between the
540 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. 577 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
541 timestamp = int(nanoseconds/100) + 0x01b21dd213814000 578 timestamp = int(nanoseconds/100) + 0x01b21dd213814000
542 if _last_timestamp is not None and timestamp <= _last_timestamp: 579 if _last_timestamp is not None and timestamp <= _last_timestamp:
543 timestamp = _last_timestamp + 1 580 timestamp = _last_timestamp + 1
544 _last_timestamp = timestamp 581 _last_timestamp = timestamp
545 if clock_seq is None: 582 if clock_seq is None:
546 import random 583 import random
547 clock_seq = random.randrange(1<<14) # instead of stable storage 584 clock_seq = random.randrange(1<<14) # instead of stable storage
548 time_low = timestamp & 0xffffffff 585 time_low = timestamp & 0xffffffff
549 time_mid = (timestamp >> 32) & 0xffff 586 time_mid = (timestamp >> 32) & 0xffff
550 time_hi_version = (timestamp >> 48) & 0x0fff 587 time_hi_version = (timestamp >> 48) & 0x0fff
551 clock_seq_low = clock_seq & 0xff 588 clock_seq_low = clock_seq & 0xff
552 clock_seq_hi_variant = (clock_seq >> 8) & 0x3f 589 clock_seq_hi_variant = (clock_seq >> 8) & 0x3f
553 if node is None: 590 if node is None:
554 node = getnode() 591 node = getnode()
555 return UUID(fields=(time_low, time_mid, time_hi_version, 592 return UUID(fields=(time_low, time_mid, time_hi_version,
556 clock_seq_hi_variant, clock_seq_low, node), version=1) 593 clock_seq_hi_variant, clock_seq_low, node), version=1)
594
557 595
558 def uuid3(namespace, name): 596 def uuid3(namespace, name):
559 """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" 597 """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
560 from hashlib import md5 598 from hashlib import md5
561 hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() 599 hash = md5(namespace.bytes + bytes(name, "utf-8")).digest()
562 return UUID(bytes=hash[:16], version=3) 600 return UUID(bytes=hash[:16], version=3)
563 601
602
564 def uuid4(): 603 def uuid4():
565 """Generate a random UUID.""" 604 """Generate a random UUID."""
566 605
567 # When the system provides a version-4 UUID generator, use it. 606 # When the system provides a version-4 UUID generator, use it.
607 if _uuid is not None:
608 return UUID(bytes=_uuid.generate_random())
568 if _uuid_generate_random: 609 if _uuid_generate_random:
569 _buffer = ctypes.create_string_buffer(16) 610 _buffer = ctypes.create_string_buffer(16)
570 _uuid_generate_random(_buffer) 611 _uuid_generate_random(_buffer)
571 return UUID(bytes=bytes_(_buffer.raw)) 612 return UUID(bytes=bytes_(_buffer.raw))
572 613
573 # Otherwise, get randomness from urandom or the 'random' module. 614 # Otherwise, get randomness from urandom or the 'random' module.
574 try: 615 try:
575 import os 616 import os
576 return UUID(bytes=os.urandom(16), version=4) 617 return UUID(bytes=os.urandom(16), version=4)
577 except: 618 except:
578 import random 619 import random
579 bytes = bytes_(random.randrange(256) for i in range(16)) 620 bytes = bytes_(random.randrange(256) for i in range(16))
580 return UUID(bytes=bytes, version=4) 621 return UUID(bytes=bytes, version=4)
622
581 623
582 def uuid5(namespace, name): 624 def uuid5(namespace, name):
583 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" 625 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
584 from hashlib import sha1 626 from hashlib import sha1
585 hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest() 627 hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest()
586 return UUID(bytes=hash[:16], version=5) 628 return UUID(bytes=hash[:16], version=5)
587 629
588 # The following standard UUIDs are for use with uuid3() or uuid5(). 630 # The following standard UUIDs are for use with uuid3() or uuid5().
589 631
590 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') 632 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
591 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') 633 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
592 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') 634 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
593 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') 635 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
OLDNEW
« no previous file with comments | « Lib/test/test_uuid.py ('k') | Modules/_uuidmodule.c » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+