GVKun编程网logo

Python ctypes 示例异常(python异常处理try)

2

本文将为您提供关于Pythonctypes示例异常的详细介绍,我们还将为您解释python异常处理try的相关知识,同时,我们还将为您提供关于ctypes.CDLL()可从anacondapython

本文将为您提供关于Python ctypes 示例异常的详细介绍,我们还将为您解释python异常处理try的相关知识,同时,我们还将为您提供关于ctypes.CDLL() 可从 anaconda python 安装运行,但不能从“原始”python 安装运行、ctypes.CDLL() 和 ctypes.cdll.LoadLibrary() 有什么区别?、CVE-2021-3177:Python ctypes 缓冲区溢出漏洞分析、Python 3.5,ctypes:TypeError:应使用字节或整数地址(而非str实例)的实用信息。

本文目录一览:

Python ctypes 示例异常(python异常处理try)

Python ctypes 示例异常(python异常处理try)

如何解决Python ctypes 示例异常

我正在研究如何通过 ctypes 将带有字符串字段的结构传递给 C。我在 Ubuntu (DigitalOcean) 上使用 python3。我一直在努力让它工作。我在设置 ctypes.c_char_p 对象指向 Python 字符串的 documentation what appears to be a very simple example 中找到。

  1. >>> from ctypes import *
  2. >>> class cell(Structure):
  3. ... pass
  4. >>> cell._fields_ = [(''name'',c_char_p),(''next'',POINTER(cell))]
  5. >>> c1=cell()
  6. >>> c1.name = "foo"

但我收到此异常:

  1. TypeError: bytes or integer address expected instead of str instance

根据我的代码运行情况,此错误与我的预期一致。所以,我的问题是,我误解了这个例子还是这个例子不对?

解决方法

这可能是因为 ctypes.c_char_p 是一个字节流,而不是一个字符串。如果你写 c1.name = b''bar'' 它应该工作。然后要从中恢复 Python 字符串,您应该使用 c1.name.decode(''utf-8'') 对其进行解码。

ctypes.CDLL() 可从 anaconda python 安装运行,但不能从“原始”python 安装运行

ctypes.CDLL() 可从 anaconda python 安装运行,但不能从“原始”python 安装运行

如何解决ctypes.CDLL() 可从 anaconda python 安装运行,但不能从“原始”python 安装运行

我有一个关于 ctypes 的使用的奇怪问题: ctypes 的行为取决于我是使用 anaconda 的 python 安装还是 python.org 的“原始”python 安装(均在 Windows 10 上)。

复制:只需转到 anaconda.com,通过默认安装程序安装 anaconda(和 anaconda python)。转到 python.org 并通过默认安装程序安装 python。

anaconda 安装附带了 mingw(x64) 二进制文件,这些文件至少是一些 .dll 所需的(我在这里不太了解,但至少我正在使用的 dll 需要它们)。 “原始”python 没有这些,因此需要手动添加它们(需要部分或全部(未检查):libatomic-1.dll、libgccc_s_seh-1.dll、libgomp-1.dll、libquadmath- 0.dll、libssp-0.dll、libstdc++-6.dll、libwinpthread-1.dll,只需将它们复制到您正在工作的目录中或将它们的目录添加到PATH)。

现在您有两个版本的 python,每个版本都有自己的 ctypes 版本(我的 anaconda python 版本为 3.8.8,“raw”python 版本为 3.9.5,ctypes 版本均为 1.1.0)。>

尝试通过 anaconda python 加载 dll,例如:

  1. import ctypes
  2. dll = ctypes.CDLL(<insertdllname>)

完全没问题(前提是你在dll的目录下工作,否则你需要指定完整路径)。

尝试相同的“原始”python 安装失败。问题是来自“原始”python 的 ctypes 找不到要加载的 dll 所依赖的 mingw 库。尽管这些库位于工作目录中(或明确地将它们的文件夹添加到 PATH)(两者都在使用 anaconda python 时工作)。仅当将附加库放入 python 安装文件夹(“python.exe”所在的位置)时,才会找到它们。

现在,当我将 ctypes 文件夹从 anaconda 安装复制到“raw”安装的 ctypes 文件夹所在的位置(将 ctypes 从“raw”安装重命名为 ctypes_raw)时,我有两个版本的 ctypes 可用。

使用:

  1. import ctypes_roh
  2. ctypes_roh.CDLL(<insertdllname>)

失败,如上。

  1. import ctypes
  2. ctypes.CDLL(<insertdllname>)

有效,所以显然两个 ctypes 库是不同的,anaconda 安装中的 ctypes 能够在工作目录和 PATH 中查找 dll,而“原始”python 安装中的 ctypes 不能这样做。

  1. import ctypes
  2. import ctypes_raw
  3. ctypes.CDLL(<insertdllname>)
  4. ctypes_raw.CDLL(<insertdllname>)

现在两个调用都有效。显然,从 anaconda ctypes 调用 CDLL 修复了阻止 CDLL 从“原始”ctypes 在工作目录或 PATH 中查找 dll 的任何问题。

所以我的问题是:

  • python anaconda 安装中的 ctypes 和 python.org 中的“原始”python 安装中的 ctypes 是否应该不同?
  • 有什么区别?为什么来自“原始”python 的 ctypes 无法在工作目录或 PATH 中查找 dll?为什么从 anaconda python 调用 ctypes 会“修复”这个问题?

编辑:在发现“原始”python 安装没有所需的 mingw 库后,我重写了帖子以说明这一点并(希望)澄清剩余的问题。

ctypes.CDLL() 和 ctypes.cdll.LoadLibrary() 有什么区别?

ctypes.CDLL() 和 ctypes.cdll.LoadLibrary() 有什么区别?

如何解决ctypes.CDLL() 和 ctypes.cdll.LoadLibrary() 有什么区别?

这两种方法似乎都有效(对我来说),但似乎 CDLL() 方法返回一个具有 _handle 属性的对象,该对象可用于通过 ctypes.windll.kernel32.FreeLibrary() 卸载库(至少在 Windows 上 - 我还不知道如何在 Linux 上做到这一点)。

这两种方法有什么区别 - 为什么我会选择一种而不是另一种?

最终,我的目标是能够在 Linux 上的两个 Windows 上加载和卸载库(因为我有一个 3rd 方库,有时似乎会进入损坏状态 - 我希望卸载/重新加载会重置它) .

解决方法

一切都在[Python.Docs]: ctypes - A foreign function library for Python中得到了很好的解释:

class ctypes.CDLL名称,mode=DEFAULT_MODE,handle=None,use_errno=False,use_last_error=False,winmode=0 )
此类的实例表示加载的共享库。这些库中的函数使用标准的 C 调用约定,并假定返回 int

...

class ctypes.LibraryLoader(dlltype)

...

LoadLibrary名称
将共享库加载到进程中并返回。此方法始终返回库的新实例。

这些预制的库加载器可用:

ctypes.cdll
创建 CDLL 个实例。

所以,第 2nd 表单只是一个方便的包装器,它们之间绝对没有功能上的区别,如下所示:

  1. >>> import ctypes as ct
  2. >>>
  3. >>>
  4. >>> k32_1 = ct.CDLL("kernel32.dll") # 1.
  5. >>> k32_2 = ct.cdll.LoadLibrary("kernel32.dll") # 2.1.
  6. >>> k32_3 = ct.cdll.kernel32 # 2.2.
  7. >>>
  8. >>> k32_1,k32_2,k32_3
  9. (<CDLL ''kernel32.dll'',handle 7fff59100000 at 0x2335c444ee0>,<CDLL ''kernel32.dll'',handle 7fff59100000 at 0x2335b44bc10>,<CDLL ''kernel32'',handle 7fff59100000 at 0x2335c45a790>)
  10. >>> type(k32_1),type(k32_2),type(k32_3)
  11. (<class ''ctypes.CDLL''>,<class ''ctypes.CDLL''>,<class ''ctypes.CDLL''>)
  12. >>>
  13. >>> k32_1._handle == k32_2._handle == k32_3._handle
  14. True

使用最适合您的方式。
2nd 形式(#2.2.)更短(我想这就是它的目的)。
#1.#2.1. 是相同的(#2.1. 可能更具解释性(因为它有 LoadLibrary)) 并且它们允许您从自定义路径或具有与默认值不同的扩展名加载库。就我个人而言,#1. 是我更喜欢的。

更多细节,你可以看看[GitHub]: python/cpython - (master) cpython/Lib/ctypes/__init__.py,特别是LibraryLoader在实现中(cdll实际上是,并且)很容易理解.

提醒一下(可能您已经知道自己在做什么):加载和卸载库有时会很棘手。

CVE-2021-3177:Python ctypes 缓冲区溢出漏洞分析

CVE-2021-3177:Python ctypes 缓冲区溢出漏洞分析

起步

相关的 issue 与 修复 ,从描述来看,这是一个 sprintf 函数引发的缓冲区溢出漏洞。

补丁获取链接:https://python-security.readthedocs.io/vuln/ctypes-buffer-overflow-pycarg_repr.html

复现

使用 3.8.7 进行复现:

17723-5k3bzo7cnt7.png

这个漏洞在 3.8.8 便已修复:

42845-7hdaq2ol18b.png

分析

通过生成的 coredump 文件,查看异常堆栈:

41587-g21ca52uols.png

注意到 Python-3.8.7/Modules/_ctypes/callproc.c :

PyCArg_repr(PyCArgObject *self)
{
    char buffer[256];
    switch(self->tag) {
    ...
    case ''d'':
        sprintf(buffer, "<cparam ''%c'' (%f)>",   // 这行引发异常
            self->tag, self->value.d);          // value.d 的值是 1e300
        break;

变量 buffer 的长度为 256 ,因此长度不够使得 sprintf 的缓冲区溢出,造成内存的破坏。

写个简单的 C 代码复现这个问题:

#include <stdio.h>

int main(int argc, char **argv) {
  char buffer[256];
  char tag = ''d'';
  double value = 1e300;
  sprintf(buffer, "<cparam ''%c'' (%f)>", tag, value);
  return 0;
}

76548-5rjgjymnk48.png

我在中间加了一行 printf("%f\n", value); 再次执行:

68659-wimuo3l4jzj.png

这个长度已经超过 buffer 定义的长度了。double 类型,表示的小数位数能很大,所以至少可以覆盖 300 个字节;如果是 float 类型,就要小的多了。

在新版本之中该问题已经得到修复,已经将 sprintf 换成 PyUnicode_FromFormat

参考链接

  • https://bugs.python.org/issue42938
  • https://blog.python.org/2021/02/python-392-and-388-are-now-available.html
  • https://www.randori.com/blog/cve-2021-3177-vulnerability-analysis/
  • http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202101-1467
  • https://access.redhat.com/security/cve/cve-2021-3177

Python 3.5,ctypes:TypeError:应使用字节或整数地址(而非str实例)

Python 3.5,ctypes:TypeError:应使用字节或整数地址(而非str实例)

我的ctypes有问题。我认为我的类型转换是正确的,并且该错误对我来说没有意义。第“ arg-ct.c_char_p(logfilepath)行错误”
TypeError:预期为字节或整数地址,而不是str实例

我在python 3.5和3.4中都尝试过。

我正在调用的功能:

stream_initialize(''stream_log.txt'')

Stream_initialize代码”

def stream_initialize(logfilepath):    f = shim.stream_initialize    arg = ct.c_char_p(logfilepath)    result = f(arg)    if result:        print(find_shim_error(result))

答案1

小编典典

c_char_p需要bytes对象,因此您必须先将其转换stringbytes

ct.c_char_p(logfilepath.encode(''utf-8''))

另一种解决方案是使用c_wchar_p带有的类型string

今天关于Python ctypes 示例异常python异常处理try的讲解已经结束,谢谢您的阅读,如果想了解更多关于ctypes.CDLL() 可从 anaconda python 安装运行,但不能从“原始”python 安装运行、ctypes.CDLL() 和 ctypes.cdll.LoadLibrary() 有什么区别?、CVE-2021-3177:Python ctypes 缓冲区溢出漏洞分析、Python 3.5,ctypes:TypeError:应使用字节或整数地址(而非str实例)的相关知识,请在本站搜索。

本文标签: