G:/ScriptBasic/source/hndlptr.c

Go to the documentation of this file.
00001 /*
00002 FILE: hndlptr.c
00003 HEADER: hndlptr.h
00004 
00005 TO_HEADER:
00006 
00007 */
00008 
00009 /*POD
00010 @c Handling handle pointer conversion
00011 
00012 The functions in this file help the various ScriptBasic extension
00013 modules to avoid crashing the system even if the BASIC programs use 
00014 the values passed by the module in a bad way. 
00015 
00016 For example a database handling module opens a database and allocates 
00017 a structure describing the connection. The usual way to identify the structure 
00018 is to return a BASIC string variable to the BASIC code that byte by byte holds 
00019 the value of the pointer. This works on any machine having 32bit or 64bit pointers 
00020 because strings can be arbitrary length in ScriptBasic. 
00021 
00022 When another external module function need access to the structure it needs a 
00023 pointer to it. This is easily done by passing the string variable to the module. 
00024 The module converts the string variable back byte by byte to a pointer and all is fine.
00025 
00026 Is it?
00027 
00028 The issue is that the BASIC program may alter the pointer and pass a string containg garbage
00029 back to the module. The module has no way to check the correctness tries to use it
00030 and crashes the whole interpreter. (Even the other interpreters running in the same process
00031 in different threads.)
00032 
00033 =bold
00034 ScriptBasic external modules should never ever pass pointers in strings back to the BASIC code.
00035 =nobold
00036 
00037 (Even that some of the modules written by the ScriptBasic developers followed this method formerly.)
00038 
00039 The better solution is to store these module pointers in arrays and pass the index of the pointer
00040 in the array to the basic application. This way the BASIC program will get INTEGER values instead
00041 of STRING and will not be able to alter the pointer value and crash the program.
00042 
00043 To store the pointer and get the index (we call it a handle) these functions can be used.
00044 
00045 Whenever a pointer needs a handle the module has to call T<GetHandle>. This function stores the
00046 pointer and returns the handle to it. When the BASIC program passes the handle back to the module
00047 and the module needs the pointer associated with the handle it has to call T<GetPointer>.
00048 
00049 When a pointer is not needed anymore the handle should be freed calling T<FreeHandle>.
00050 
00051 This implementation uses arrays to hold the pointers. The handles are the indexes to the array.
00052 The index 0 is never used. Handle value zero is returned as an invalid handle value whenever
00053 some error occures, like out of memory condition.
00054 
00055 CUT*/
00056 #include <stdlib.h>
00057 
00058 #include "myalloc.h"
00059 #include "thread.h"
00060 
00061 #define ARRAY_INCREMENT 100
00062 
00063 typedef struct _HandleArray {
00064   unsigned long n;
00065   MUTEX mx;
00066   void **pointer;
00067   }HandleArray,*pHandleArray;
00068 
00069 /*POD
00070 =H handle_GetHandle
00071 @c GetHandle
00072 
00073 Having a pointer allocate a handle. This function stores the
00074 pointer and returns the handle.
00075 
00076 The handle is a small positive integer.
00077 
00078 If any error is happened (aka out of memory) zero is returned.
00079 /*FUNCTION*/
00080 unsigned long handle_GetHandle(void **pHandle,
00081                                void *pMEM,
00082                                void *pointer
00083   ){
00084 /*noverbatim
00085 
00086 =itemize
00087 =item The first argument T<pHandle> is a pointer to the handle array.
00088 =item The second argument T<pMEM> is the memory segment that is to be used to allocate
00089 memory.
00090 =item The last argument T<pointer> is the pointer to store.
00091 =noitemize
00092 
00093 Note that T<NULL> pointer can not be stored in the array.
00094 
00095 The pointer to the handle array T<pHandle> should be initialized to NULL
00096 before the first call to T<handle_GetHandle>. For example:
00097 =verbatim
00098    void *Handle = NULL;
00099      ....
00100    if( !handle_GetHandle(&Handle,pMEM,pointer) )return ERROR_CODE;
00101 =noverbatim
00102 CUT*/
00103   pHandleArray q;
00104   unsigned long i;
00105   void **z;
00106 
00107   if( pointer == NULL )return 0;
00108   if( *pHandle == NULL ){
00109     *pHandle = alloc_Alloc(sizeof(HandleArray),pMEM);
00110     if( *pHandle == NULL )return 0;
00111     q = *pHandle;
00112     thread_InitMutex( &(q->mx) );
00113     q->n = 0;
00114     q->pointer = NULL;
00115     }
00116   q = (pHandleArray)*pHandle;
00117   thread_LockMutex( &(q->mx) );
00118   /* search for a free handle */
00119   for( i=1 ; i < q->n ; i++ )
00120     if( q->pointer[i] == NULL )break;
00121   /* we need to allocate more space */
00122   if( i >= q->n ){
00123     z = alloc_Alloc((q->n+ARRAY_INCREMENT)*sizeof(void*),pMEM);
00124     if( z == NULL )return 0;
00125     memset(z,0,(q->n+ARRAY_INCREMENT)*sizeof(void*));
00126     memcpy(z,q->pointer,q->n*sizeof(void *));
00127     alloc_Free(q->pointer,pMEM);
00128     q->pointer = z;
00129     q->n += ARRAY_INCREMENT;
00130     }
00131   q->pointer[i] = pointer;
00132   thread_UnlockMutex( &(q->mx) );
00133   return i;
00134   }
00135 
00136 /*POD
00137 =H handle_GetPointer
00138 @c GetPointer
00139 
00140 This function is the opposite of R<GetHandle>. If a pointer was
00141 stored in the handle array this function can be used to retrieve the
00142 pointer knowing the handle.
00143 
00144 /*FUNCTION*/
00145 void *handle_GetPointer(void **pHandle,
00146                         unsigned long handle
00147   ){
00148 /*noverbatim
00149 =itemize
00150 =item The first argument T<pHandle> is the pointer to the handle array.
00151 =ite, The second argument T<handle> is the handle of the pointer.
00152 =noitemize
00153 
00154 If there was not pointer registered with that handle the return value of the
00155 function is T<NULL>.
00156 CUT*/
00157   pHandleArray q;
00158   void *z;
00159 
00160   q = *pHandle;
00161   /* if there is no registered handle or the handle is
00162      out of range of registered handles. */
00163   if( q == NULL || handle < 1 || handle >= q->n )return NULL;
00164   thread_LockMutex( &(q->mx) );
00165   z = q->pointer[handle];
00166   thread_UnlockMutex( &(q->mx) );
00167   return z;
00168   }
00169 
00170 /*POD
00171 =H handle_FreeHandle
00172 @c FreeHandle
00173 
00174 Use this function when a pointer is no longer valid. Calling
00175 this function releases the T<handle> for further pointers.
00176 
00177 /*FUNCTION*/
00178 void handle_FreeHandle(void **pHandle,
00179                        unsigned long handle
00180   ){
00181 /*noverbatim
00182 CUT*/
00183   pHandleArray q;
00184 
00185   q = *pHandle;
00186   /* if there is no registered handle or the handle is
00187      out of range of registered handles. */
00188   if( q == NULL || handle < 1 || handle >= q->n )return;
00189   thread_LockMutex( &(q->mx) );
00190   q->pointer[handle] = NULL;
00191   thread_UnlockMutex( &(q->mx) );
00192   return;
00193   }
00194 
00195 /*POD
00196 =H handle_DestroyHandleArray
00197 @c DestroyHandleArray
00198 
00199 Call this function to release the handle array after all handles are
00200 freed and there is no need for the handle heap.
00201 
00202 Use the same memory head T<pMEM> that was used in R<GetHandle>.
00203 
00204 /*FUNCTION*/
00205 void handle_DestroyHandleArray(void **pHandle,
00206                                void *pMEM
00207   ){
00208 /*noverbatim
00209 CUT*/
00210   pHandleArray q;
00211 
00212   q = *pHandle;
00213   if( q == NULL  )return;
00214 
00215   thread_FinishMutex( &(q->mx) );
00216   alloc_Free(q,pMEM);
00217   }

Generated on Sun Mar 12 23:56:30 2006 for ScriptBasic by  doxygen 1.4.6-NO