Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

6 May, 2024: The networking issue during the past two days has been identified and appears to be fixed. Will keep monitoring.


devel / comp.lang.python / Re: Can you mock a C function using ctypes?

SubjectAuthor
o Re: Can you mock a C function using ctypes?Eryk Sun

1
Re: Can you mock a C function using ctypes?

<mailman.446.1663307463.20444.python-list@python.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=19526&group=comp.lang.python#19526

  copy link   Newsgroups: comp.lang.python
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!not-for-mail
From: eryk...@gmail.com (Eryk Sun)
Newsgroups: comp.lang.python
Subject: Re: Can you mock a C function using ctypes?
Date: Fri, 16 Sep 2022 00:51:00 -0500
Lines: 56
Message-ID: <mailman.446.1663307463.20444.python-list@python.org>
References: <63237ff4.c80a0220.23ec1.ce9c@mx.google.com>
<CACL+1avqHT-nzGm4JtY_bu2s6NA-SYLOoNZwXu1iU9KhxyiWgQ@mail.gmail.com>
<6323d81b.050a0220.7552d.1ed1@mx.google.com>
<CACL+1avBicbzfFBbXJbv0eH3ZmM+80UtB+4mGM7Sym4mzxkgAw@mail.gmail.com>
Mime-Version: 1.0
Content-Type: text/plain; charset="UTF-8"
X-Trace: news.uni-berlin.de WDfOE2w/v1YmydIw3onJvQ48D9uCa7BMZD3QUD3EN/yg==
Return-Path: <eryksun@gmail.com>
X-Original-To: python-list@python.org
Delivered-To: python-list@mail.python.org
Authentication-Results: mail.python.org; dkim=pass
reason="2048-bit key; unprotected key"
header.d=gmail.com header.i=@gmail.com header.b=k0uKEjji;
dkim-adsp=pass; dkim-atps=neutral
X-Spam-Status: OK 0.011
X-Spam-Evidence: '*H*': 0.98; '*S*': 0.00; 'def': 0.04; "python's":
0.05; 'cc:addr:python-list': 0.09; 'received:209.85.219': 0.09;
'terminal': 0.09; 'trivial': 0.09; 'cc:no real name:2**0': 0.14;
'import': 0.15; 'memory': 0.15; 'accessed': 0.16; 'easily,': 0.16;
'exported': 0.16; 'hooked': 0.16; 'object,': 0.16; 'read:': 0.16;
'rfp': 0.16; 'stdout': 0.16; 'variable,': 0.16; 'void': 0.16;
'wrote:': 0.16; 'python': 0.16; 'grant': 0.17; "can't": 0.17;
'cc:addr:python.org': 0.20; 'creates': 0.22; 'subject:using':
0.23; 'cc:2**0': 0.25; 'library': 0.26; 'normally': 0.26;
'object': 0.26; 'function': 0.27; '>>>': 0.28; 'example,': 0.28;
'printed': 0.28; 'wrong': 0.28; 'default': 0.31; "doesn't": 0.32;
'subject:Can': 0.32; 'message-id:@mail.gmail.com': 0.32; 'but':
0.32; 'header:In-Reply-To:1': 0.34; 'received:google.com': 0.34;
'from:addr:gmail.com': 0.35; 'target': 0.36; 'using': 0.37;
"it's": 0.37; 'received:209.85': 0.37; 'received:209': 0.39;
'least': 0.39; 'this,': 0.39; 'use': 0.39; 'prompt': 0.39;
'case.': 0.40; 'reference': 0.60; "there's": 0.61; 'pass': 0.64;
'skip:r 20': 0.64; 'order': 0.69; 'instead,': 0.70; 'global':
0.73; 'chain': 0.76; 'choice': 0.76; 'subject:you': 0.84;
'attribute': 0.84; 'callback': 0.84; 'converted': 0.84; 'exports':
0.84; 'pointer': 0.84; 'prototype': 0.84
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
h=cc:to:subject:message-id:date:from:references:in-reply-to
:mime-version:from:to:cc:subject:date;
bh=x0hNFadpiO6c2VKXRr/Q4nQs5nA6dJdtT3+YGzwut8Q=;
b=k0uKEjjiH+3JG1h+3ToR/oEjLOfgemsQvjBnjg9liNOUIzVM3ON7J5Bm6HWhVT+ND5
ZwUZ8ELpHSaiE2Tm2ug9LeBDTEsNGVx2TatudJwbws1cC1SJ6npJHmB5kzptif3GCvrK
6Tle0CumP+mxejO3lXYeS3x5wtADEzVFqX0lhq+4568PKtlXuerQSgnXy+aDwr/KkAlm
7M4TVyVBMLN5sCAs6GHAdpzTrV1FzXxrDkaAlZrOepRdecQab4oM7zeo1ojos4j6c32C
ld/ofShqrlQsR+nBOmrN1D5vPPBbK6J+6awzNKr4iN2DjPGGiZICpRHHq2OgcXVqMKCM
AXYA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20210112;
h=cc:to:subject:message-id:date:from:references:in-reply-to
:mime-version:x-gm-message-state:from:to:cc:subject:date;
bh=x0hNFadpiO6c2VKXRr/Q4nQs5nA6dJdtT3+YGzwut8Q=;
b=osp+iX83ZNMX4m7j+1zO9NW/FNCKgrNsUIbUCuf25odsogMEBc48t9TM4jIEWoTTN5
QUcxxn389aluYthye5Te/mDuMI9Qym+0kh81iqQwsHafvPp2cBKIM2SlWd/mVkThkr/j
Wil2sDjtsWGM9Vn5YlOtCpG7b89kEDZ1p4EkbWaJoCbjMSwNTrpA+6L8eH8iKJbCu8Nu
oL8D2HXhNc/DvAd6bpCjPjME2naZieNnx6vCrmYbmilkSX6WdSYDG+zJxHxcZ8wcxnAi
5/9N5X2VNiMwGzHut2QPZTwl445VugUEsAz8SZxmom3zYudiVluW2A8PJdbVvd2vnV9s
N63A==
X-Gm-Message-State: ACrzQf32MUYK8T7Vp14Ro87ydPTeIxYK3oszLc25E8DwZR4Wmp89Fakz
otY9Djxu9h7mh1hl0/NXZo+Z0GWIO1xjxO6cC5w=
X-Google-Smtp-Source: AMsMyM76zsgcl0zzOWToTvN/XWoOVsCPzFsPC0U/EnGx7F6tO0MVop7Fwy2SgAyLt7Hd+ZDeD3BmTgFuyuCEgpeyGdY=
X-Received: by 2002:a05:6214:4017:b0:4ac:6db5:66f0 with SMTP id
kd23-20020a056214401700b004ac6db566f0mr3075532qvb.105.1663307461370; Thu, 15
Sep 2022 22:51:01 -0700 (PDT)
In-Reply-To: <6323d81b.050a0220.7552d.1ed1@mx.google.com>
X-BeenThere: python-list@python.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: General discussion list for the Python programming language
<python-list.python.org>
List-Unsubscribe: <https://mail.python.org/mailman/options/python-list>,
<mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive: <https://mail.python.org/pipermail/python-list/>
List-Post: <mailto:python-list@python.org>
List-Help: <mailto:python-list-request@python.org?subject=help>
List-Subscribe: <https://mail.python.org/mailman/listinfo/python-list>,
<mailto:python-list-request@python.org?subject=subscribe>
X-Mailman-Original-Message-ID: <CACL+1avBicbzfFBbXJbv0eH3ZmM+80UtB+4mGM7Sym4mzxkgAw@mail.gmail.com>
X-Mailman-Original-References: <63237ff4.c80a0220.23ec1.ce9c@mx.google.com>
<CACL+1avqHT-nzGm4JtY_bu2s6NA-SYLOoNZwXu1iU9KhxyiWgQ@mail.gmail.com>
<6323d81b.050a0220.7552d.1ed1@mx.google.com>
 by: Eryk Sun - Fri, 16 Sep 2022 05:51 UTC

On 9/15/22, Grant Edwards <grant.b.edwards@gmail.com> wrote:
>
> Does the pointer have to be passed? Or can it be "poked" into a global
> variable?

If the library exports the function pointer as a global variable, it
can be set in ctypes using the in_dll() method. Unfortunately, as far
as I know, a ctypes function prototype can't be used directly for
this, at least not easily, since the function pointer it creates
doesn't have a `value` or `contents` attribute to set the target
address. Instead, the exported global can be accessed as a void
pointer. It's clunky, but it works.

For example, Python's REPL supports a callback for reading a line from
the terminal. Normally it's either hooked by a C extension, such as
the readline module, or set to the default function
PyOS_StdioReadline(). We can use a ctypes callback to hook into this
and chain to the previous function.

import ctypes

PyOS_RFP = ctypes.CFUNCTYPE(
ctypes.c_void_p,
ctypes.c_void_p, # stdin (FILE *)
ctypes.c_void_p, # stdout (FILE *)
ctypes.c_char_p, # prompt
)

@PyOS_RFP
def readline_hook(stdin, stdout, prompt):
print('HOOKED: ', end='', flush=True)
return prev_rfp(stdin, stdout, prompt)

rfp_vp = ctypes.c_void_p.in_dll(ctypes.pythonapi,
'PyOS_ReadlineFunctionPointer')

if rfp_vp:
# there's a previous RFP that can be hooked
prev_rfp = ctypes.cast(rfp_vp, PyOS_RFP)
rfp_vp.value = ctypes.cast(readline_hook, ctypes.c_void_p).value

In this trivial example, "HOOKED: " is printed to the terminal before
each line is read:

HOOKED: >>> def f():
HOOKED: ... pass
HOOKED: ...
HOOKED: >>>

Note that I defined the return type of PyOS_RFP to be c_void_p. Using
c_char_p as the return type would convert the result to a bytes
object, which is wrong in this case. If the setfunc of the callback's
return type has to keep a reference to a converted Python object, such
as a bytes object, then the callback has no choice but to leak the
reference in order to keep the object alive indefinitely, which
usually causes a memory leak.

1
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor