'Python Ctypes - Memmove not working correctly

I would like to move data from one variable to another.

I have the following code:

a = 'a' # attempting to move the contents of b into here
b = 'b'

obj = ctypes.py_object.from_address(id(a))
obj2 = ctypes.py_object.from_address(id(b))

ptr = ctypes.pointer(obj)
ptr2 = ctypes.pointer(obj2)

ctypes.memmove(ptr, ptr2, ctypes.sizeof(obj2))
print(a, b) # expected result: b b

a does not change, and gives no errors.

Is this simply not possible, or is it something I am doing wrong?



Solution 1:[1]

NOT RECOMMENDED But interesting for learning...

It's possible on CPython due to the implementation detail that id(obj) returns the address of the internal PyObject, but a very bad idea. Python strings are immutable, so corrupting their inner workings is going to break things. Python objects have internal data like reference counts, type, length that will be corrupted by blindly copying over them.

import ctypes as ct
import sys

# Using strings that are more unique and less likely to be used inside Python
# (lower reference counts).
a = '123'
b = '456'

# Create ctypes byte buffers that reference the same memory as a and b
bytes_a = (ct.c_ubyte * sys.getsizeof(a)).from_address(id(a))
bytes_b = (ct.c_ubyte * sys.getsizeof(b)).from_address(id(b))

# View the bytes as hex.  The first bytes are the reference counts.
# The last bytes are the ASCII bytes of the strings.
print(bytes(bytes_a).hex())
print(bytes(bytes_b).hex())
ct.memmove(bytes_b, bytes_a, len(bytes_a))

# Does what you want, but Python crashes on exit in my case
print(a,b)

Output:

030000000000000060bc9563fc7f00000300000000000000bf4fda89331c3232e5a5a97d1b020000000000000000000031323300
030000000000000060bc9563fc7f00000300000000000000715a1b84492b4696e5feaf7d1b020000000000000000000034353600
123 123
Exception ignored deletion of interned string failed:
KeyError: '123'
111

Safe way to do make a copy of the memory and view it

import ctypes as ct
import sys

a = '123'
# Copy memory at address to a Python bytes object.
bytes_a = ct.string_at(id(a), sys.getsizeof(a))
print(bytes_a.hex())

Output:

020000000000000060bc5863fc7f000003000000000000001003577d19c6d60be59f53919b010000000000000000000031323300

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1