From mboxrd@z Thu Jan 1 00:00:00 1970 From: Fernando Nasser To: insight@sources.redhat.com Subject: Buffer Overflow Patch in GDB/TCL Interface code. Date: Thu, 19 Oct 2000 06:30:00 -0000 Message-id: <39EEF758.21EDD4C5@cygnus.com> X-SW-Source: 2000-q4/msg00087.html Message forwarded in behalf of Steven Johnson (Steven is not sure if this message made it to the list -- ISP problems. Please forgive us if you get it in duplicate) There are a number of fixed size buffers defined in the C code that acts as an interface between GDB and the TCL Insight. Unfortunately, on my system some of those buffers were not big enough, leading to stack corruption and a resultant segfault. I Specifically had a problem with clearing breakpoints, the problem was that the path to my source file was quite long, and caused a sprintf to overflow it's pre-allocated buffer. Instead of just adding some more to the buffer, i decided to fix as many of the pre-allocated buffers as possible, so that this sort of problem can not occur in future. A Couple of fixes were tried. The one I settled on was wholescale replacement of as many 'sprintf'/'vsprintf' calls with 'asprintf' and 'vasprintf' respectively, as was possible without serious modification of the existing code. There are now only 2 or 3 places in gdbtk-cmds where sprintf is used (Mainly to do with source file loading). Everywhere else has been replaced with asprintf/vasprintf. Given that neither asprintf or vasprintf are in the MAN pages of linux, here is a brief explenation. asprintf (I call it "auto sprintf"): It automatically allocates a buffer of the correct size to hold the sprintf'd string. The buffer when finished with must be discarded with "free", otherwise you will get a heap leak. vasprintf is the same as vsprintf, except it too automatically allocates its buffer. Eg: Where code would have once been: char buf[1024]; /* This is big enough for any reasonable use I reckon. */ sprintf(buf,"my %s %s %s %s %s undetermined length string",s1,s2,s3,s4,s5); it is written as: char *buf; sprintf(&buf,"my %s %s %s %s %s undetermined length string",s1,s2,s3,s4,s5); /* I have now finished with buf, so... */ free(buf); The big difference is you no longer have to guess the size of your buffer, so no more stack corruption can result. It has been used elsewhere in GDB/Insight (remote.c and MI) to name a couple, ergo, "it's portable". If it isn't really portable, then I would suggest adding a local copy to utils.c in GDB for targets that do not support it. Anyway, here comes the changelog and patch: 12345678901234567890123456789012345678901234567890123456789012345678901234567890 2000-10-19 Steven Johnson * gdbtk.c,gdbtk-cmds.c,gdbtk-hooks.c,gdbtk-variable.c : Replaced the vast majority of sprintf/vsprintf calls with asprintf and vasprintf respectively. Should prevent any possible buffer overruns possible with fixed size sprintf buffers. Specifically fixes a problem with long filenames and clearing breakpoints overflowing their buffers when using sprintf, causing a segfault. Generically should also prevent any other similar problems from occuring. diff -C2 -r -b ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk-cmds.c src/gdb/gdbtk/generic/gdbtk-cmds.c *** ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk-cmds.c Mon Aug 21 08:59:40 2000 --- src/gdb/gdbtk/generic/gdbtk-cmds.c Thu Oct 19 11:25:10 2000 *************** *** 546,556 **** { va_list args; ! char buf[1024]; va_start (args, format); ! vsprintf (buf, format, args); Tcl_ListObjAppendElement (NULL, objp, Tcl_NewStringObj (buf, -1)); } --- 546,557 ---- { va_list args; ! char *buf; va_start (args, format); ! vasprintf (&buf, format, args); Tcl_ListObjAppendElement (NULL, objp, Tcl_NewStringObj (buf, -1)); + free(buf); } *************** *** 2009,2016 **** Tcl_Obj *CONST objv[]; { ! char buff[64]; ! sprintf (buff, "0x%llx", (long long) read_register (PC_REGNUM)); Tcl_SetStringObj (result_ptr->obj_ptr, buff, -1); return TCL_OK; } --- 2010,2018 ---- Tcl_Obj *CONST objv[]; { ! char *buff; ! asprintf (&buff, "0x%llx", (long long) read_register (PC_REGNUM)); Tcl_SetStringObj (result_ptr->obj_ptr, buff, -1); + free(buff); return TCL_OK; } *************** *** 2181,2187 **** if (tp == NULL) { ! char buff[64]; ! sprintf (buff, "Tracepoint #%d does not exist", tpnum); Tcl_SetStringObj (result_ptr->obj_ptr, buff, -1); return TCL_ERROR; } --- 2183,2190 ---- if (tp == NULL) { ! char *buff; ! asprintf (&buff, "Tracepoint #%d does not exist", tpnum); Tcl_SetStringObj (result_ptr->obj_ptr, buff, -1); + free(buff); return TCL_ERROR; } *************** *** 2598,2609 **** if (ret_val == TCL_OK) { ! char buffer[256]; Tcl_Obj *limits_obj[2]; ! sprintf (buffer, "0x%s", paddr_nz (low)); limits_obj[0] = Tcl_NewStringObj (buffer, -1); ! sprintf (buffer, "0x%s", paddr_nz (high)); limits_obj[1] = Tcl_NewStringObj (buffer, -1); Tcl_DecrRefCount (result_ptr->obj_ptr); --- 2601,2614 ---- if (ret_val == TCL_OK) { ! char *buffer; Tcl_Obj *limits_obj[2]; ! asprintf (&buffer, "0x%s", paddr_nz (low)); limits_obj[0] = Tcl_NewStringObj (buffer, -1); + free(buffer); ! asprintf (&buffer, "0x%s", paddr_nz (high)); limits_obj[1] = Tcl_NewStringObj (buffer, -1); + free(buffer); Tcl_DecrRefCount (result_ptr->obj_ptr); *************** *** 2621,2625 **** struct disassembly_client_data *client_data = (struct disassembly_client_data *) clientData; ! char buffer[18]; int index_len; --- 2626,2630 ---- struct disassembly_client_data *client_data = (struct disassembly_client_data *) clientData; ! char *buffer; int index_len; *************** *** 2696,2704 **** will allow us avoid converting widget_line_no into a string. */ ! sprintf (buffer, "%d", client_data->widget_line_no); Tcl_SetVar2 (client_data->interp, client_data->map_arr, Tcl_DStringValue (&client_data->src_to_line_prefix), buffer, 0); Tcl_DStringSetLength (&client_data->src_to_line_prefix, index_len); --- 2701,2710 ---- will allow us avoid converting widget_line_no into a string. */ ! asprintf (&buffer, "%d", client_data->widget_line_no); Tcl_SetVar2 (client_data->interp, client_data->map_arr, Tcl_DStringValue (&client_data->src_to_line_prefix), buffer, 0); + free(buffer); Tcl_DStringSetLength (&client_data->src_to_line_prefix, index_len); *************** *** 2802,2806 **** if (*client_data->map_arr != '\0') { ! char buffer[16]; /* Run the command, then add an entry to the map array in --- 2808,2812 ---- if (*client_data->map_arr != '\0') { ! char *buffer; /* Run the command, then add an entry to the map array in *************** *** 2812,2816 **** will allow us avoid converting widget_line_no into a string. */ ! sprintf (buffer, "%d", client_data->widget_line_no); Tcl_SetVar2 (client_data->interp, client_data->map_arr, --- 2818,2822 ---- will allow us avoid converting widget_line_no into a string. */ ! asprintf (&buffer, "%d", client_data->widget_line_no); Tcl_SetVar2 (client_data->interp, client_data->map_arr, *************** *** 2829,2832 **** --- 2835,2839 ---- Tcl_DStringSetLength (&client_data->line_to_pc_prefix, line_to_pc_len); + free(buffer); } *************** *** 3685,3689 **** int line, ret, thread = -1; struct breakpoint *b; ! char buf[64], *typestr; Tcl_DString cmd; enum bpdisp disp; --- 3692,3696 ---- int line, ret, thread = -1; struct breakpoint *b; ! char *buf, *typestr; Tcl_DString cmd; enum bpdisp disp; *************** *** 3745,3751 **** /* FIXME: this won't work for duplicate basenames! */ ! sprintf (buf, "%s:%d", basename (Tcl_GetStringFromObj (objv[1], NULL)), line); b->addr_string = strsave (buf); /* now send notification command back to GUI */ --- 3752,3759 ---- /* FIXME: this won't work for duplicate basenames! */ ! asprintf (&buf, "%s:%d", basename (Tcl_GetStringFromObj (objv[1], NULL)), line); b->addr_string = strsave (buf); + free(buf); /* now send notification command back to GUI */ *************** *** 3754,3769 **** Tcl_DStringAppend (&cmd, "gdbtk_tcl_breakpoint create ", -1); ! sprintf (buf, "%d", b->number); Tcl_DStringAppendElement (&cmd, buf); ! sprintf (buf, "0x%lx", (long) sal.pc); Tcl_DStringAppendElement (&cmd, buf); Tcl_DStringAppendElement (&cmd, Tcl_GetStringFromObj (objv[2], NULL)); Tcl_DStringAppendElement (&cmd, Tcl_GetStringFromObj (objv[1], NULL)); Tcl_DStringAppendElement (&cmd, bpdisp[b->disposition]); ! sprintf (buf, "%d", b->enable); Tcl_DStringAppendElement (&cmd, buf); ! sprintf (buf, "%d", b->thread); Tcl_DStringAppendElement (&cmd, buf); ! ret = Tcl_Eval (interp, Tcl_DStringValue (&cmd)); --- 3762,3780 ---- Tcl_DStringAppend (&cmd, "gdbtk_tcl_breakpoint create ", -1); ! asprintf (&buf, "%d", b->number); Tcl_DStringAppendElement (&cmd, buf); ! free(buf); ! asprintf (&buf, "0x%lx", (long) sal.pc); Tcl_DStringAppendElement (&cmd, buf); Tcl_DStringAppendElement (&cmd, Tcl_GetStringFromObj (objv[2], NULL)); Tcl_DStringAppendElement (&cmd, Tcl_GetStringFromObj (objv[1], NULL)); Tcl_DStringAppendElement (&cmd, bpdisp[b->disposition]); ! free(buf); ! asprintf (&buf, "%d", b->enable); Tcl_DStringAppendElement (&cmd, buf); ! free(buf); ! asprintf (&buf, "%d", b->thread); Tcl_DStringAppendElement (&cmd, buf); ! free(buf); ret = Tcl_Eval (interp, Tcl_DStringValue (&cmd)); *************** *** 3797,3801 **** long addr; struct breakpoint *b; ! char *filename, *typestr, buf[64]; Tcl_DString cmd; enum bpdisp disp; --- 3808,3812 ---- long addr; struct breakpoint *b; ! char *filename, *typestr, *buf; Tcl_DString cmd; enum bpdisp disp; *************** *** 3849,3853 **** b->thread = thread; ! sprintf (buf, "*(0x%lx)", addr); b->addr_string = strsave (buf); --- 3860,3864 ---- b->thread = thread; ! asprintf (&buf, "*(0x%lx)", addr); b->addr_string = strsave (buf); *************** *** 3857,3865 **** Tcl_DStringAppend (&cmd, "gdbtk_tcl_breakpoint create ", -1); ! sprintf (buf, "%d", b->number); Tcl_DStringAppendElement (&cmd, buf); ! sprintf (buf, "0x%lx", addr); Tcl_DStringAppendElement (&cmd, buf); ! sprintf (buf, "%d", b->line_number); Tcl_DStringAppendElement (&cmd, buf); --- 3868,3879 ---- Tcl_DStringAppend (&cmd, "gdbtk_tcl_breakpoint create ", -1); ! free(buf); ! asprintf (&buf, "%d", b->number); Tcl_DStringAppendElement (&cmd, buf); ! free(buf); ! asprintf (&buf, "0x%lx", addr); Tcl_DStringAppendElement (&cmd, buf); ! free(buf); ! asprintf (&buf, "%d", b->line_number); Tcl_DStringAppendElement (&cmd, buf); *************** *** 3869,3879 **** Tcl_DStringAppendElement (&cmd, filename); Tcl_DStringAppendElement (&cmd, bpdisp[b->disposition]); ! sprintf (buf, "%d", b->enable); Tcl_DStringAppendElement (&cmd, buf); ! sprintf (buf, "%d", b->thread); Tcl_DStringAppendElement (&cmd, buf); ret = Tcl_Eval (interp, Tcl_DStringValue (&cmd)); Tcl_DStringFree (&cmd); return ret; } --- 3883,3896 ---- Tcl_DStringAppendElement (&cmd, filename); Tcl_DStringAppendElement (&cmd, bpdisp[b->disposition]); ! free(buf); ! asprintf (&buf, "%d", b->enable); Tcl_DStringAppendElement (&cmd, buf); ! free(buf); ! asprintf (&buf, "%d", b->thread); Tcl_DStringAppendElement (&cmd, buf); ret = Tcl_Eval (interp, Tcl_DStringValue (&cmd)); Tcl_DStringFree (&cmd); + free(buf); return ret; } *************** *** 4014,4020 **** if (!b || b->type != bp_breakpoint) { ! char err_buf[64]; ! sprintf (err_buf, "Breakpoint #%d does not exist.", bpnum); Tcl_SetStringObj (result_ptr->obj_ptr, err_buf, -1); return TCL_ERROR; } --- 4031,4038 ---- if (!b || b->type != bp_breakpoint) { ! char *err_buf; ! asprintf (&err_buf, "Breakpoint #%d does not exist.", bpnum); Tcl_SetStringObj (result_ptr->obj_ptr, err_buf, -1); + free(err_buf); return TCL_ERROR; } *************** *** 4309,4321 **** Tcl_Obj *CONST objv[]; { ! char frame[32]; if (selected_frame == NULL) ! strcpy (frame, ""); else ! sprintf (frame, "0x%s", paddr_nz (FRAME_FP (selected_frame))); Tcl_SetStringObj (result_ptr->obj_ptr, frame, -1); return TCL_OK; } --- 4327,4340 ---- Tcl_Obj *CONST objv[]; { ! char *frame; if (selected_frame == NULL) ! asprintf (&frame, "%s",""); else ! asprintf (&frame, "0x%s", paddr_nz (FRAME_FP (selected_frame))); Tcl_SetStringObj (result_ptr->obj_ptr, frame, -1); + free(frame); return TCL_OK; } *************** *** 4339,4349 **** Tcl_Obj *CONST objv[]; { ! char start[32]; ! char end[32]; if (selected_frame == NULL) { ! strcpy (start, ""); ! strcpy (end, ""); } else --- 4358,4368 ---- Tcl_Obj *CONST objv[]; { ! char *start = NULL; ! char *end = NULL; if (selected_frame == NULL) { ! asprintf (&start, "%s", ""); ! asprintf (&end, "%s", ""); } else *************** *** 4351,4356 **** struct block *block; block = get_frame_block (selected_frame); ! sprintf (start, "0x%s", paddr_nz (BLOCK_START (block))); ! sprintf (end, "0x%s", paddr_nz (BLOCK_END (block))); } --- 4370,4375 ---- struct block *block; block = get_frame_block (selected_frame); ! asprintf (&start, "0x%s", paddr_nz (BLOCK_START (block))); ! asprintf (&end, "0x%s", paddr_nz (BLOCK_END (block))); } *************** *** 4361,4364 **** --- 4380,4385 ---- Tcl_NewStringObj (end, -1)); + free(start); + free(end); return TCL_OK; } *************** *** 4436,4449 **** if (!junk && pc < BLOCK_END (block)) { ! char addr[32]; Tcl_Obj *elt = Tcl_NewListObj (0, NULL); ! sprintf (addr, "0x%s", paddr_nz (BLOCK_START (block))); Tcl_ListObjAppendElement (interp, elt, Tcl_NewStringObj (addr, -1)); ! sprintf (addr, "0x%s", paddr_nz (BLOCK_END (block))); Tcl_ListObjAppendElement (interp, elt, Tcl_NewStringObj (addr, -1)); Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, elt); } --- 4457,4472 ---- if (!junk && pc < BLOCK_END (block)) { ! char *addr; Tcl_Obj *elt = Tcl_NewListObj (0, NULL); ! asprintf (&addr, "0x%s", paddr_nz (BLOCK_START (block))); Tcl_ListObjAppendElement (interp, elt, Tcl_NewStringObj (addr, -1)); ! free(addr); ! asprintf (&addr, "0x%s", paddr_nz (BLOCK_END (block))); Tcl_ListObjAppendElement (interp, elt, Tcl_NewStringObj (addr, -1)); Tcl_ListObjAppendElement (interp, result_ptr->obj_ptr, elt); + free(addr); } diff -C2 -r -b ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk-hooks.c src/gdb/gdbtk/generic/gdbtk-hooks.c *** ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk-hooks.c Thu Jul 13 09:10:03 2000 --- src/gdb/gdbtk/generic/gdbtk-hooks.c Thu Oct 19 10:54:06 2000 *************** *** 293,300 **** va_list args; { ! char buf[200]; ! vsprintf (buf, warning, args); gdbtk_two_elem_cmd ("gdbtk_tcl_warning", buf); } --- 293,302 ---- va_list args; { ! char *buf; ! vasprintf (&buf, warning, args); gdbtk_two_elem_cmd ("gdbtk_tcl_warning", buf); + + free(buf); } *************** *** 326,333 **** const char *warning; { ! char buf[512]; ! sprintf (buf, "gdbtk_tcl_ignorable_warning {%s} {%s}", class, warning); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); } --- 328,336 ---- const char *warning; { ! char *buf; ! asprintf (&buf, "gdbtk_tcl_ignorable_warning {%s} {%s}", class, warning); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); + free(buf); } *************** *** 460,468 **** { va_list args; ! char buf[200]; va_start (args, format); ! vsprintf (buf, format, args); gdbtk_two_elem_cmd ("gdbtk_tcl_readline_begin", buf); } --- 466,475 ---- { va_list args; ! char *buf; va_start (args, format); ! vasprintf (&buf, format, args); gdbtk_two_elem_cmd ("gdbtk_tcl_readline_begin", buf); + free(buf); } *************** *** 529,533 **** Tcl_DString cmd; char *p; ! char buffer[30]; Tcl_DStringInit (&cmd); --- 536,540 ---- Tcl_DString cmd; char *p; ! char *buffer = NULL; Tcl_DStringInit (&cmd); *************** *** 541,545 **** { char *q = strchr (p, ' '); ! char save; if (q) { --- 548,552 ---- { char *q = strchr (p, ' '); ! char save = '\0'; if (q) { *************** *** 572,581 **** case var_uinteger: case var_zinteger: ! sprintf (buffer, "%u", *(unsigned int *) cmdblk->var); Tcl_DStringAppendElement (&cmd, buffer); break; case var_integer: ! sprintf (buffer, "%d", *(int *) cmdblk->var); Tcl_DStringAppendElement (&cmd, buffer); break; --- 579,588 ---- case var_uinteger: case var_zinteger: ! asprintf (&buffer, "%u", *(unsigned int *) cmdblk->var); Tcl_DStringAppendElement (&cmd, buffer); break; case var_integer: ! asprintf (&buffer, "%d", *(int *) cmdblk->var); Tcl_DStringAppendElement (&cmd, buffer); break; *************** *** 591,594 **** --- 598,606 ---- Tcl_DStringFree (&cmd); + + if (buffer != NULL) + { + free(buffer); + } } *************** *** 631,635 **** const char *action; { ! char buf[256]; int v; struct symtab_and_line sal; --- 643,647 ---- const char *action; { ! char *buf; int v; struct symtab_and_line sal; *************** *** 646,650 **** filename = ""; ! sprintf (buf, "gdbtk_tcl_breakpoint %s %d 0x%lx %d {%s} {%s} %d %d", action, b->number, (long) b->address, b->line_number, filename, bpdisp[b->disposition], b->enable, b->thread); --- 658,662 ---- filename = ""; ! asprintf (&buf, "gdbtk_tcl_breakpoint %s %d 0x%lx %d {%s} {%s} %d %d", action, b->number, (long) b->address, b->line_number, filename, bpdisp[b->disposition], b->enable, b->thread); *************** *** 652,655 **** --- 664,668 ---- if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); + free(buf); } *************** *** 657,664 **** gdbtk_load_hash (const char *section, unsigned long num) { ! char buf[128]; ! sprintf (buf, "Download::download_hash %s %ld", section, num); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); return atoi (gdbtk_interp->result); } --- 670,679 ---- gdbtk_load_hash (const char *section, unsigned long num) { ! char *buf; ! asprintf (&buf, "Download::download_hash %s %ld", section, num); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); + free(buf); + return atoi (gdbtk_interp->result); } *************** *** 712,720 **** va_list args; { ! char buf[200]; long val; ! vsprintf (buf, query, args); gdbtk_two_elem_cmd ("gdbtk_tcl_query", buf); val = atol (gdbtk_interp->result); --- 727,736 ---- va_list args; { ! char *buf; long val; ! vasprintf (&buf, query, args); gdbtk_two_elem_cmd ("gdbtk_tcl_query", buf); + free(buf); val = atol (gdbtk_interp->result); *************** *** 760,764 **** const char *action; { ! char buf[256]; int v; struct symtab_and_line sal; --- 776,780 ---- const char *action; { ! char *buf; int v; struct symtab_and_line sal; *************** *** 772,780 **** if (filename == NULL) filename = "N/A"; ! sprintf (buf, "gdbtk_tcl_tracepoint %s %d 0x%lx %d {%s} %d", action, tp->number, (long) tp->address, sal.line, filename, tp->pass_count); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); } --- 788,797 ---- if (filename == NULL) filename = "N/A"; ! asprintf (&buf, "gdbtk_tcl_tracepoint %s %d 0x%lx %d {%s} %d", action, tp->number, (long) tp->address, sal.line, filename, tp->pass_count); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); + free(buf); } *************** *** 877,881 **** gdbtk_annotate_signal () { ! char buf[128]; /* Inform gui that the target has stopped. This is --- 894,898 ---- gdbtk_annotate_signal () { ! char *buf; /* Inform gui that the target has stopped. This is *************** *** 885,892 **** Tcl_Eval (gdbtk_interp, "gdbtk_stop_idle_callback"); ! sprintf (buf, "gdbtk_signal %s {%s}", target_signal_to_name (stop_signal), target_signal_to_string (stop_signal)); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); } --- 902,910 ---- Tcl_Eval (gdbtk_interp, "gdbtk_stop_idle_callback"); ! asprintf (&buf, "gdbtk_signal %s {%s}", target_signal_to_name (stop_signal), target_signal_to_string (stop_signal)); if (Tcl_Eval (gdbtk_interp, buf) != TCL_OK) report_error (); + free(buf); } diff -C2 -r -b ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk-variable.c src/gdb/gdbtk/generic/gdbtk-variable.c *** ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk-variable.c Thu Jul 13 09:10:03 2000 --- src/gdb/gdbtk/generic/gdbtk-variable.c Thu Oct 19 11:18:26 2000 *************** *** 566,570 **** gdb_variable *var; char *name; ! char obj_name[31]; int index; static int id = 0; --- 566,570 ---- gdb_variable *var; char *name; ! char *obj_name; int index; static int id = 0; *************** *** 587,596 **** /* generate a name for this object */ id++; ! sprintf (obj_name, "var%d", id); } else { /* specified name for object */ ! strncpy (obj_name, name, 30); objv++; objc--; --- 587,596 ---- /* generate a name for this object */ id++; ! asprintf (&obj_name, "var%d", id); } else { /* specified name for object */ ! asprintf (&obj_name, "%s", name); objv++; objc--; *************** *** 648,651 **** --- 648,653 ---- } + free(obj_name); + return TCL_ERROR; } *************** *** 2018,2025 **** case TYPE_CODE_ARRAY: { ! char number[16]; *obj = Tcl_NewStringObj (NULL, 0); ! sprintf (number, "%d", var->num_children); Tcl_AppendStringsToObj (*obj, "[", number, "]", NULL); } break; --- 2020,2028 ---- case TYPE_CODE_ARRAY: { ! char *number; *obj = Tcl_NewStringObj (NULL, 0); ! asprintf (&number, "%d", var->num_children); Tcl_AppendStringsToObj (*obj, "[", number, "]", NULL); + free(number); } break; diff -C2 -r -b ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk.c src/gdb/gdbtk/generic/gdbtk.c *** ../gdb_cvs/src/gdb/gdbtk/generic/gdbtk.c Thu Jul 6 12:04:47 2000 --- src/gdb/gdbtk/generic/gdbtk.c Thu Oct 19 10:59:48 2000 *************** *** 197,201 **** { va_list args; ! char buf[10000], *v[3], *merge, *priority; switch (level) --- 197,201 ---- { va_list args; ! char *buf, *v[3], *merge, *priority; switch (level) *************** *** 216,230 **** va_start (args, fmt); v[0] = "dbug"; v[1] = priority; v[2] = buf; - vsprintf (buf, fmt, args); - va_end (args); - merge = Tcl_Merge (3, v); if (Tcl_Eval (gdbtk_interp, merge) != TCL_OK) Tcl_BackgroundError (gdbtk_interp); Tcl_Free (merge); } --- 216,232 ---- va_start (args, fmt); + + vasprintf (&buf, fmt, args); + va_end (args); + v[0] = "dbug"; v[1] = priority; v[2] = buf; merge = Tcl_Merge (3, v); if (Tcl_Eval (gdbtk_interp, merge) != TCL_OK) Tcl_BackgroundError (gdbtk_interp); Tcl_Free (merge); + free(buf); } *************** *** 359,363 **** struct cleanup *old_chain; int found_main; ! char s[5]; Tcl_Obj *auto_path_elem, *auto_path_name; --- 361,365 ---- struct cleanup *old_chain; int found_main; ! char *s; Tcl_Obj *auto_path_elem, *auto_path_name; *************** *** 389,394 **** /* Set up some globals used by gdb to pass info to gdbtk for start up options and the like */ ! sprintf (s, "%d", inhibit_gdbinit); Tcl_SetVar2 (gdbtk_interp, "GDBStartup", "inhibit_prefs", s, TCL_GLOBAL_ONLY); /* Note: Tcl_SetVar2() treats the value as read-only (making a copy). Unfortunatly it does not mark the parameter as --- 391,398 ---- /* Set up some globals used by gdb to pass info to gdbtk for start up options and the like */ ! asprintf (&s, "%d", inhibit_gdbinit); Tcl_SetVar2 (gdbtk_interp, "GDBStartup", "inhibit_prefs", s, TCL_GLOBAL_ONLY); + free(s); + /* Note: Tcl_SetVar2() treats the value as read-only (making a copy). Unfortunatly it does not mark the parameter as