我可以从内存地址构建环境对象吗?

问题描述 投票:0回答:1

我发现我们可以从一个内存地址构建/重建一个外部指针,参见这个例子,我从一个数据表对象中获取一个指针并重建它:

# devtools::install_github("randy3k/xptr")
iris_dt <- data.table::as.data.table(iris)
ptr1 <- attr(iris_dt, ".internal.selfref")
ptr1
#> <pointer: 0x13c00d4e0>
typeof(ptr1)
#> [1] "externalptr"

address <- xptr::xptr_address(ptr1)
address
#> [1] "0x13c00d4e0"
ptr2 <- xptr::new_xptr(address)
identical(ptr1, ptr2)
#> [1] TRUE

显然

xptr::new_xptr("0x13c00d4e0")
在会话之间不稳定,我知道上面不是分配内存而只是定义绑定,这对我的用例来说很好。

我想对环境做同样的事情:

e <- new.env()
e
#> <environment: 0x10b5bf038>

env("0x10b5bf038") # I want this "env" function
#> <environment: 0x10b5bf038>

我怀疑 base R 能否做到这一点,所以我对打包选项和 C 魔法持开放态度。

解决 X/Y 评论的非必需阅读

我需要这个用于{constructive}包,说我想探索

asNamespace("stats")$.__NAMESPACE__.$DLLs
对象,它的打印方式不是很有帮助:

asNamespace("stats")$.__NAMESPACE__.$DLLs
#> $stats
#> DLL name: stats
#> Filename: /opt/R/4.2.1-arm64/Resources/library/stats/libs/stats.so
#> Dynamic lookup: FALSE

dput()
通常是丑陋和脆弱的,另外这里的代码不是句法的所以我不能确定对象是否被准确描述。

dput(asNamespace("stats")$.__NAMESPACE__.$DLLs)
#> list(stats = structure(list(name = "stats", path = "/opt/R/4.2.1-arm64/Resources/library/stats/libs/stats.so", 
#>     dynamicLookup = FALSE, handle = <pointer: 0x2011ce960>, info = <pointer: 0x6000021f00c0>), class = "DLLInfo"))

str()
在一般情况下做得更好但并不理想

str(asNamespace("stats")$.__NAMESPACE__.$DLLs)
#> List of 1
#>  $ stats:List of 5
#>   ..$ name         : chr "stats"
#>   ..$ path         : chr "/opt/R/4.2.1-arm64/Resources/library/stats/libs/stats.so"
#>   ..$ dynamicLookup: logi FALSE
#>   ..$ handle       :Class 'DLLHandle' <externalptr> 
#>   ..$ info         :Class 'DLLInfoReference' <externalptr> 
#>   ..- attr(*, "class")= chr "DLLInfo"

{constructive} 保证它输出复制对象的代码,现在它适用于包含指针的对象。

constructive::construct(asNamespace("stats")$.__NAMESPACE__.$DLLs)
#> list(
#>   stats = list(
#>     name = "stats",
#>     path = "/opt/R/4.2.1-arm64/Resources/library/stats/libs/stats.so",
#>     dynamicLookup = FALSE,
#>     handle = constructive::external_pointer("0x2051d6960") |>
#>       structure(class = "DLLHandle"),
#>     info = constructive::external_pointer("0x600002970de0") |>
#>       structure(class = "DLLInfoReference")
#>   ) |>
#>     structure(class = "DLLInfo")
#> )

我在包中有其他方法来处理环境,例如从列表构建等效环境等......但我想集成一个仅使用内存地址的替代方案,因为它会打印得更好并且足以满足某些用例。

r memory low-level
1个回答
1
投票

如果存在安全且便携的版本,您需要做更多的工作来使其安全且便携。请注意,整数类型

uintptr_t
和相应的宏格式说明符
SCNxPTR
在C99中是可选的。请参阅 WRE 中“编写可移植包”下的建议。

/* objectFromAddress.c */

#include <stdio.h> /* sscanf */
#include <inttypes.h> /* SCNxPTR */
#include <Rinternals.h> /* SEXP, etc. */

SEXP objectFromAddress(SEXP a) {
    uintptr_t p = 0;
    
    if (TYPEOF(a) != STRSXP || XLENGTH(a) != 1 ||
        (a = STRING_ELT(a, 0)) == NA_STRING ||
        sscanf(CHAR(a), "%" SCNxPTR, &p) != 1)
        error("'a' is not a formatted unsigned hexadecimal integer");
    
    return (SEXP) p;
}
tools::Rcmd(c("SHLIB", "objectFromAddress.c"))
using C compiler: ‘Apple clang version 13.0.0 (clang-1300.0.29.30)’
using SDK: ‘MacOSX12.1.sdk’
clang -I"/usr/local/lib/R/include" -DNDEBUG   -I/opt/R/arm64/include -I/usr/local/include    -fPIC  -Wall -g -O2 -pedantic -mmacosx-version-min=11.0 -arch arm64 -falign-functions=64 -Wno-error=implicit-function-declaration -flto=thin -c objectFromAddress.c -o objectFromAddress.o
clang -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -Wall -g -O2 -pedantic -mmacosx-version-min=11.0 -arch arm64 -falign-functions=64 -Wno-error=implicit-function-declaration -flto=thin -fPIC -Wl,-mllvm,-threads=4 -L/usr/local/lib/R/lib -L/opt/R/arm64/lib -L/usr/local/lib -o objectFromAddress.so objectFromAddress.o -L/usr/local/lib/R/lib -lR -Wl,-framework -Wl,CoreFoundation
dyn.load("objectFromAddress.so")
(e <- new.env())
<environment: 0x112811b30>
identical(.Call("objectFromAddress", "112811b30"), e)
[1] TRUE

你想问的问题是:

  • 如果地址处的内存在调用
    objectFromAddress
    之前被垃圾收集器释放会怎样?
  • 更一般地说,如果提供的地址不是
    SEXPREC
    的地址会怎样?
© www.soinside.com 2019 - 2024. All rights reserved.