Skip Menu |

This queue is for tickets about the Tk CPAN distribution.

Report information
The Basics
Id: 121631
Status: resolved
Priority: 0/
Queue: Tk

People
Owner: Nobody in particular
Requestors: mark [...] aufflick.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 804.033
Fixed in:
  • 804.033_500
  • 804.034



Subject: When built with latest clang, tests fail with "Abort trap: 6" due to detecting "buffer overflow" related to Tcl_HashEntry
Ok so this is icky. I just tried to build a perl from scratch and then perl-Tk (as I have done many times before) with the latest clang from Apple's Xcode (but the latest llvm/clang distro will show the same behaviour). make test was failing nearly immediately with "Abort trap: 6". When built with -g and run under lldb, I got: (lldb) r r Process 90756 launched: '/Users/markaufflick/src/_Pumptheory/EFC/hnav1/gdt-app/perl/bin/perl' (x86_64) 2017-05-12 20:59:22.907474 perl[90756:2863014] detected buffer overflow Process 90756 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT frame #0: 0x00007fffb7bdedd6 libsystem_kernel.dylib`__pthread_kill + 10 libsystem_kernel.dylib`__pthread_kill: -> 0x7fffb7bdedd6 <+10>: jae 0x7fffb7bdede0 ; <+20> 0x7fffb7bdedd8 <+12>: movq %rax, %rdi 0x7fffb7bdeddb <+15>: jmp 0x7fffb7bd7cdf ; cerror_nocancel 0x7fffb7bdede0 <+20>: retq (lldb) bt bt * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT * frame #0: 0x00007fffb7bdedd6 libsystem_kernel.dylib`__pthread_kill + 10 frame #1: 0x00007fffb7cca787 libsystem_pthread.dylib`pthread_kill + 90 frame #2: 0x00007fffb7b44420 libsystem_c.dylib`abort + 129 frame #3: 0x00007fffb7b44592 libsystem_c.dylib`abort_report_np + 181 frame #4: 0x00007fffb7b6af28 libsystem_c.dylib`__chk_fail + 48 frame #5: 0x00007fffb7b6aef8 libsystem_c.dylib`__chk_fail_overflow + 16 frame #6: 0x00007fffb7b6b145 libsystem_c.dylib`__strcpy_chk + 83 frame #7: 0x0000000100723467 Tk.bundle`AllocStringEntry + 87 frame #8: 0x000000010072375f Tk.bundle`Tcl_CreateHashEntry + 287 frame #9: 0x00000001007313ec Tk.bundle`TkBindInit + 92 frame #10: 0x0000000100790e83 Tk.bundle`TkCreateMainWindow + 195 frame #11: 0x000000010074a157 Tk.bundle`CreateFrame + 807 frame #12: 0x00000001007124be Tk.bundle`XS_Tk__MainWindow_Create(cv=<unavailable>) at tkGlue.c:2378 [opt] frame #13: 0x000000010009d229 perl`Perl_pp_entersub + 2073 frame #14: 0x0000000100095fc3 perl`Perl_runops_standard + 19 frame #15: 0x000000010002247e perl`perl_run + 878 frame #16: 0x000000010000128f perl`main + 159 frame #17: 0x00007fffb7ab0255 libdyld.dylib`start + 1 (lldb) The problem is that whatever clang's runtime library is doing to detect buffer overflows really doesn't like how Tcl_HashEntry has a union with a char[4] array that is "abused" to be as long a string as we like. The AllocStringEntry symbol causing the problem above is: static Tcl_HashEntry * AllocStringEntry(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key to store in the hash table entry. */ { CONST char *string = (CONST char *) keyPtr; Tcl_HashEntry *hPtr; unsigned int size; size = sizeof(Tcl_HashEntry) + strlen(string) + 1 - sizeof(hPtr->key); if (size < sizeof(Tcl_HashEntry)) size = sizeof(Tcl_HashEntry); hPtr = (Tcl_HashEntry *) ckalloc(size); strcpy(hPtr->key.string, string); return hPtr; } But I can reproduce exactly the same crash with this minimal C: #include <stdlib.h> #include <stdio.h> #include <string.h> typedef struct Tcl_HashEntry { union { /* Key has one of these forms: */ char *oneWordValue; /* One-word value for key. */ int words[1]; /* Multiple integer words for key. * The actual size will be as large * as necessary for this table's * keys. */ char string[4]; /* String for key. The actual size * will be as large as needed to hold * the key. */ } key; /* MUST BE LAST FIELD IN RECORD!! */ } Tcl_HashEntry; int main (void) { char * string = "fooo"; Tcl_HashEntry *hPtr; size_t size = sizeof(Tcl_HashEntry) + strlen(string) + 1 - sizeof(hPtr->key); hPtr = (Tcl_HashEntry *)calloc (1, size); strcpy (hPtr->key.string, string); printf ("foo: %s\n", hPtr->key.string); return 0; } It works fine if string is "foo" (which with null is four chars), but crashes with Abort trap: 6 for "fooo"... Not quite sure what to do here - changing Tcl_HashEntry isn't exactly trivial. I'll investigate if these runtime checks can be turned off (although that wouldn't be ideal - perhaps they can be turned off just for some structures...)
It seems the runtime check is part of the clang/llvm stdlib strcpy/strncpy and can be avoided by using memcpy instead. Same problem in TkTextSegment body.chars & TkTextCharLayoutProc chars fields. Here's a PR that allows all tests to pass: https://github.com/eserte/perl-tk/pull/28 There's probably a better long term solution though...
On 2017-05-12 09:19:05, AUFFLICK wrote: Show quoted text
> It seems the runtime check is part of the clang/llvm stdlib > strcpy/strncpy and can be avoided by using memcpy instead. > > Same problem in TkTextSegment body.chars & TkTextCharLayoutProc chars > fields. > > Here's a PR that allows all tests to pass: > > https://github.com/eserte/perl-tk/pull/28 > > There's probably a better long term solution though...
Thanks, this will be part of the next Tk release. Did you try to compile current Tcl/Tk with this compiler? I wonder if the Tcl folk already have a fix for this.