Rocksolid Light

News from da outaworlds

mail  files  register  groups  login

Message-ID:  

BOFH excuse #70: nesting roaches shorted out the ether cable


comp / comp.lang.tcl / Values being overwritten in Tcl_HashTable

SubjectAuthor
* Values being overwritten in Tcl_HashTableKevin Walzer
`- Re: Values being overwritten in Tcl_HashTableFrancois Vogel

1
Subject: Values being overwritten in Tcl_HashTable
From: Kevin Walzer
Newsgroups: comp.lang.tcl
Organization: A noiseless patient Spider
Date: Mon, 11 Nov 2024 03:37 UTC
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: kw@codebykevin.com (Kevin Walzer)
Newsgroups: comp.lang.tcl
Subject: Values being overwritten in Tcl_HashTable
Date: Sun, 10 Nov 2024 22:37:07 -0500
Organization: A noiseless patient Spider
Lines: 182
Message-ID: <vgru54$q1g9$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Mon, 11 Nov 2024 04:37:08 +0100 (CET)
Injection-Info: dont-email.me; posting-host="4f904a8dfe047400e0aa44456831801e";
logging-data="853513"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+iTvFi3VXzZVKmMIVuY8K7ToG8vp3bGLw="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:ij1es5TAC7VGR4XyNlHxCeWuznk=
Content-Language: en-US
View all headers

I am trying to write mulitple key-value pairs to a Tcl_HashTable, but
when I call Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2)), it reads the
last value written to the hash table - even if that value is not
associated with the key that I am using.

Is there a best practice I am missing here? I thought that differing
keys would be tracked in the hash table and the Tcl_FindHashEntry call
would return different data depending on the key.

Tcl_ResetResult does not change the result in the interpreter, which
tells me the issue is with the table - calls to the key for "role" and
"name" return the value for "name" - seems like the "role" value has
been overwritten.

My C code is below. Any help is appreciated.

int
Tk_SetAccessibleRole(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 3) {
Tcl_WrongNumArgs(ip, 1, objv, "window? role?");
return TCL_ERROR;
}
Tk_Window win;
char *role;
Tcl_HashEntry *hPtr, *hPtr2;

Tcl_HashTable *AccessibleAttributes;
AccessibleAttributes = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(AccessibleAttributes,TCL_STRING_KEYS);

int isNew;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}

/* Set accessible role for window. */
hPtr=Tcl_CreateHashEntry(TkAccessibilityObject, win, &isNew);

Tcl_SetHashValue(hPtr, AccessibleAttributes);

hPtr2 = Tcl_CreateHashEntry(AccessibleAttributes, role, &isNew);
if (!isNew) {
Tcl_DecrRefCount(Tcl_GetHashValue(hPtr2));
}
Tcl_IncrRefCount(objv[2]);
Tcl_SetHashValue(hPtr2, objv[2]);

Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}

int
Tk_SetAccessibleName(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 3) {
Tcl_WrongNumArgs(ip, 1, objv, "window? name?");
return TCL_ERROR;
}

Tk_Window win;
char *name;
Tcl_HashEntry *hPtr, *hPtr2;
int isNew;
Tcl_HashTable *AccessibleAttributes;
win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}

/* Set accessible name for window. */

hPtr=Tcl_FindHashEntry(TkAccessibilityObject, win);
if (!hPtr) {
Tcl_AppendResult(ip, "No table found", (char *) NULL);
return TCL_ERROR;
}

AccessibleAttributes = Tcl_GetHashValue(hPtr);
hPtr2 = Tcl_CreateHashEntry(AccessibleAttributes, name, &isNew);
if (!isNew) {
Tcl_DecrRefCount(Tcl_GetHashValue(hPtr2));
}
Tcl_IncrRefCount(objv[2]);
Tcl_SetHashValue(hPtr2, objv[2]);

Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}

int
Tk_GetAccessibleRole(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 2) {
Tcl_WrongNumArgs(ip, 1, objv, "window?");
return TCL_ERROR;
}
Tk_Window win;
char *role;
Tcl_HashEntry *hPtr, *hPtr2;

Tcl_HashTable *AccessibleAttributes;

win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}

/* Get accessible role for window. */
hPtr=Tcl_FindHashEntry(TkAccessibilityObject, win);
if (!hPtr) {
Tcl_AppendResult(ip, "No table found", (char *) NULL);
return TCL_ERROR;
}
AccessibleAttributes = Tcl_GetHashValue(hPtr);
hPtr2=Tcl_FindHashEntry(AccessibleAttributes, (char*) role);
if (!hPtr2) {
Tcl_AppendResult(ip, "No role found", (char *) NULL);
return TCL_ERROR;
}

Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}

int
Tk_GetAccessibleName(
TCL_UNUSED(void *),
Tcl_Interp *ip, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 2) {
Tcl_WrongNumArgs(ip, 1, objv, "window?");
return TCL_ERROR;
}

Tk_Window win;
char *name;
Tcl_HashEntry *hPtr, *hPtr2;

Tcl_HashTable *AccessibleAttributes;

win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
if (win == NULL) {
return TCL_ERROR;
}

/* Get accessible name for window. */
hPtr=Tcl_FindHashEntry(TkAccessibilityObject, win);
if (!hPtr) {
Tcl_AppendResult(ip, "No table found", (char *) NULL);
return TCL_ERROR;
}
AccessibleAttributes = Tcl_GetHashValue(hPtr);
hPtr2=Tcl_FindHashEntry(AccessibleAttributes, (char *) name);
if (!hPtr2) {
Tcl_AppendResult(ip, "No name found", (char *) NULL);
return TCL_ERROR;
}

Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
return TCL_OK;
}

Subject: Re: Values being overwritten in Tcl_HashTable
From: Francois Vogel
Newsgroups: comp.lang.tcl
Organization: Guest of ProXad - France
Date: Mon, 11 Nov 2024 22:23 UTC
References: 1
Path: eternal-september.org!news.eternal-september.org!feeder2.eternal-september.org!news.gegeweb.eu!gegeweb.org!usenet-fr.net!proxad.net!feeder1-2.proxad.net!cleanfeed3-a.proxad.net!nnrp2-2.free.fr!not-for-mail
Date: Mon, 11 Nov 2024 23:23:20 +0100
MIME-Version: 1.0
User-Agent: Mozilla Thunderbird
Subject: Re: Values being overwritten in Tcl_HashTable
To: Kevin Walzer <kw@codebykevin.com>
Newsgroups: comp.lang.tcl
References: <vgru54$q1g9$1@dont-email.me>
Content-Language: en-US
From: francois.vogel.fv.NOSPAM@gmail.com (Francois Vogel)
In-Reply-To: <vgru54$q1g9$1@dont-email.me>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
X-Antivirus: Avast (VPS 241111-0, 11/11/2024), Outbound message
X-Antivirus-Status: Clean
Lines: 66
Message-ID: <673283d9$0$434$426a74cc@news.free.fr>
Organization: Guest of ProXad - France
NNTP-Posting-Date: 11 Nov 2024 23:23:21 CET
NNTP-Posting-Host: 82.65.57.56
X-Trace: 1731363801 news-3.free.fr 434 82.65.57.56:51111
X-Complaints-To: abuse@proxad.net
View all headers

Le 11/11/2024 à 04:37, Kevin Walzer a écrit :
> int
> Tk_SetAccessibleRole(
>              TCL_UNUSED(void *),
>              Tcl_Interp *ip,        /* Current interpreter. */
>              int objc,            /* Number of arguments. */
>              Tcl_Obj *const objv[])    /* Argument objects. */
> {
>   if (objc < 3) {
>     Tcl_WrongNumArgs(ip, 1, objv, "window? role?");
>     return TCL_ERROR;
>   }
>
>   Tk_Window win;
>   char *role;
>   Tcl_HashEntry *hPtr, *hPtr2;
>
>   Tcl_HashTable *AccessibleAttributes;
>   AccessibleAttributes = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
>   Tcl_InitHashTable(AccessibleAttributes,TCL_STRING_KEYS);
>
>   int isNew;
>   win = Tk_NameToWindow(ip, Tcl_GetString(objv[1]), Tk_MainWindow(ip));
>   if (win == NULL) {
>     return TCL_ERROR;
>   }
>
>   /* Set accessible role for window.  */
>   hPtr=Tcl_CreateHashEntry(TkAccessibilityObject, win, &isNew);
>
>   Tcl_SetHashValue(hPtr, AccessibleAttributes);
>
>   hPtr2 =  Tcl_CreateHashEntry(AccessibleAttributes, role, &isNew);
>   if (!isNew) {
>     Tcl_DecrRefCount(Tcl_GetHashValue(hPtr2));
>   }
>   Tcl_IncrRefCount(objv[2]);
>   Tcl_SetHashValue(hPtr2, objv[2]);
>
>   Tcl_SetObjResult(ip, Tcl_GetHashValue(hPtr2));
>   return TCL_OK;
> }

Without diving deep into your code, here a handful of quick observations
that may or may not be useful to you:

1. The canonical pattern for these kind of things is:

int isNew;
hPtr = Tcl_CreateHashEntry(tablePtr, key, &isNew);
if (isNew) {
myValue = ...; // get or create myValue from somewhere
Tcl_SetHashValue(hPtr, myValue);
} else {
myValue = (myValue *)Tcl_GetHashValue(hPtr);
}

Perhaps you should stick at it.

2. You are using the isNew flag twice without checking it the first time.

3. You are calling Tcl_CreateHashEntry twice, yes, but not with the same
hash table. Is this what is intended?

Regards,
Francois

1

rocksolid light 0.9.8
clearnet tor