From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/401 Path: news.gmane.org!not-for-mail From: =?UTF-8?B?THVrYSBNYXLEjWV0acSH?= Newsgroups: gmane.linux.lib.musl.general Subject: cluts daily reports 8/12 - continuing pthread_eintr, still stuck with alloc Date: Fri, 12 Aug 2011 04:45:58 +0200 Message-ID: <4E4493E6.6050809@gmail.com> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------090706090809050607060800" X-Trace: dough.gmane.org 1313117310 23274 80.91.229.12 (12 Aug 2011 02:48:30 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Fri, 12 Aug 2011 02:48:30 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-402-gllmg-musl=m.gmane.org@lists.openwall.com Fri Aug 12 04:48:26 2011 Return-path: Envelope-to: gllmg-musl@lo.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by lo.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1QrhnN-00044E-Hk for gllmg-musl@lo.gmane.org; Fri, 12 Aug 2011 04:48:25 +0200 Original-Received: (qmail 21934 invoked by uid 550); 12 Aug 2011 02:48:25 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 21920 invoked from network); 12 Aug 2011 02:48:24 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject :content-type; bh=3/mlcjAelFXrMYMjHNYSpEX2ENepEuFRYAPGnKXm2Rc=; b=eQlOf6u92t1yvHXYg3uaxHSJCXDf8mFrUaMEfSfs8Qtdp9FoUFDtug1AL4gQtu2x6l h6dykfWF4Q5V62H7lFcu2awbJmndFtIachJKQpDO/G0RNLrHA5NXPascgB6/6MoF8gxf NeGPeU25r33fpT4TXs69xmh2zbZ0g/biRwjN4= User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110626 Icedove/3.1.11 Xref: news.gmane.org gmane.linux.lib.musl.general:401 Archived-At: This is a multi-part message in MIME format. --------------090706090809050607060800 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hey. As I've explained in the recent e-mail to Alexander, I couldn't get alloc.c to work with musl, so I switched to pthread_eintr, but ran into a problem there too. Rich, help me out please with the question from IRC: What's up with the line from pthread_eintr.c looking like this: pthread_cleanup_push(child_wait_vp, NULL); Both musl and glibc macros generate invalid code for this one, it ends with `do {;` in both cases iirc. Strange - what is it? Thank you, Luka P.S. Oh yes, priorities are pthread_eintr, and to start working on one of the other 2 tasks. --------------090706090809050607060800 Content-Type: text/plain; name="to-report" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="to-report" IGEub3V0ICAgICAgICAgICB8YmluYXJ5CiBhbGxvYy5jICAgICAgICAgfCAgIDUzICsrKysr KysrKysrKysrKystLS0tLS0tLS0KIHB0aHJlYWRfZWludHIuYyB8ICAxMTcgKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKy0tLS0tLS0tLS0tLS0KIDMgZmls ZXMgY2hhbmdlZCwgMTI0IGluc2VydGlvbnMoKyksIDQ2IGRlbGV0aW9ucygtKQo= --------------090706090809050607060800 Content-Type: text/x-csrc; name="alloc.c" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="alloc.c" #include #include #include #include #include #include #include #include #include //PTRDIFF_MAX, SIZE_MAX #include #include "common/common.h" /* * Copyright (c) 2011 Luka Marčetić * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. */ /** ** \file ** Tests that blocks allocated by various functions do not overlap, that they ** are successfully writable, and that they are freeable by free(). ** In case of posix_memalign, it allso tests that blocks are correctly aligned, ** and in the case of calloc, that allocation of huge values results in failure ** tests: malloc, realloc, calloc, posix_memalign ** depends: sysconf, free, fork,wait, rand, setjmp,longjmp, qsort, fprintf ** memcmp,memset, open,mmap **/ jmp_buf env; struct { size_t page, prog, blocks; } mem; struct block { char *ptr; size_t size; }; struct s_err { unsigned int alloc:1, overlapping:1, notr:1, notw:1, notsame:1, misaligned:1, ov_size_t:1, ov_ptrdiff_t:1, free:1, mallocfree:1, rand:1, limit:1, no; } *err; #define TRY_FREE(PTR) { err->free = 0; free(PTR); err->free = 0; } static int vm_limit(const size_t); static size_t posix_memalign_alignment(size_t); static size_t blocks_alloc(const void *, struct block *, size_t); static size_t blocks_overlapping(struct block *, size_t); static void blocks_sort(struct block *, size_t); static int blocks_sort_compar(const void *, const void *); static int block_misaligned(struct block, size_t); static int blocks_misaligned(struct block *, size_t); static int blocks_notrw(struct block *, size_t); static int calloc_overflows(long long unsigned int); static void bridge_sig_jmp(int); int main() { struct block *b; size_t i, j, nr_blocks; int ret, stat; const void *fun[] = { malloc, realloc, calloc, posix_memalign }; const char *fun_name[] = {"malloc","realloc","calloc","posix_memalign"}; const int fd = open("/dev/zero", O_RDWR); char *s; mem.page = sysconf(_SC_PAGE_SIZE); mem.blocks = 1000; //max. nr. of blocks to be generated mem.prog = mem.blocks*mem.page; //memory reserved for dynamic allocation b = malloc(mem.blocks*sizeof(struct block)); err = mmap(NULL,sizeof(struct s_err),PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); ret = 0; for (i=0; iov_size_t = 1; if(calloc_overflows(PTRDIFF_MAX)) err->ov_ptrdiff_t = 1; } if (!vm_limit(mem.prog)) { err->limit = 1; free(b); return 0; //!!! } if (fun[i] == realloc) { nr_blocks = blocks_alloc(malloc, b, mem.blocks); if (nr_blocks > 5) { //free some for subsequent realloc err->mallocfree = 1; for(j = nr_blocks; nr_blocks >= j-5; --nr_blocks) free(b[nr_blocks-1].ptr); err->mallocfree = 0; nr_blocks = blocks_alloc(fun[i], b, nr_blocks); } } else nr_blocks = blocks_alloc(fun[i], b, mem.blocks); printf("%zu: %zu\n", i, nr_blocks); //--- if (nr_blocks < 10) //an imposed minimum err->alloc = 1; else { if (fun[i]==posix_memalign && blocks_misaligned(b, nr_blocks)) err->misaligned = 1; //universal: if (blocks_overlapping(b, nr_blocks)) err->overlapping = 1; switch (blocks_notrw(b, nr_blocks)) { case 1: err->notw = 1; break; case 2: err->notr = 1; break; case 3: err->notsame = 1; break; } } for(j=0; jfree) { ++ret; fprintf(stderr, "%s test quit unexpectedly!\n", fun_name[i]); if (WIFSIGNALED(stat)) fprintf(stderr, "\tTerminating signal: %d\n", WTERMSIG(stat)); }else { ret += (memcmp(err,(struct s_err []){{.free=0}},sizeof(*err)) != 0); if (err->rand) fprintf(stderr, "An unlikely situation occurred while generating size" " arguments for %s: rand()%%(%zu)+1 on average resulted" " in values no greater than 10%% of the possible maximum" " value. Subsequent errors may result from this.\n", fun_name[i], mem.page*10 ); if (err->limit) fprintf(stderr, "Initial virtual memory allocation failed." "%s tests will not run\n", fun_name[i] ); if (err->alloc) fprintf( stderr, "%s failed to allocate sufficient amount of memory required" " for the test\n", fun_name[i] ); if (err->overlapping) fprintf(stderr,"%s allocated blocks that overlap\n",fun_name[i]); if (err->notr) fprintf(stderr,"%s 'allocated' unreadable memory\n",fun_name[i]); if (err->notw) fprintf(stderr,"%s 'allocated' unwritable memory\n",fun_name[i]); if (err->notsame) fprintf(stderr, "a byte read from %s-allocated memory does not" " match the one previously writen there\n", fun_name[i] ); if (err->misaligned) fprintf( stderr, "%s allocated at least one misaligned block\n", fun_name[i] ); if (err->mallocfree) fprintf( stderr, "%s can't be tested: free() failed to free memory allocated" " by malloc(), which was required for the test to run\n", fun_name[i] ); if (err->free) fprintf( stderr, "free() failed to free memory allocated by %s\n", fun_name[i] ); if (err->ov_size_t) fprintf( stderr, "%s tried to allocate more than SIZE_MAX bytes, which" " means the block's size would not be representable" " by a size_t type\n", fun_name[i] ); if (err->ov_ptrdiff_t) fprintf( stderr, "%s tried to allocate more than PTRDIFF_MAX bytes, which" " would cause an overflow of ptrdiff_t when subtracting" " two pointers from the opposite ends of the block\n", fun_name[i] ); if (err->no) { fprintf(stderr, "%s test set errno=%s\n", fun_name[i], s = e_name(err->no)); free(s); } } } free(b); return ret; } /** ** Allocates all remaining virtual memory, leaving limit both for brk and mmap ** \limit a desired number of free bytes upon returning from the function ** \returns 1 on success, 0 on failure **/ static int vm_limit(const size_t limit) { const int fd = open("/dev/zero", O_RDWR); size_t i,j,last; void *mmapd, *vp; void **brkd, **vpp; //allocate mmap area of size limit: mmapd = mmap(NULL, limit, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); //allocate brk area of size limit: brkd = (vpp = malloc(mem.page)); for(i=0; vpp!=NULL && (i+=mem.page)=limit) { //repeated mmaps of binary-search-determined sizes to fill everything: do { last = 0; for (i=j=SIZE_MAX/2+1; i>0; i/=2) { if ((vp=mmap(NULL, j,PROT_NONE,MAP_PRIVATE,fd,0)) == MAP_FAILED) j -= i/2; else { munmap(vp, (last=j)); j += i/2; } } }while(last && mmap(NULL, last,PROT_NONE,MAP_PRIVATE,fd,0)!=MAP_FAILED); //free that mmap area: munmap(mmapd, limit); //free that brk area: for(i=0; i=limit && !last); } /** ** (re)Allocates blocks of random sizes to fill memory, saves info about them ** NOTE: Function not stand-alone, requires initialized *err and mem structures ** \param fun a pointer to the function to call to (re)allocate the blocks ** \param b a pointer to a struct block array to be filled with blocks info ** \param n for realloc: a number of blocks that are allocated (<=mem.blocks) ** \returns the number of blocks successfully allocated **/ static size_t blocks_alloc(const void *fun, struct block *b, size_t n) { long int rndm; size_t i, size, nr_blocks; char *ptr; int error; nr_blocks = error = 0; for (i=0; !error && irand if (fun == malloc) ptr = malloc(size); else if (fun == calloc) ptr = calloc(1, size); else if (fun == posix_memalign) error=posix_memalign((void**)&ptr,posix_memalign_alignment(i),size); else if (fun == realloc) { if (irand = 1; else err->no = (unsigned int)error; for (i=0; ialloc in main() } return nr_blocks; } /** ** Generates a value to be used as a 2nd argument(alignment) to posix_memalign ** \param seed - required for the calculation (index of the block element) ** \returns a power of two value that is a multiple of sizeof(void *) **/ static size_t posix_memalign_alignment(size_t seed) { do{ ++seed; }while(seed%sizeof(void*) || (seed/sizeof(void*) & (seed/sizeof(void*)-1))); return seed; } /** ** Searches for overlapping blocks ** \param b a pointer to an array of type struct block ** \param n number of elements in the array to search through (will be sorted!) ** \returns an index to b of an element whose .ptr points to an address in the ** preceeding block's space[ptr, ptr+size], or 0 if none such is found **/ static size_t blocks_overlapping(struct block *b, size_t n) { blocks_sort(b, n); for (size_t i=1; i b2.ptr); } /** ** Check blocks for read/write-ability (+consistence) ** \param b a pointer to an array of type struct block ** \param n the number of array elements to check ** \returns ** 0 - if all blocks are readable and writable ** 1 - if at least one of the blocks isn't writable ** 2 - if at least one of the blocks isn't readable ** 3 - if a byte read didn't match a byte previously written **/ static int blocks_notrw(struct block *b, size_t n) { size_t i; struct sigaction oldact, act = {.sa_handler = bridge_sig_jmp, .sa_flags = SA_NODEFER}; int ret = 0; sigaction(SIGSEGV, &act, &oldact); for (i=0; !ret && i #include #include #include #include #include #include #include #include #include #include #include #include #include "common/common.h" #include /* * Copyright (c) 2011 Luka Marčetić * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. */ /** ** \file ** Tests that EINTR isn't returned by interrupted pthread_* functions for which ** this is a specified behavior ** tests: pthread_create, ** depends: open,pipe,close, mmap, sigaction, kill,waitpid,nanosleep, fprintf, ** setjmp, sched_yield **/ #define NANOSLEEP_MAX 100 unsigned char *exit_child; //a barrier for child processes //signal handler that just returns static void handler(int sig) { ++sig; // -Wunused-parameter return; } //waits for *exit_child to be set, then returns static void child_wait(void) { while(!*exit_child) sched_yield(); return; } static void child_wait_vp(void* foo) { child_wait(); ++foo; // -Wunused-parameter return; } /** ** Executes a function whose pointer was passed to it, before exitting ** \param fun a void pointer to the function to execute, or NULL for none **/ static void* thread(void *fun) { if(fun != NULL) { pthread_cleanup_push(child_wait_vp, NULL); } return NULL; } int main() { char *s; pid_t pid; pthread_t tid; pthread_key_t tkey; struct timespec ns = {.tv_nsec=0}; unsigned int i, nr_fun, failed; const int fd = open("/dev/zero", O_RDWR); int sig, ret[2]={0,0}, stat, pfd[2]; const char *function[] = { "pthread_create", "pthread_cancel", "pthread_once", "pthread_setspecific", "pthread_key_delete", "pthread_join", "pthread_atfork", "pthread_sigmask", "pthread_equal", "pthread_setschedprio", "pthread_setconcurrency", "pthread_create", "pthread_setconcurrency", "pthread_detach", "pthread_sigmask", "pthread_setspecific", "pthread_key_create", "pthread_rwlock_unlock", "pthread_kill", }; struct { unsigned int kill:1, wait:1; } err, no_err = {.wait=0}; struct sigaction act = {.sa_handler=handler, .sa_flags=SA_NODEFER}; exit_child = mmap(NULL,1,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); failed = 0; for (i=0; i < (nr_fun=sizeof(function)/sizeof(*function)); ++i) { memset(&err, 0, sizeof(err)); pipe(pfd); *exit_child = 0; if(!(pid = fork())) { sigaction(SIGABRT, &act, NULL); sig = 0; switch (i) { case 1: pthread_create(&tid, NULL, thread, child_wait); break; case 3: case 4: pthread_key_create(&tkey, child_wait_vp); break; } close(pfd[0]); close(pfd[1]); //ready switch (i) { case 0: while(sig != EINTR && !*exit_child) sig = pthread_create(&tid, NULL, thread, NULL); break; case 1: while(sig != EINTR && !*exit_child) sig = pthread_cancel(tid); break; case 2: sig = pthread_once((pthread_once_t []){ PTHREAD_ONCE_INIT }, child_wait); break; case 3: while(sig != EINTR && !*exit_child) sig = pthread_setspecific(tkey, NULL); /*no break;*/ case 4: pthread_key_delete(tkey); break; default: fprintf(stdout, "BUG: test i=%d missing!\n", i); break; } return (sig == EINTR); } if (!pid) { fprintf(stdout, "BUG: child i=%d escaped!\n", i); exit(0); //exit/contain child }else if (pid == -1) { fprintf(stderr, "A call to fork() nr %d/%d yeilded -1 (errno=%s)!\n", i+1, nr_fun, (s = e_name(errno)) ); free(s); close (pfd[0]); close (pfd[1]); failed += 1; }else{ close (pfd[1]); read(pfd[0], NULL, 1); //wait for the child to become ready close (pfd[0]); //Send signals in intervals of microseconds: ns.tv_nsec = NANOSLEEP_MAX; while( (ret[0] = kill(pid, SIGABRT)) == 0 && (ret[1] = waitpid(pid, &stat, WNOHANG)) == 0 && --ns.tv_nsec ) nanosleep(&ns, NULL); *exit_child=1; //let the child loose from its loop (if any) //Process errors: s = e_name(errno); err.kill = (ret[0] != 0); err.wait = (ret[1] != 0 && ret[1] != pid); if (!(!memcmp(&err, &no_err, sizeof(err)))) { ++failed; if (err.kill) fprintf(stderr, "A call to kill() returned %d, errno=%s\n", ret[0], s ); if (err.wait) fprintf(stderr, "A call to waitpid() returned %d, errno=%s\n", ret[1], s ); }else if (WIFEXITED(stat)) { *ret = WEXITSTATUS(stat); //repurpose ret[0] if (*ret == 1) { ++failed; fprintf(stderr, "%s() returned EINTR\n", function[i]); } else if (*ret != 0) fprintf(stdout, "BUG: child nr %d ended with status %d!\n", i, *ret ); }else{ fprintf(stderr, "%s()'s process crashed!\n", function[i]); if (WIFSIGNALED(stat)) fprintf(stderr,"\tTerminating signal: %d\n",WTERMSIG(stat)); } free(s); } } return failed; } --------------090706090809050607060800--