Deutsch English Français Italiano |
<86a5jafyw2.fsf@linuxsc.com> View for Bookmarking (what is this?) Look up another Usenet article |
Path: ...!weretis.net!feeder8.news.weretis.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch <tr.17687@z991.linuxsc.com> Newsgroups: comp.lang.c Subject: Re: Fixing a sample from K&R book using cake static analyser Date: Mon, 24 Jun 2024 02:55:41 -0700 Organization: A noiseless patient Spider Lines: 152 Message-ID: <86a5jafyw2.fsf@linuxsc.com> References: <v53sl1$35qt7$1@dont-email.me> <v558hv$3dskb$1@dont-email.me> <20240623034624.135@kylheku.com> <87wmmfq4if.fsf@bsb.me.uk> <20240624012527.8bbe16b96f5bfca10feadb5c@gmail.moc> <87zfrbnsvv.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Mon, 24 Jun 2024 11:55:42 +0200 (CEST) Injection-Info: dont-email.me; posting-host="b3b1304951eae8dc1e53ef86c96f1e35"; logging-data="910961"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+LS2mZqRrrurHefIzqdyFOU4eDDsHtw9I=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:W9TUzbeeRDTO//WolEJrc7jw/zE= sha1:u9vhsCBCaVosIGvlMXQHAUysmaI= Bytes: 5966 Ben Bacarisse <ben@bsb.me.uk> writes: > Anton Shepelev <anton.txt@gmail.moc> writes: > >> Ben Bacarisse: >> >>> I don't get why the goto crowd want to complicate it so >>> much. >> >> Will someone post a goto-less that fixes what I perceive as >> bugs in the original: >> >> a. the failure to free() a newly allocated nlist in case >> of a later error, >> >> b. the failure to free() a newly allocated np->name in >> case of a later error, >> >> c. the failure to keep np->defn unchaged if the >> allocation of the new defn value failed. >> >> And my perception be wrong, let us first establish the >> actual bug(s). > > With the usual trepidation that this is untested (though I did compile > it), I'd write something like: > > struct nlist *install(const char *name, const char *defn) > { > struct nlist *node = lookup(name); > if (node) { > char *new_defn = strdup(defn); > if (new_defn) { > free(node->defn); > node->defn = new_defn; > return node; > } > else return NULL; > } > else { > struct nlist *new_node = malloc(sizeof *new_node); > char *new_name = strdup(name), *new_defn = strdup(defn); > if (new_node && new_name && new_defn) { > unsigned hashval = hash(name); > new_node->name = new_name; > new_node->defn = new_defn; > new_node->next = hashtab[hashval]; > return hashtab[hashval] = new_node; > } > else { > free(new_defn); > free(new_name); > free(new_node); > return NULL; > } > } > } > > We have four cases: > > node with the name found > new definition allocated > new definition not allocated > node with the name not found > new node, name and definition all allocated > not all of new node, name and definition allocated. > > We can very simply reason about all of these situations. For example, > when is storage freed? Just before returning NULL because the name was > not in the table and one or more of the required allocations failed. > Are the calls to free legal? Yes, all are initialised with the return > from malloc-like functions and are never assigned. Pretty much anything > that you want to check can be checked by simple reasoning. In > particular, your (a), (b) and (c) can be checked quite easily. > > (I've written out all the else clauses because I want to show the "fully > structured" version. I admit that I might sometimes save three lines by > putting "return NULL;" at the very end and allowing two cases to fall > through.) After seeing your response I decided to post my own effort. Some names have been changed (and some const qualifiers added) but the logical composition of the struct is the same. The main entry point is define_or_redefine_key(). Disclaimer: compiled, not tested. #include <stdlib.h> typedef const char *String; typedef struct nlist *Association; struct nlist { Association next; String key; String value; }; extern Association lookup( String ); extern unsigned hash( String ); extern Association hashtable[]; extern char *strdup( String ); static Association find_entry( String ); static Association installed_new_entry( String ); static Association install_new( Association ); static Association new_uninstalled_association( String ); static void cfree( const void * ); Association define_or_redefine_key( String key_string, String value_string ){ String value = strdup( value_string ); Association r = value ? find_entry( key_string ) : 0; return r ? cfree( r->value ), r->value = value, r : (cfree( value ), r); } Association find_entry( String key_string ){ Association entry = lookup( key_string ); return entry ? entry : installed_new_entry( key_string ); } Association installed_new_entry( String key_string ){ return install_new( new_uninstalled_association( key_string ) ); } Association install_new( Association r ){ Association *list = r ? &hashtable[ hash( r->key ) ] : 0; return r ? r->next = *list, *list = r : r; } Association new_uninstalled_association( String key_string ){ String key = strdup( key_string ); Association r = key ? malloc( sizeof *r ) : 0; return r ? r->next = 0, r->key = key, r->value = 0, r : (cfree( key ), r); } void cfree( const void *p ){ union { const void *pcv; void *pv; } it = (it.pcv = p, it); free( it.pv ); }