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

Delta Between Two Patch Sets: Lib/uuid.py

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