Re: safestr alpha (Safe C String Library)

From: kevindat_private
Date: Tue Feb 11 2003 - 18:54:57 PST

  • Next message: John Viega: "Re: safestr alpha (Safe C String Library)"

    On Tue, Feb 11, 2003 at 11:01:25AM -0800, Kim Reece wrote:
    > 
    > Perhaps an acknowledgement system of some type?  ie. having parameters for
    > "die" or "don't die" or "die if they don't check it", then a function the
    > user of the library would call to say "return code checked, acknowledge so
    > I can use the results".  Basically a taint system.
    
    The Unix signal()/sigaction() mechanism provides some inspiration here,
    where you have these possibilities with SIG_DFL, SIG_IGN and a handler.
    A callback function for string function errors achieves much of the desired result.
    
    A caveat - I'd better admit that I haven't looked at the current proposed library,
    so I don't even know its API.  I've just been following the discussion as it's happened here.
    Please apply grains of salt accordingly.
    
    Calls to the various string routines share a lot of common error conditions,
    so much of that can be handled by the callback function,
    particularly those parts which are outside the scope of the string manipulation.
    There would also be benefit of removing a lot of the noise from the code -
    the error-return checking that Dana mentioned - so it becomes more readable.
    
    The callback function should probably take a few parameters:
    - an error code
    - perhaps a reference to the string function and the arguments given to it
    - a user supplied argument.  My usual practice is a (void *).
    Its return value, seen by the string function, would indicate such things as
    whether to retry the operation, or fail and pass the error back to the original call.
    
    The user-supplied argument is intentionally versatile, being weakly typed.
    It could be as simple as a flag to indicate a global error condition,
    or as complex as a structure pointer holding state information.
    While this weak typing is normally seen as lower-level programming security,
    it would be near impossible in many languages to retain the versatility otherwise.
    An alternative could be to have the user define the type of the parameter
    but this only allows that single type within its scope
    and it would also have to be defined before the declaration of the string functions
    (ie before the include file), which separates it from where it's used.
    
    The level of security can the be set by the user.
    A simplistic approach would be to call the function and let it terminate
    the process on any error:
    
    	(void) somestringfunc(str, STRING_DEFAULT_ERROR, NULL);
    
    The semantics of STRING_DEFAULT_ERROR might include some generic operation before exit(),
    perhaps indicated by the user argument, such as printing an error.
    Anything more substantial (and maybe even this) is better managed by a handler.
    
    The typical use would be where you have error handling managed in a fairly general way:
    
    string_error_result_t
    handler(int error, string_function_t func, void *arg)
    {
    	string_error_result_t	result;
    
    	/* code dependent on the arguments and required error processing */
    	return result;
    }
    
    	.
    	.
    	arg = ...;
    	(void) somestringfunc(str1, handler, (void *) &arg);
    	if (anotherstringfunc(str1, str2, handler, (void *) &arg) == STRING_ERROR_NONE)
    		(void) somestringfunc(str2, handler, NULL);
    	.
    	.
    
    Finally, STRING_FAIL_ERROR could be used when the caller wants to do all checking
    (or do no checking at all, when it is known there will be no errors).
    A NULL callback function would do the same thing.
    This would normally be the only case where the function call starts to disappear
    under the noise as it does with the current string functions:
    
    	switch (somestringfunc(str, STRING_FAIL_ERROR, NULL))
    	{
    	case STRING_ERROR_NONE:
    		break;
    
    	case STRING_ERROR_this:
    	case STRING_ERROR_that:
    		/* whatever */
    
    	default:
    		/* unknown or unmanaged error */
    	}
    
    	(void) anotherstringfunc(str1, str2, NULL, NULL);
    
    
    Whilst all the above examples are in C, there is nothing particularly fundamental
    that requires this.  For languages that implement exception handling natively,
    it would be worth investigating that whole approach.
    
    It's tempting to implement the existing string functions with macros
    because those that add to strings all "succeed" anyway:
    
    #define		strcpy(d, s)	((void) safestrcpy(d, s, STRING_FAIL_ERROR, NULL), d)
    
    but be aware of the usual pitfalls:
    
    	strcpy(*pps++, something);	/* char **pps; */
    	strcpy(func(), something);	/* where func() has side effects */
    
    Kevin
    



    This archive was generated by hypermail 2b30 : Wed Feb 12 2003 - 09:19:03 PST