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 }