gpt4 book ai didi

tcl - TclInvalidateStringRep() 不应该重置长度吗?

转载 作者:行者123 更新时间:2023-12-04 20:32:58 25 4
gpt4 key购买 nike

我对TCL 8.6.8源码tclInt.h中的以下代码有疑问:

4277 #define TclInvalidateStringRep(objPtr) \
4278 if (objPtr->bytes != NULL) { \
4279 if (objPtr->bytes != tclEmptyStringRep) { \
4280 ckfree((char *) objPtr->bytes); \
4281 } \
4282 objPtr->bytes = NULL; \
4283 }

该宏由 tclObj.c 中的 Tcl_InvalidateStringRep() 调用。

我的疑问是,为什么 tclObj 的长度没有重置为零?

这里是来自 Tcl_Obj 的定义:

 808 typedef struct Tcl_Obj {
809 int refCount; /* When 0 the object will be freed. */
810 char *bytes; /* This points to the first byte of the
811 * object's string representation. The array
812 * must be followed by a null byte (i.e., at
813 * offset length) but may also contain
814 * embedded null characters. The array's
815 * storage is allocated by ckalloc. NULL means
816 * the string rep is invalid and must be
817 * regenerated from the internal rep. Clients
818 * should use Tcl_GetStringFromObj or
819 * Tcl_GetString to get a pointer to the byte
820 * array as a readonly value. */
821 int length; /* The number of bytes at *bytes, not
822 * including the terminating null. */

所以你可以看到长度与字节紧密耦合,当字节被清除时,我们是否应该重新设置长度?

我的疑问来自于下面的代码,tclLiteral.c 中的 TclCreateLiteral():

 200     for (globalPtr=globalTablePtr->buckets[globalHash] ; globalPtr!=NULL;
201 globalPtr = globalPtr->nextPtr) {
202 objPtr = globalPtr->objPtr;
203 if ((globalPtr->nsPtr == nsPtr)
204 && (objPtr->length == length) && ((length == 0)
205 || ((objPtr->bytes[0] == bytes[0])
206 && (memcmp(objPtr->bytes, bytes, (unsigned) length) == 0)))) {

因此在第 204 行,当长度不为零且字节为 NULL 时,程序崩溃。

我的产品包含TCL源,我在跟踪程序崩溃时发现了上述问题。我将解决方法放在我们的代码中,但想与社区确认它是否确实是一个漏洞。

最佳答案

你的方法好像哪里不对。

TclInvalidateStringRep的来电对于没有引用 ( refCount == 0 ) 或只有一个引用 (所以 refCount <= 1 ) 的对象基本上是允许的,然后只有当您确定这 1 个引用仅是您自己的引用时。

Tcl 的共享对象 可以切换其内部表示,但字符串表示保持不变。否则你将违反 Tcl 的基本原则(如 EIAS 等)。

可以解释这一点的最简单的例子:

set k 0x7f
dict set d $k test
expr {$k}; # ==> 127 (obj is integer now, but...)
puts $k; # ==> 0x7f (... still remains the string-representation)
puts [dict get $d $k]; # ==> test

# some code that fouls it up (despite of two references var `k` and key in dict `d`):
magic_happens_here $k; # string representation gets lost.

# and hereafter:
puts $k; # ==> 127 (representation is now 127, so...)
puts [dict get $d $k]; # ==> ERROR: key "127" not known in dictionary

如您所见,重新设置 resp。更改共享对象的字符串表示是设计错误。
请在 Tcl 中避免这种情况。

关于tcl - TclInvalidateStringRep() 不应该重置长度吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54337750/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com