From: Keith M. <no...@so...> - 2016-07-03 19:25:35
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Repository: mingw-org-wsl". The branch, legacy has been updated via 8b688df2fd6c40d8287e8f84024546f8fff9f64a (commit) via fc36f6df4ede289014df0c328a28a2621fea3457 (commit) from 47d501fda777efe7fa8520aeac0e0da347ae20b0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://sf.net/p/mingw/mingw-org-wsl/ci/8b688df2fd6c40d8287e8f84024546f8fff9f64a/ commit 8b688df2fd6c40d8287e8f84024546f8fff9f64a Author: Keith Marshall <kei...@us...> Date: Sun Jul 3 20:23:28 2016 +0100 Rework tsearch and friends; resolve issues [#1512] and [#1576]. diff --git a/mingwrt/ChangeLog b/mingwrt/ChangeLog index 77484d2..da12f15 100644 --- a/mingwrt/ChangeLog +++ b/mingwrt/ChangeLog @@ -1,3 +1,40 @@ +2016-07-03 Keith Marshall <kei...@us...> + + Rework tsearch and friends; resolve issues [#1512] and [#1576]. + + * include/search.h: Assert copyright; tidy layout. + (_SEARCH_H_): Rename this multiple inclusion guard macro... + (_SEARCH_H): ...to conform to this preferred standard convention. + (__search_comparator): New function prototype typedef; it provides a + convenient shorthand notation for argument declarations in functions + which require a comparator function pointer; use it where appropriate. + (tsearch, tfind, tdelete) [__MINGW_ATTRIB_NONNULL]: Apply to arguments + #2 and #3; was previously incorrectly applied to arguments #1 and #3. + (twalk) [__MINGW_ATTRIB_NONNULL]: Apply to both arguments #1 and #2. + [_SEARCH_PRIVATE] (__MINGW_ATTRIB_NONNULL): Suppress its effect, to + ensure that GCC does not optimize away checks within implementation. + (_BEGIN_C_DECLS, _END_C_DECLS): Use these. + + * mingwex/tdelete.c: Tidy layout. + (tdelete): Reimplement it as a thin wrapper around... + (__tdelete): ...this; it encapsulates the original implementation as a + __CRT_ALIAS (inline) function, to simplify void ** --> node_t ** casts. + Remove unnecessary non-null assertions for arguments #1 and #3; prefer + to validate arguments #2 and #3 internally, and simply return NULL if + necessary; hence, do not include <assert.h> + + * mingwex/tfind.c: Tidy layout. + (tfind): Similarly reimplement it as a thin wrapper around... + (__tfind): ...this __CRT_ALIAS (inline) encapsulation of the original. + Add non-null validation for argument #3; do not include <assert.h> + + * mingwex/tsearch.c: Tidy layout. + (tsearch): Once again, reimplement it as a thin wrapper around... + (__tsearch): ...this __CRT_ALIAS variant. Add non-null validation for + argument #3; do not include <assert.h> + + * mingwex/twalk.c: Tidy layout; do not include <assert.h> + 2016-06-28 Keith Marshall <kei...@us...> Rework __try1/__except1 to resolve issue [#1328]. diff --git a/mingwrt/include/search.h b/mingwrt/include/search.h index ec14e95..ce93ca7 100644 --- a/mingwrt/include/search.h +++ b/mingwrt/include/search.h @@ -3,104 +3,143 @@ * * Functions for searching and sorting. * - * This file is part of the Mingw32 package. + * $Id$ * - * Contributors: - * Created by Danny Smith <dan...@us...> + * Written by Danny Smith <dan...@us...> + * Copyright (C) 2003, 2004, 2007, 2016, MinGW.org Project. * - * THIS SOFTWARE IS NOT COPYRIGHTED * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * The above copyright notice, this permission notice, and the following + * disclaimer shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER + * DEALINGS IN THE SOFTWARE. * */ +#ifndef _SEARCH_H +#pragma GCC system_header +#define _SEARCH_H -#ifndef _SEARCH_H_ -#define _SEARCH_H_ - -/* All the headers include this file. */ +/* All MinGW headers must include <_mingw.h> + */ #include <_mingw.h> #ifndef RC_INVOKED -#ifdef __cplusplus -extern "C" { -#endif +_BEGIN_C_DECLS -#ifndef _SIZE_T_DEFINED -typedef unsigned int size_t; -#define _SIZE_T_DEFINED -#endif +/* POSIX specifies that <search.h> must define size_t, as it + * is defined in <sys/types.h>; get it from <stddef.h>, just as + * <sys/types.h> does. + */ +#define __need_size_t +#include <stddef.h> + +/* All search functions require a user-specified comparator + * function, to be passed as an argument; this typedef is a + * convenient shorthand for its generic prototype. + */ +typedef int (*__search_comparator)(const void *, const void *); -/* bsearch and qsort are also declared in stdlib.h */ -_CRTIMP void* __cdecl bsearch (const void*, const void*, size_t, size_t, - int (*)(const void*, const void*)); -_CRTIMP void __cdecl qsort (void*, size_t, size_t, - int (*)(const void*, const void*)); +/* POSIX specifies that bsearch() and qsort() are to be declared in + * <stdlib.h>, and NOT here; they ARE duplicated here, for Microsoft + * compatibility only. + */ +_CRTIMP __cdecl void *bsearch +(const void *, const void *, size_t, size_t, __search_comparator ); -_CRTIMP void* __cdecl _lfind (const void*, const void*, unsigned int*, - unsigned int, int (*)(const void*, const void*)); -_CRTIMP void* __cdecl _lsearch (const void*, void*, unsigned int*, unsigned int, - int (*)(const void*, const void*)); -/* -Documentation for these POSIX definitions and prototypes can be found in -The Open Group Base Specifications Issue 6 -IEEE Std 1003.1, 2004 Edition. -eg: http://www.opengroup.org/onlinepubs/009695399/functions/twalk.html -*/ +_CRTIMP __cdecl void qsort (void *, size_t, size_t, __search_comparator ); +/* This pair of functions are Microsoft specific; see below for their + * POSIX counterparts, (corresponding to Microsoft's old names). + */ +_CRTIMP __cdecl void *_lfind +(const void *, const void *, unsigned int *, unsigned int, __search_comparator ); -typedef struct entry { - char *key; - void *data; +_CRTIMP __cdecl void *_lsearch +(const void *, void *, unsigned int *, unsigned int, __search_comparator ); + +#ifdef _POSIX_C_SOURCE +/* Documentation for the following POSIX definitions and prototypes + * may be found in the Open Group Base Specifications Issue 7, (which + * corresponds to IEEE Std 1003.1, 2008 Edition); see: + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/search.h.html + */ +typedef +struct entry +{ char *key; + void *data; } ENTRY; -typedef enum { - FIND, - ENTER -} ACTION; +typedef +enum { FIND, ENTER } ACTION; -typedef enum { - preorder, - postorder, - endorder, - leaf -} VISIT; +typedef +enum { preorder, postorder, endorder, leaf } VISIT; #ifdef _SEARCH_PRIVATE -typedef struct node { - char *key; - struct node *llink, *rlink; +/* For private use within the respective tree function implementations, + * we define a structured representation of a tree node. + * + * FIXME: this really doesn't belong here! Users should NEVER enable + * this feature test; they should not be given this opportunity. + */ +typedef +struct node +{ const void *key; + struct node *llink, *rlink; } node_t; -#endif -void * __cdecl tdelete (const void * __restrict__, void ** __restrict__, - int (*)(const void *, const void *)) - __MINGW_ATTRIB_NONNULL (1) __MINGW_ATTRIB_NONNULL (3); -void * __cdecl tfind (const void *, void * const *, - int (*)(const void *, const void *)) - __MINGW_ATTRIB_NONNULL (1) __MINGW_ATTRIB_NONNULL (3); -void * __cdecl tsearch (const void *, void **, - int (*)(const void *, const void *)) - __MINGW_ATTRIB_NONNULL (1) __MINGW_ATTRIB_NONNULL (3); -void __cdecl twalk (const void *, void (*)(const void *, VISIT, int)); - -#ifndef _NO_OLDNAMES -_CRTIMP void* __cdecl lfind (const void*, const void*, unsigned int*, - unsigned int, int (*)(const void*, const void*)); -_CRTIMP void* __cdecl lsearch (const void*, void*, unsigned int*, unsigned int, - int (*)(const void*, const void*)); -#endif +/* Suppress non-null argument annotations, when building the tsearch(), + * tfind(), tdelete(), and twalk() implementations, to ensure that GCC + * does not optimize away internal argument validation checks. + */ +#undef __MINGW_ATTRIB_NONNULL +#define __MINGW_ATTRIB_NONNULL(ARG_INDEX) /* NOTHING */ + +#endif /* _SEARCH_PRIVATE */ + +__cdecl void *tdelete +(const void *__restrict__, void **__restrict__, __search_comparator) +__MINGW_ATTRIB_NONNULL(2) __MINGW_ATTRIB_NONNULL(3); + +__cdecl void *tfind (const void *, void *const *, __search_comparator) +__MINGW_ATTRIB_NONNULL(2) __MINGW_ATTRIB_NONNULL(3); + +__cdecl void *tsearch (const void *, void **, __search_comparator) +__MINGW_ATTRIB_NONNULL(2) __MINGW_ATTRIB_NONNULL(3); + +__cdecl void twalk (const void *, void (*)(const void *, VISIT, int)) +__MINGW_ATTRIB_NONNULL(1) __MINGW_ATTRIB_NONNULL(2); + +#endif /* _POSIX_C_SOURCE */ + +#if !defined _NO_OLDNAMES || defined _POSIX_C_SOURCE +/* Declared as deprecated, by Microsoft, but these are the POSIX names + * for the functions which Microsoft now call _lfind() and _lsearch(). + */ +_CRTIMP __cdecl void *lfind +(const void *, const void *, unsigned int *, unsigned int, __search_comparator); -#ifdef __cplusplus -} +_CRTIMP __cdecl void *lsearch +(const void *, void *, unsigned int *, unsigned int, __search_comparator); #endif -#endif /* RC_INVOKED */ +_END_C_DECLS -#endif /* _SEARCH_H_ */ +#endif /* ! RC_INVOKED */ +#endif /* !_SEARCH_H: $RCSfile$: end of file */ diff --git a/mingwrt/mingwex/tdelete.c b/mingwrt/mingwex/tdelete.c index 4de3897..a4d0f92 100644 --- a/mingwrt/mingwex/tdelete.c +++ b/mingwrt/mingwex/tdelete.c @@ -1,65 +1,64 @@ -/* $NetBSD: tdelete.c,v 1.3 1999/09/20 04:39:43 lukem Exp $ */ - -/* - * Tree search generalized from Knuth (6.2.2) Algorithm T just like - * the AT&T man page says. +/* $NetBSD: tdelete.c,v 1.3 1999/09/20 04:39:43 lukem Exp $ * - * The node_t structure is for internal use only, lint doesn't grok it. + * + * Tree search generalized from Knuth (6.2.2) Algorithm T just like + * the AT&T man page says; tdelete based on Knuth's Algorithm D. * * Written by reading the System V Interface Definition, not the code. * * Totally public domain. + * */ - -#include <assert.h> #define _SEARCH_PRIVATE #include <search.h> #include <stdlib.h> -#define _DIAGASSERT assert - - - -/* delete node with given key */ -void * -tdelete(const void *vkey, /* key to be deleted */ - void **vrootp, /* address of the root of tree */ - int (*compar)(const void *, const void *)) +__CRT_ALIAS void *__tdelete +(const void *key, node_t **rootp, int (*compar)(const void *, const void *)) { - node_t **rootp = (node_t **)vrootp; - node_t *p, *q, *r; - int cmp; + /* Delete node with specified "key", from tree referred to by "rootp". + * + * NOTE: node_t is defined as a structured data type, for internal use + * when _SEARCH_PRIVATE is enabled; for public consumption, it becomes + * an alias for "void", (assuming _SEARCH_PRIVATE is NOT enabled). + */ + int cmp; + node_t *p, *q, *r; - _DIAGASSERT(vkey != NULL); - _DIAGASSERT(compar != NULL); + if( (rootp == NULL) || ((p = *rootp) == NULL) || (compar == NULL) ) + return NULL; - if (rootp == NULL || (p = *rootp) == NULL) - return NULL; + while( (cmp = (*compar)(key, (*rootp)->key)) != 0 ) + { + rootp = (cmp < 0) + ? &(p = *rootp)->llink /* follow llink branch */ + : &(p = *rootp)->rlink; /* follow rlink branch */ - while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) { - p = *rootp; - rootp = (cmp < 0) ? - &(*rootp)->llink : /* follow llink branch */ - &(*rootp)->rlink; /* follow rlink branch */ - if (*rootp == NULL) - return NULL; /* key not found */ - } - r = (*rootp)->rlink; /* D1: */ - if ((q = (*rootp)->llink) == NULL) /* Left NULL? */ - q = r; - else if (r != NULL) { /* Right link is NULL? */ - if (r->llink == NULL) { /* D2: Find successor */ - r->llink = q; - q = r; - } else { /* D3: Find NULL link */ - for (q = r->llink; q->llink != NULL; q = r->llink) - r = q; - r->llink = q->rlink; - q->llink = (*rootp)->llink; - q->rlink = (*rootp)->rlink; - } - } - free(*rootp); /* D4: Free node */ - *rootp = q; /* link parent to new node */ - return p; + if (*rootp == NULL) + return NULL; /* key not found */ + } + r = (*rootp)->rlink; /* D1: */ + if( (q = (*rootp)->llink) == NULL ) /* Left NULL? */ + q = r; + else if( r != NULL ) /* Right link is NULL? */ + { if( r->llink == NULL ) /* D2: Find successor */ + { r->llink = q; + q = r; + } + else /* D3: Find NULL link */ + { + for( q = r->llink; q->llink != NULL; q = r->llink ) + r = q; + r->llink = q->rlink; + q->llink = (*rootp)->llink; + q->rlink = (*rootp)->rlink; + } + } + free(*rootp); /* D4: Free node */ + *rootp = q; /* link parent to new node */ + return p; } + +void *tdelete +(const void *key, void **rootp, int (*compar)(const void *, const void *)) +{ return __tdelete (key, (node_t **)(rootp), compar); } diff --git a/mingwrt/mingwex/tfind.c b/mingwrt/mingwex/tfind.c index e8ffe65..fa33d86 100644 --- a/mingwrt/mingwex/tfind.c +++ b/mingwrt/mingwex/tfind.c @@ -1,41 +1,45 @@ -/* $NetBSD: tfind.c,v 1.3.18.2 2005/03/23 11:12:21 tron Exp $ */ - -/* +/* $NetBSD: tfind.c,v 1.3.18.2 2005/03/23 11:12:21 tron Exp $ + * + * * Tree search generalized from Knuth (6.2.2) Algorithm T just like * the AT&T man page says. * - * The node_t structure is for internal use only, lint doesn't grok it. - * * Written by reading the System V Interface Definition, not the code. * * Totally public domain. + * */ - -#include <assert.h> #define _SEARCH_PRIVATE #include <stdlib.h> #include <search.h> - -/* find a node, or return 0 */ -void * -tfind(const void *vkey, - void * const *vrootp, - int (*compar) (const void *, const void *)) +__CRT_ALIAS void *__tfind +(const void *key, node_t *const *rootp, int (*compar)(const void *, const void *)) { - node_t * const *rootp = (node_t * const*)vrootp; + /* Find node with specified "key", within tree referred to by "rootp"; + * return NULL if not found, (or if either "rootp" or "compar" is not + * a valid pointer). + * + * NOTE: node_t is defined as a structured data type, for internal use + * when _SEARCH_PRIVATE is enabled; for public consumption, it becomes + * an alias for "void", (assuming _SEARCH_PRIVATE is NOT enabled). + */ + if( (rootp == NULL) || (compar == NULL) ) + return NULL; - if (rootp == NULL) - return NULL; + while (*rootp != NULL) /* Knuth's T1: */ + { + int cmp; /* T2: */ + if( (cmp = (*compar)(key, (*rootp)->key)) == 0 ) + return *rootp; /* key found */ - while (*rootp != NULL) { /* T1: */ - int r; - - if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */ - return *rootp; /* key found */ - rootp = (r < 0) ? - &(*rootp)->llink : /* T3: follow left branch */ - &(*rootp)->rlink; /* T4: follow right branch */ - } - return NULL; + rootp = (cmp < 0) + ? &(*rootp)->llink /* T3: follow left branch */ + : &(*rootp)->rlink; /* T4: follow right branch */ + } + return NULL; /* key not found */ } + +void *tfind +(const void *key, void *const *rootp, int (*compar)(const void *, const void *)) +{ return __tfind (key, (node_t *const *)(rootp), compar); } diff --git a/mingwrt/mingwex/tsearch.c b/mingwrt/mingwex/tsearch.c index a0aa0eb..9cbba49 100644 --- a/mingwrt/mingwex/tsearch.c +++ b/mingwrt/mingwex/tsearch.c @@ -1,51 +1,57 @@ -/* $NetBSD: tsearch.c,v 1.4 1999/09/20 04:39:43 lukem Exp $ */ - -/* +/* $NetBSD: tsearch.c,v 1.4 1999/09/20 04:39:43 lukem Exp $ + * + * * Tree search generalized from Knuth (6.2.2) Algorithm T just like * the AT&T man page says. * - * The node_t structure is for internal use only, lint doesn't grok it. - * * Written by reading the System V Interface Definition, not the code. * * Totally public domain. + * */ - -#include <assert.h> #define _SEARCH_PRIVATE #include <search.h> #include <stdlib.h> - -/* find or insert datum into search tree */ -void * -tsearch(const void * __restrict__ vkey, /* key to be located */ - void ** __restrict__ vrootp, /* address of tree root */ - int (*compar) (const void *, const void *)) +__CRT_ALIAS void *__tsearch +(const void *key, node_t **rootp, int (*compar)(const void *, const void *)) { - node_t *q; - node_t **rootp = (node_t **)vrootp; - - if (rootp == NULL) - return NULL; - - while (*rootp != NULL) { /* Knuth's T1: */ - int r; - - if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */ - return *rootp; /* we found it! */ - - rootp = (r < 0) ? - &(*rootp)->llink : /* T3: follow left branch */ - &(*rootp)->rlink; /* T4: follow right branch */ - } - - q = malloc(sizeof(node_t)); /* T5: key not found */ - if (q != 0) { /* make new node */ - *rootp = q; /* link new node to old */ - /* LINTED const castaway ok */ - q->key = (void *)vkey; /* initialize new node */ - q->llink = q->rlink = NULL; - } - return q; + /* Find node identified by "key", within the tree referred to by "rootp", + * or insert such datum node, if not already present. + * + * NOTE: node_t is defined as a structured data type, for internal use + * when _SEARCH_PRIVATE is enabled; for public consumption, it becomes + * an alias for "void", (assuming _SEARCH_PRIVATE is NOT enabled). + */ + node_t *q; + + /* Cannot search from an invalid tree reference pointer, or without a + * valid comparator function reference. + */ + if( (rootp == NULL) || (compar == NULL) ) + return NULL; + + while( *rootp != NULL ) /* Knuth's T1: */ + { + int cmp; /* T2: */ + if( (cmp = (*compar)(key, (*rootp)->key)) == 0 ) + return *rootp; /* we found it! */ + + rootp = (cmp < 0) + ? &(*rootp)->llink /* T3: follow left branch */ + : &(*rootp)->rlink; /* T4: follow right branch */ + } + + q = malloc( sizeof(node_t) ); /* T5: key not found */ + if( q != NULL ) /* make new node */ + { + *rootp = q; /* link new node to old */ + q->key = key; /* initialize new node */ + q->llink = q->rlink = NULL; + } + return q; } + +void *tsearch +(const void *key, void **rootp, int (*compar)(const void *, const void *)) +{ return __tsearch (key, (node_t **)(rootp), compar); } diff --git a/mingwrt/mingwex/twalk.c b/mingwrt/mingwex/twalk.c index aa7909c..0c681e5 100644 --- a/mingwrt/mingwex/twalk.c +++ b/mingwrt/mingwex/twalk.c @@ -1,48 +1,48 @@ -/* $NetBSD: twalk.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ */ - -/* +/* $NetBSD: twalk.c,v 1.2 1999/09/16 11:45:37 lukem Exp $ + * + * * Tree search generalized from Knuth (6.2.2) Algorithm T just like * the AT&T man page says. * - * The node_t structure is for internal use only, lint doesn't grok it. - * * Written by reading the System V Interface Definition, not the code. * * Totally public domain. + * */ - -#include <assert.h> #define _SEARCH_PRIVATE #include <search.h> #include <stdlib.h> -static void trecurse (const node_t *, void (*action)(const void *, VISIT, int), - int level) __MINGW_ATTRIB_NONNULL (1) - __MINGW_ATTRIB_NONNULL (2); -/* Walk the nodes of a tree */ -static void -trecurse( const node_t *root, /* Root of the tree to be walked */ - void (*action)(const void *, VISIT, int), - int level) +static __MINGW_ATTRIB_NONNULL(1) __MINGW_ATTRIB_NONNULL(2) +void trecurse (const node_t *, void (*)(const void *, VISIT, int), int); + +static void trecurse +( const node_t *root, void (*action)(const void *, VISIT, int), int level) { - if (root->llink == NULL && root->rlink == NULL) - (*action)(root, leaf, level); - else { - (*action)(root, preorder, level); - if (root->llink != NULL) - trecurse(root->llink, action, level + 1); - (*action)(root, postorder, level); - if (root->rlink != NULL) - trecurse(root->rlink, action, level + 1); - (*action)(root, endorder, level); - } + /* Recursively walk the nodes of a tree, performing the specified + * action as each node is traversed, and as appropriate for each + * phase of traversal. + */ + if( (root->llink == NULL) && (root->rlink == NULL) ) + (*action) (root, leaf, level); + + else + { (*action) (root, preorder, level); + if( root->llink != NULL ) + trecurse (root->llink, action, level + 1); + (*action) (root, postorder, level); + if( root->rlink != NULL) + trecurse (root->rlink, action, level + 1); + (*action) (root, endorder, level); + } } -/* Walk the nodes of a tree */ -void -twalk( const void *vroot, /* Root of the tree to be walked */ - void (*action) (const void *, VISIT, int)) +void twalk (const void *root, void (*action)(const void *, VISIT, int)) { - if (vroot != NULL && action != NULL) - trecurse(vroot, action, 0); + /* Walk the nodes of a tree, delegating to the local recursive + * helper function, to invoke the specified action on each node + * in turn, as appropriate in each phase of traversal. + */ + if( (root != NULL) && (action != NULL) ) + trecurse (root, action, 0); } https://sf.net/p/mingw/mingw-org-wsl/ci/fc36f6df4ede289014df0c328a28a2621fea3457/ commit fc36f6df4ede289014df0c328a28a2621fea3457 Author: Keith Marshall <kei...@us...> Date: Tue Jun 28 14:50:38 2016 +0100 Rework __try1/__except1 to resolve issue [#1328]. diff --git a/mingwrt/ChangeLog b/mingwrt/ChangeLog index 7e2001b..77484d2 100644 --- a/mingwrt/ChangeLog +++ b/mingwrt/ChangeLog @@ -1,3 +1,22 @@ +2016-06-28 Keith Marshall <kei...@us...> + + Rework __try1/__except1 to resolve issue [#1328]. + + * include/excpt.h: Assert copyright; tidy layout. + (_EXCPT_H_): Multiple inclusion guard macro renamed to... + (_EXCPT_H): ...this; update all references as appropriate. + (_BEGIN_C_DECLS, _END_C_DECLS): Use these. + (__typecast_alloca): New macro; define it, casting return type of... + (__builtin_alloca): ...this to a specified data type; use it in... + (__try1_setup, __except1_teardown): ...these new macros; define them + as parameterized templates, providing both -masm-att and -masm-intel + syntax implementations, with host specific word size and register + assignment parameter substitutions; use them to redefine... + (__try1, __except1): ...each of these, using __builtin_alloca to avoid + direct stack pushes when registering exception handlers; assign the + template parameters as appropriate to support implementation for... + [_WIN64, _WIN32]: ...either of these, as the host requires. + 2016-06-17 Keith Marshall <kei...@us...> Merge Cygwin CVS updates to legacy branch. diff --git a/mingwrt/include/excpt.h b/mingwrt/include/excpt.h index 7433dd0..df03176 100644 --- a/mingwrt/include/excpt.h +++ b/mingwrt/include/excpt.h @@ -1,115 +1,186 @@ /* * excpt.h - * This file has no copyright assigned and is placed in the Public Domain. - * This file is a part of the mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within the package. * - * Support for operating system level structured exception handling. + * Experimental support for operating system level structured handling + * of exceptions. * - * NOTE: This is very preliminary stuff. I am also pretty sure it is - * completely Intel specific. + * $Id$ + * + * Written by Colin Peters <co...@bi...> + * Revised by Keith Marshall <kei...@us...> + * Copyright (C) 1997, 1999, 2001-2002, 2004, 2007, 2012, 2016, + * MinGW.org Project. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice, this permission notice, and the following + * disclaimer shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER + * DEALINGS IN THE SOFTWARE. * */ +#ifndef _EXCPT_H +#pragma GCC system_header +#define _EXCPT_H + +/* FIXME: this utility macro, to allocate stack space for any aggregate + * data type, with an explicit type cast of a pointer to that data type, + * deserves a place in a more universally accessible header file. The + * type cast is not strictly necessary for C, (but is permitted); it is + * essential for C++. + */ +#define __typecast_alloca(type) (type *)(__builtin_alloca( sizeof(type) )) -#ifndef _EXCPT_H_ -#define _EXCPT_H_ - -/* All the headers include this file. */ +/* All MinGW CRT headers are required to include <_mingw.h> + */ #include <_mingw.h> +/* Exception handler functions require definitions of _CONTEXT, and + * _EXCEPTION_RECORD structures, which are provided in <windef.h> + */ #include <windef.h> -/* - * NOTE: The constants structs and typedefs below should be defined in the - * Win32 API headers. +#ifndef _EXCPT_W32API_H +/* FIXME: These constants, structs, and typedefs should be defined + * in the Win32 API headers; (we need to establish where -- perhaps + * this header itself should be redesignated as a W32API header). */ -#define EH_NONCONTINUABLE 0x01 -#define EH_UNWINDING 0x02 -#define EH_EXIT_UNWIND 0x04 -#define EH_STACK_INVALID 0x08 -#define EH_NESTED_CALL 0x10 - -#ifndef RC_INVOKED - -typedef enum { - ExceptionContinueExecution, - ExceptionContinueSearch, - ExceptionNestedException, - ExceptionCollidedUnwind +#define EH_NONCONTINUABLE 0x01 +#define EH_UNWINDING 0x02 +#define EH_EXIT_UNWIND 0x04 +#define EH_STACK_INVALID 0x08 +#define EH_NESTED_CALL 0x10 + +#ifndef RC_INVOKED + +typedef enum +{ ExceptionContinueExecution, + ExceptionContinueSearch, + ExceptionNestedException, + ExceptionCollidedUnwind } EXCEPTION_DISPOSITION; +#endif /* ! RC_INVOKED */ +#endif /* !_EXCPT_W2API_H */ -/* - * End of stuff that should be in the Win32 API files. - */ +#ifndef RC_INVOKED +_BEGIN_C_DECLS -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The type of function that is expected as an exception handler to be - * installed with __try1. +/* The type of function that is expected as an exception handler, + * to be installed by the __try1(__handler) primitive. */ typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER) - (struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); +(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *); -/* - * This is not entirely necessary, but it is the structure installed by - * the __try1 primitive below. - */ typedef struct _EXCEPTION_REGISTRATION -{ - struct _EXCEPTION_REGISTRATION* prev; - PEXCEPTION_HANDLER handler; +{ /* Maps the structure of the exception handler registration + * block, as installed by the __try1(__handler) primitive. + */ + struct _EXCEPTION_REGISTRATION *prev; + PEXCEPTION_HANDLER handler; } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; +/* Aliases which may be preferred, when referring to the + * EXCEPTION_REGISTRATION structure. + */ typedef EXCEPTION_REGISTRATION EXCEPTION_REGISTRATION_RECORD; typedef PEXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION_RECORD; -/* - * A macro which installs the supplied exception handler. - * Push the pointer to the new handler onto the stack, - * then push the pointer to the old registration structure (at fs:0) - * onto the stack, then put a pointer to the new registration - * structure (i.e. the current stack pointer) at fs:0. +/* Deployment of exception handlers is facilitated by the pair + * of macros, __try1(_handler) and __except1. + * + * CAUTION: __try1(__handler) and __except1 must be deployed as + * a complementary pair, within the scope of the stack frame of + * a single function, with __try1(__handler) preceding the use + * of __except1. Failure to invoke __except1 before release of + * any stack frame, in which __try1(__handler) has been invoked, + * will invalidate the EXCEPTION_REGISTRATION_RECORD, which has + * been installed by __try1(_handler), at the head of the active + * exception handler chain; this will cause undefined behaviour, + * which is sure to go badly. + * + * To accommodate implementation differences between _WIN32 and + * _WIN64 hosts, the actual implementations of __try1(__handler) + * and __except1 are expressed in terms of a pair of lower level + * internal macros, namely: + * + * Macro: __try1_setup(__handler,__wsize,__ts) + * + * Helper for implementation of macro __try1(__handler); allocate + * a block of memory, within the stack frame of the calling function, + * which is then initialized as an EXCEPTION_REGISTRATION_RECORD, and + * linked to the head of the installed exception handler chain. + * + * Inputs: + * __handler pointer to an EXCEPTION_HANDLER function. + * __wsize the Intel host word size pointer description. + * __ts thread information segment register name. */ -#ifdef _WIN64 -# define __try1(pHandler) \ - __asm__ __volatile__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : \ - "g" (pHandler)); -#else -# define __try1(pHandler) \ - __asm__ __volatile__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : \ - "g" (pHandler)); -#endif +#define __try1_setup(__handler,__wsize,__ts) \ +{ EXCEPTION_REGISTRATION *__hook; \ + __hook = __typecast_alloca( EXCEPTION_REGISTRATION ); \ + __hook->handler = __handler; \ + __asm__ __volatile__ \ + ( "mov{%z0}\t{%%|%0, "__wsize" }"__ts":{|[}0x0{, %0|]}\n\t" \ + "mov{%z1}\t{%1, %%|"__wsize" }"__ts":{|[}0x0{|], %1}" \ + :"=r"(__hook->prev):"r"(__hook):"memory" \ + ); \ +} -/* - * A macro which (despite its name) *removes* an installed - * exception handler. Should be used only in conjunction with the above - * install routine __try1. - * Move the pointer to the old reg. struct (at the current stack - * position) to fs:0, replacing the pointer we installed above, - * then add 8 to the stack pointer to get rid of the space we - * used when we pushed on our new reg. struct above. Notice that - * the stack must be in the exact state at this point that it was - * after we did __try1 or this will smash things. +/* Macro: __except1_teardown(__wsize,__ts) + * + * Helper which provides the implementation for the __except1 + * complement to __try1(__handler) macro; it unlinks the first + * EXCEPTION_REGISTRATION_RECORD from the head of the exception + * handler chain. Arguments are as described for those of the + * same name, in the __try1_setup macro argument list. + */ +#define __except1_teardown(__wsize,__ts) \ +{ register EXCEPTION_REGISTRATION *__hook; \ + __asm__ __volatile__ \ + ( "mov{%z0}\t{%%|%0, "__wsize" }"__ts":{|[}0x0{, %0|]}\n\t" \ + "mov{%z0}\t{(}%0{)}, {|"__wsize" [}%0{|]}\n\t" \ + "mov{%z0}\t{%0, %%|"__wsize" }"__ts":{|[}0x0{|], %0}" \ + :"+r"(__hook)::"memory" \ + ); \ +} + +/* Specialization of the above primitives, creating __try1(__handler), + * and its complementary __except1 implementation, with the appropriate + * assignments of word size and TIB segment register, for each of... */ #ifdef _WIN64 -# define __except1 \ - __asm__ __volatile__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq \ - $16,%%rsp;" : : : "%rax"); -#else -# define __except1 \ - __asm__ __volatile__ ("movl (%%esp),%%eax;movl %%eax,%%fs:0;addl \ - $8,%%esp;" : : : "%eax"); -#endif +/* ...64-bit windows, for which the word size for representation of + * pointers, in Intel-syntax code, is "QWORD PTR", and the gs segment + * is used for access to the thread information block... + */ +# define __try1(__handler) __try1_setup(__handler,"QWORD PTR","gs") +# define __except1 __except1_teardown("QWORD PTR","gs") -#ifdef __cplusplus -} +#else /* _WIN32 */ +/* ...while in 32-bit windows, the corresponding pointer word size + * is "DWORD PTR", and the the thread information block is located + * in the fs segment. + */ +# define __try1(__handler) __try1_setup(__handler,"DWORD PTR","fs") +# define __except1 __except1_teardown("DWORD PTR","fs") #endif -#endif /* Not RC_INVOKED */ +_END_C_DECLS -#endif /* _EXCPT_H_ not defined */ +#endif /* ! RC_INVOKED */ +#endif /* !_EXCPT_H: $RCSfile$: end of file */ ----------------------------------------------------------------------- Summary of changes: mingwrt/ChangeLog | 56 +++++++++++ mingwrt/include/excpt.h | 233 +++++++++++++++++++++++++++++---------------- mingwrt/include/search.h | 187 ++++++++++++++++++++++-------------- mingwrt/mingwex/tdelete.c | 99 ++++++++++---------- mingwrt/mingwex/tfind.c | 56 ++++++----- mingwrt/mingwex/tsearch.c | 82 +++++++++-------- mingwrt/mingwex/twalk.c | 64 ++++++------ 7 files changed, 476 insertions(+), 301 deletions(-) hooks/post-receive -- Repository: mingw-org-wsl |