From e62ea3c5ac49ca894db853d966f1cd2cb808f35c Mon Sep 17 00:00:00 2001 From: David O'Shea Date: Thu, 11 Jan 2018 14:58:16 +1030 Subject: [PATCH] xhfs: Use Tcl_Alloc()/Tcl_Free() as required when interacting with Tcl. On CentOS 7 with tcl-8.5.13-8, xhfs failed with SIGABRT in a number of code paths, including cases where free() was called and eventually resulted in munmap_chunk() reporting e.g.: munmap_chunk(): invalid pointer: 0x000000000089df40 *** and cases where Tcl_Free() was called (presumably internally by Tcl) and eventually resulted in Tcl_Panic() being called and reporting e.g.: alloc: invalid block: 0xb9ce00: 95 8 The failures when calling free() were due to attempts to free memory that was allocated using Tcl_Alloc() and similar functions (possibly via other Tcl calls), so this fix replaces some calls to free() with calls to Tcl_Free(). The failures when calling Tcl_Free() were due to Tcl calling that function for memory that was passed to it via Tcl_SetResult(..., ..., TCL_DYNAMIC) when that memory had been allocated using malloc() or similar functions, so this fix replaces a call to ALLOC() with a call to Tcl_Alloc(), and copies the malloc()'d buffer returned by cs_macroman() or cs_latin1() into a Tcl_Alloc()'d buffer. --- tclhfs.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tclhfs.c b/tclhfs.c index 636f985..e854cbc 100644 --- a/tclhfs.c +++ b/tclhfs.c @@ -227,7 +227,7 @@ int getdir(Tcl_Interp *interp, volref *vref, const char *path) Tcl_AppendElement(interp, str); - free(str); + Tcl_Free(str); } if (hfs_closedir(dir) == -1) @@ -244,7 +244,7 @@ int getdir(Tcl_Interp *interp, volref *vref, const char *path) Tcl_AppendElement(interp, str); - free(str); + Tcl_Free(str); } return TCL_OK; @@ -378,17 +378,12 @@ int file_cmd(ClientData clientData, Tcl_Interp *interp, return TCL_ERROR; } - mem = ALLOC(char, bytes + 1); - if (mem == 0) - { - interp->result = "out of memory"; - return TCL_ERROR; - } + mem = Tcl_Alloc(bytes + 1); bytes = hfs_read(file, mem, bytes); if (bytes == -1) { - free(mem); + Tcl_Free(mem); return error(interp, 0); } @@ -902,7 +897,7 @@ int vol_cmd(ClientData clientData, Tcl_Interp *interp, } result = Tcl_Merge(listc, listv); - free(listv); + Tcl_Free(listv); Tcl_SetResult(interp, result, TCL_DYNAMIC); } @@ -1047,7 +1042,7 @@ int vol_cmd(ClientData clientData, Tcl_Interp *interp, } result = Tcl_Merge(fargc, fargv); - free(fargv); + Tcl_Free(fargv); Tcl_SetResult(interp, result, TCL_DYNAMIC); } @@ -1313,7 +1308,7 @@ int cmd_hfs(ClientData clientData, Tcl_Interp *interp, badblocks = ALLOCX(unsigned long, listc); if (listc && badblocks == 0) { - free(listv); + Tcl_Free(listv); interp->result = "out of memory"; return TCL_ERROR; @@ -1324,13 +1319,13 @@ int cmd_hfs(ClientData clientData, Tcl_Interp *interp, if (Tcl_ExprLong(interp, listv[i], (long *) &badblocks[i]) != TCL_OK) { - free(listv); + Tcl_Free(listv); FREE(badblocks); return TCL_ERROR; } } - free(listv); + Tcl_Free(listv); if (do_format(argv[2], partno, 0, argv[4], listc, badblocks) == -1) { @@ -1352,6 +1347,7 @@ int cmd_hfs(ClientData clientData, Tcl_Interp *interp, else if (strcmp(argv[1], "chartrans") == 0) { char *result; + char *tclresult; if (argc != 5) { @@ -1387,7 +1383,11 @@ int cmd_hfs(ClientData clientData, Tcl_Interp *interp, return TCL_ERROR; } - Tcl_SetResult(interp, result, TCL_DYNAMIC); + tclresult = Tcl_Alloc(strlen(result) + 1); + memcpy(tclresult, result, strlen(result) + 1); + free(result); + + Tcl_SetResult(interp, tclresult, TCL_DYNAMIC); } else if (strcmp(argv[1], "version") == 0) {