[tkined] Memory leak found.

Matthew Upton (mupton@bridgewatersys.com)
Mon, 20 Dec 1999 09:02:19 -0500

I came across a memory leak in the Tnm library. It occurs
in the decode routines for SNMPv1 traps, and variable
bindings of the following syntaxes:
INTEGER (enumerated values actually)
OCTET STRING
ASN1_OBJECT_IDENTIFIER

The problem was that the TnmMibFormat command was returning
a char* that it extracted from a Tcl_Obj, but the Tcl_Obj
was never deleted (it was obtained from TnmMibFormatValue).
The changes I made to fix it were to make TnmMibFormat
return a Tcl_Obj* and have any routines calling this
function deallocate the Tcl_Obj*. Here is the affected code
(My changes are indicated by (***) ):

tnmMib.h:
=======
EXTERN Tcl_Obj* (***)
TnmMibFormatValue _ANSI_ARGS_((TnmMibType *typePtr, int
syntax,
Tcl_Obj *value));

tnmMibUtil.c:
==========
Tcl_Obj*
(***)
TnmMibFormat(name, exact, value)
char *name;
int exact;
char *value;
{
TnmMibNode *nodePtr;
Tcl_Obj *src, *dst;

nodePtr = TnmMibFindNode(name, NULL, exact);
if (! nodePtr) {
return NULL;
}

if ((nodePtr->macro != TNM_MIB_OBJECTTYPE) &&
!(nodePtr->macro == TNM_MIB_VALUE_ASSIGNEMENT &&
!nodePtr->childPtr)) {
return NULL;
}

src = Tcl_NewStringObj(value, -1);
dst = TnmMibFormatValue(nodePtr->typePtr, (int)
nodePtr->syntax, src);
Tcl_DecrRefCount(src);

if
(dst)
(***)
return
dst;
(***)

else
(***)
return
Tcl_NewStringObj(value,-1);
(***)
/* return dst ? Tcl_GetStringFromObj(dst, NULL) :
value; */
}

tnmSnmpRecv.c: line 1298
====================
Tcl_Obj *tmp = TnmMibFormat("1.3.6.1.6.3.1.1.4.1.0", 0,
toid); (***)
if (tmp) {
char *tmp2 = Tcl_GetStringFromObj(tmp,
NULL); (***)
Tcl_DStringAppendElement(&pdu->varbind,
tmp2); (***)

Tcl_DecrRefCount(tmp);
(***)
} else {
Tcl_DStringAppendElement(&pdu->varbind, toid);
}
tnmSnmpRecv.c: line 1476
====================
case ASN1_INTEGER:
packet = TnmBerDecInt(packet, packetlen, tag,
&int_val);
if (packet == NULL) goto asn1Error;
{ char* tmp2;
Tcl_Obj*
tmp;
(***)
sprintf(buf, "%d", int_val);
tmp = TnmMibFormat(vboid, 0, buf);
if (tmp) {
tmp2 = Tcl_GetStringFromObj(tmp,
NULL); (***)
Tcl_DStringAppendElement(&pdu->varbind,
tmp2); (***)

Tcl_DecrRefCount(tmp);
(***)
} else {
Tcl_DStringAppendElement(&pdu->varbind, buf);
}
tnmSnmpRecv.c: line 1514
====================
case ASN1_OBJECT_IDENTIFIER:
packet = TnmBerDecOID(packet, packetlen, oid,
&oidlen);
if (packet == NULL) goto asn1Error;
#if 1
{ char *soid = TnmOidToStr(oid, oidlen);
Tcl_Obj *tmp = TnmMibFormat(vboid, 0,
soid); (***)
if (tmp) {
char *tmp2 = Tcl_GetStringFromObj(tmp,
NULL); (***)
Tcl_DStringAppendElement(&pdu->varbind,
tmp2); (***)

Tcl_DecrRefCount(tmp);
(***)
} else {
Tcl_DStringAppendElement(&pdu->varbind, soid);
}
}

tnmSnmpRecv.c: 1542
====================
case ASN1_OCTET_STRING:
packet = TnmBerDecOctetString(packet, packetlen,
tag,
(char **) &freeme, &int_val);
if (packet == NULL) goto asn1Error;
{
char* tmp2;
Tcl_Obj*
tmp; (***)
/* char *tmp;*/
static char *hex = NULL;
static int hexLen = 0;
if (hexLen < int_val * 5 + 1) {
if (hex) ckfree(hex);
hexLen = int_val * 5 + 1;
hex = ckalloc(hexLen);
}
TnmHexEnc(freeme, int_val, hex);
if (tag == ASN1_OCTET_STRING) {
tmp = TnmMibFormat(vboid, 0, hex);
if (tmp) {
tmp2 = Tcl_GetStringFromObj(tmp, NULL);
(***)
Tcl_DStringAppendElement(&pdu->varbind, tmp2); (***)

Tcl_DecrRefCount(tmp);
(***)
} else {
Tcl_DStringAppendElement(&pdu->varbind, hex);

==============
Here is the script I used to monitor the leak:

package require Tnm
set s [Tnm::snmp generator -address 10.10.10.1]

# These function take option a S for single
# VB or M for multiple VBs
proc sync {option} {
global s

set i 0
while {$i < 10000} {
if {$option == "i"} {
catch {set x [$s get {ifOperStatus.14}]}
} elseif {$option == "os"} {
catch {set x [$s get {sysLocation.0}]}
} elseif {$option == "tt"} {
catch {set x [$s get {sysUpTime.0}]}
} else {
puts "unknown type code"
}

incr i
}
puts "Done"
}
"sync i' and "sync os" were leaking memory but "sync tt"
was not.

Regards,

Matt Upton

--

Matthew Upton Bridgewater Systems mupton@bridgewatersys.com

--
!! This message is brought to you via the `tkined & scotty' mailing list.
!! Please do not reply to this message to unsubscribe. To subscribe or
!! unsubscribe, send a mail message to <tkined-request@ibr.cs.tu-bs.de>.
!! See http://wwwsnmp.cs.utwente.nl/~schoenw/scotty/ for more information.