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

Delta Between Two Patch Sets: Lib/uuid.py

Issue 20519: ctypes.create_string_buffer creates reference cycles
Left Patch Set: Created 5 years, 7 months ago
Right 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/test_uuid.py ('k') | Modules/_uuidmodule.c » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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: 428
429 import ctypes, ctypes.util 429
430 430 import sys
431 import os
432
433 if sys.platform == "darwin" and int(os.uname().release.split('.')[0]) < 9:
434 # The uuid_generate_* functions are broken on MacOS X 10.5, as noted
435 # in issue #8621 the function generates the same sequence of values
436 # in the parent process and all children created using fork (unless
437 # those children use exec as well).
438 #
439 # Assume that the uuid_generate functions are broken from 10.5 onward,
440 # the test can be adjusted when a later version is fixed.
441 _uuid = None
442 else:
431 try: 443 try:
432 import _uuid 444 import _uuid
433 except ImportError: 445 except ImportError:
434 _uuid = None 446 _uuid = None
435 447
436 # On Windows prior to 2000, UuidCreate gives a UUID containing the 448 if _uuid is None:
437 # hardware address. On Windows 2000 and later, UuidCreate makes a
438 # random UUID and UuidCreateSequential gives a UUID containing the
439 # hardware address. These routines are provided by the RPC runtime.
440 # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
441 # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
442 # to bear any relationship to the MAC address of any network device
443 # on the box.
444 import ctypes, ctypes.util
445 try: 449 try:
446 lib = ctypes.windll.rpcrt4 450 # If we couldn't find an extension module, try ctypes
447 except: 451 import ctypes
448 lib = None 452 import ctypes.util
449 _UuidCreate = getattr(lib, 'UuidCreateSequential', 453
450 getattr(lib, 'UuidCreate', None)) 454 # The uuid_generate_* routines are provided by libuuid on at least
451 except: 455 # Linux and FreeBSD, and provided by libc on Mac OS X.
452 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
453 499
454 def _unixdll_getnode(): 500 def _unixdll_getnode():
455 """Get the hardware address on Unix using ctypes.""" 501 """Get the hardware address on Unix using ctypes."""
456 _buffer = ctypes.create_string_buffer(16) 502 _buffer = ctypes.create_string_buffer(16)
457 _uuid_generate_time(_buffer) 503 _uuid_generate_time(_buffer)
458 return UUID(bytes=bytes_(_buffer.raw)).node 504 return UUID(bytes=bytes_(_buffer.raw)).node
459 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
512
460 def _windll_getnode(): 513 def _windll_getnode():
461 """Get the hardware address on Windows using ctypes.""" 514 """Get the hardware address on Windows using ctypes."""
462 _buffer = ctypes.create_string_buffer(16) 515 _buffer = ctypes.create_string_buffer(16)
463 if _UuidCreate(_buffer) == 0: 516 if _UuidCreate(_buffer) == 0:
464 return UUID(bytes=bytes_(_buffer.raw)).node 517 return UUID(bytes=bytes_(_buffer.raw)).node
465 518
519
466 def _random_getnode(): 520 def _random_getnode():
467 """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."""
468 import random 522 import random
469 return random.randrange(0, 1<<48) | 0x010000000000 523 return random.randrange(0, 1<<48) | 0x010000000000
470 524
471 _node = None 525 _node = None
526
472 527
473 def getnode(): 528 def getnode():
474 """Get the hardware address as a 48-bit positive integer. 529 """Get the hardware address as a 48-bit positive integer.
475 530
476 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
477 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
478 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
479 in RFC 4122. 534 in RFC 4122.
480 """ 535 """
481 536
482 global _node 537 global _node
483 if _node is not None: 538 if _node is not None:
484 return _node 539 return _node
485 540
486 import sys 541 import sys
487 if sys.platform == 'win32': 542 if sys.platform == 'win32':
488 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] 543 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
489 else: 544 else:
490 getters = [_unixdll_getnode, _ifconfig_getnode] 545 getters = [_unix_extmod_getnode, _unixdll_getnode, _ifconfig_getnode]
491 546
492 for getter in getters + [_random_getnode]: 547 for getter in getters + [_random_getnode]:
493 try: 548 try:
494 _node = getter() 549 _node = getter()
495 except: 550 except:
496 continue 551 continue
497 if _node is not None: 552 if _node is not None:
498 return _node 553 return _node
499 554
500 _last_timestamp = None 555 _last_timestamp = None
501 556
557
502 def uuid1(node=None, clock_seq=None): 558 def uuid1(node=None, clock_seq=None):
503 """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.
504 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
505 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;
506 otherwise a random 14-bit sequence number is chosen.""" 562 otherwise a random 14-bit sequence number is chosen."""
507 563
508 # 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
509 # 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())
510 if _uuid_generate_time and node is clock_seq is None: 568 if _uuid_generate_time and node is clock_seq is None:
511 _buffer = ctypes.create_string_buffer(16) 569 _buffer = ctypes.create_string_buffer(16)
512 _uuid_generate_time(_buffer) 570 _uuid_generate_time(_buffer)
513 return UUID(bytes=bytes_(_buffer.raw)) 571 return UUID(bytes=bytes_(_buffer.raw))
514 572
515 global _last_timestamp 573 global _last_timestamp
516 import time 574 import time
517 nanoseconds = int(time.time() * 1e9) 575 nanoseconds = int(time.time() * 1e9)
518 # 0x01b21dd213814000 is the number of 100-ns intervals between the 576 # 0x01b21dd213814000 is the number of 100-ns intervals between the
519 # 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.
520 timestamp = int(nanoseconds/100) + 0x01b21dd213814000 578 timestamp = int(nanoseconds/100) + 0x01b21dd213814000
521 if _last_timestamp is not None and timestamp <= _last_timestamp: 579 if _last_timestamp is not None and timestamp <= _last_timestamp:
522 timestamp = _last_timestamp + 1 580 timestamp = _last_timestamp + 1
523 _last_timestamp = timestamp 581 _last_timestamp = timestamp
524 if clock_seq is None: 582 if clock_seq is None:
525 import random 583 import random
526 clock_seq = random.randrange(1<<14) # instead of stable storage 584 clock_seq = random.randrange(1<<14) # instead of stable storage
527 time_low = timestamp & 0xffffffff 585 time_low = timestamp & 0xffffffff
528 time_mid = (timestamp >> 32) & 0xffff 586 time_mid = (timestamp >> 32) & 0xffff
529 time_hi_version = (timestamp >> 48) & 0x0fff 587 time_hi_version = (timestamp >> 48) & 0x0fff
530 clock_seq_low = clock_seq & 0xff 588 clock_seq_low = clock_seq & 0xff
531 clock_seq_hi_variant = (clock_seq >> 8) & 0x3f 589 clock_seq_hi_variant = (clock_seq >> 8) & 0x3f
532 if node is None: 590 if node is None:
533 node = getnode() 591 node = getnode()
534 return UUID(fields=(time_low, time_mid, time_hi_version, 592 return UUID(fields=(time_low, time_mid, time_hi_version,
535 clock_seq_hi_variant, clock_seq_low, node), version=1) 593 clock_seq_hi_variant, clock_seq_low, node), version=1)
536 594
595
537 def uuid3(namespace, name): 596 def uuid3(namespace, name):
538 """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."""
539 from hashlib import md5 598 from hashlib import md5
540 hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() 599 hash = md5(namespace.bytes + bytes(name, "utf-8")).digest()
541 return UUID(bytes=hash[:16], version=3) 600 return UUID(bytes=hash[:16], version=3)
542 601
602
543 def uuid4(): 603 def uuid4():
544 """Generate a random UUID.""" 604 """Generate a random UUID."""
545 605
546 # When the system provides a version-4 UUID generator, use it. 606 # When the system provides a version-4 UUID generator, use it.
547 if _uuid is not None: 607 if _uuid is not None:
548 return UUID(bytes=_uuid.generate_random()) 608 return UUID(bytes=_uuid.generate_random())
609 if _uuid_generate_random:
610 _buffer = ctypes.create_string_buffer(16)
611 _uuid_generate_random(_buffer)
612 return UUID(bytes=bytes_(_buffer.raw))
549 613
550 # Otherwise, get randomness from urandom or the 'random' module. 614 # Otherwise, get randomness from urandom or the 'random' module.
551 try: 615 try:
552 import os 616 import os
553 return UUID(bytes=os.urandom(16), version=4) 617 return UUID(bytes=os.urandom(16), version=4)
554 except: 618 except:
555 import random 619 import random
556 bytes = bytes_(random.randrange(256) for i in range(16)) 620 bytes = bytes_(random.randrange(256) for i in range(16))
557 return UUID(bytes=bytes, version=4) 621 return UUID(bytes=bytes, version=4)
558 622
623
559 def uuid5(namespace, name): 624 def uuid5(namespace, name):
560 """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."""
561 from hashlib import sha1 626 from hashlib import sha1
562 hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest() 627 hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest()
563 return UUID(bytes=hash[:16], version=5) 628 return UUID(bytes=hash[:16], version=5)
564 629
565 # The following standard UUIDs are for use with uuid3() or uuid5(). 630 # The following standard UUIDs are for use with uuid3() or uuid5().
566 631
567 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') 632 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
568 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') 633 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
569 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') 634 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
570 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') 635 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
LEFTRIGHT

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