Deixando o interpretador Python maluco por diversão e lucro, ou Como se livrar de um colega de trabalho desenvolvedor Python

Você está lá, em apenas mais um dia comum de trabalho (ou diversão), debugando um sistema complexo e tentando entender porque diabos algo que deveria acontecer não acontece. Você consegue reduzir o seu problema a uma linha de código, que não se comporta como você espera:

>>> print 42 == 0
True

O resultado foi verdadeiro, ou seja, 42 realmente é igual a 0 no momento em que esta comparação roda! Mas como assim?! Em Python não é possível reabrir a classe dos números (int), reescrever os métodos de comparação para fazer isso dar certo.
Lembre-se que esta comparação estranha está no meio de um sistema complexo. Assim:

algo_que_deixa_interpretador_maluco()
print 42 == 0

Explicação: A função algo_que_deixa_interpretador_maluco está modificando o objeto “número inteiro 42” (mesmo os números são objetos). Mas os números são objetos imutáveis, como assim você modificou o valor de 42? Um número inteiro em Python (na verdade, CPython) é representado por uma struct do C, que entre outras coisas, contém um long do C com o mesmo valor  – o atributo ob_ival.

Simplificando uma longa história, quando temos uma comparação de números, ela é repassada para o nível do C, e os atributos ob_ival da struct C são comparados com o operador == do C. Basta então mudarmos o ob_ival do objeto “número 42” que podemos influenciar na comparação.

E para mudar o valor de ob_ival? Como é possível acessar e modificar o estado interno e a memória do interpretador? Com o módulo ctypes, da biblioteca padrão, podemos acessar do Python os tipos do C. Basta então conseguirmos achar na memória a struct do número 42. Mas isso é fácil, a função builtin id retorna exatamente o lugar na memória onde o objeto está. Com isso, temos tudo que precisamos.

import ctypes

if hasattr(ctypes.pythonapi, 'Py_InitModule4'):
    Py_ssize_t = ctypes.c_int
elif hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
    Py_ssize_t = ctypes.c_int64
else:
    raise TypeError("Cannot determine type of Py_ssize_t")

class PyObject(ctypes.Structure):
    pass # incomplete type

class PyObject(ctypes.Structure):
    _fields_ = [('ob_refcnt', Py_ssize_t),
                ('ob_type', ctypes.POINTER(PyObject))]

class PyIntObject(PyObject):
    _fields_ = [('ob_ival', ctypes.c_long)]

forty_two_object = PyIntObject.from_address(id(42))
forty_two_object.ob_ival = 0

print 42 == 0

Neste código, estamos primeiro conseguindo o endereço do objeto 42 (linha 20), depois criando a struct do ctypes (ponte entre o Python e a struct C), depois alteramos o ob_ival do 42 para 0, na memória do interpretador (linha 21).

A partir daí, quando o Python fizer a comparação entre o número 42 e 0 (linha 23), ela será verdadeira, já que seus ob_ival são iguais.

Extensões em C ou mesmo código Python com ctypes mal testados podem causar consequências imprevisíveis e bugs dificílimos de reproduzir, mesmo onde parece impossível. Mas também tem usos interessantes: Pense em um dos inúmeros jogos que suportam Python como Civilization IV, Battlefield 2 e Piratas do Caribe Online. É possível fazer um script usando o mesmo princípio que modifica, por exemplo, as variáveis de controle de vidas do jogador, posição etc.

Anúncios
Publicado em C, hack, Python. Tags: , , . 8 Comments »

Osciloscópios e jogos

Demo maravilhosa (download do áudio) feita num osciloscópio. Terceiro lugar na categoria shortfilm no Assembly 2007. E o cara tinha só 15 anos. Sensacional! Eu juro que um dia vou juntar dinheiro e ir pra Finlândia participar do Assembly, nem que seja só pra ficar olhando.

Pra falar a verdade eu queria mesmo era ver a demoscene brasileira no Campus Party Brasil.

Já que estamos falando de osciloscópios. Tennis for two, o segundo jogo usando display gráfico inventado. 1958.

OXO (1952) foi o primeiro, mas era um jogo da velha. Não achei vídeo no youtube. No entanto, existem emuladores, para os que estiverem interessados.

Publicado em hack. Tags: , , . 1 Comment »

Mais um Google Hack

Vejam este site.

E agora, esta busca no Google por IE7.

Já está em quinto. Mais um pouquinho (façam links nos seus sites para ajudar!) e o “Estou com sorte” é Firefox. Seria bem irônico. Será que o Google faz algo para combater este tipo de coisa?

Abraços
Leandro Lameiro

Publicado em hack, Uncategorized. Tags: . Leave a Comment »