common: prevent buffer overflow
[supercollider.git] / server / scsynth / SC_Lib_Cintf.cpp
blob1afab13c644bbbd13c6f16fb5e3da9700764f830
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "SC_Lib_Cintf.h"
24 #include "SC_ComPort.h"
25 #include "SC_CoreAudio.h"
26 #include "SC_UnitDef.h"
27 #include "SC_BufGen.h"
28 #include "SC_World.h"
29 #include "SC_StringParser.h"
30 #include "SC_InterfaceTable.h"
31 #include "SC_DirUtils.h"
32 #include <stdexcept>
33 #ifndef _MSC_VER
34 #include <dirent.h>
35 #endif //_MSC_VER
37 #ifndef _WIN32
38 #include <dlfcn.h>
39 #endif
41 #ifdef _WIN32
42 #include "SC_Win32Utils.h"
43 #else
44 #include <libgen.h>
45 #endif
47 // Plugin directory in resource directory
48 #if defined(_WIN32) && defined(_DEBUG)
49 # define SC_PLUGIN_DIR_NAME "plugins_debug"
50 #else
51 # define SC_PLUGIN_DIR_NAME "plugins"
52 #endif
54 // Extension for binary plugins
55 #ifndef SC_PLUGIN_EXT
56 # define SC_PLUGIN_EXT ".scx"
57 #endif
59 // Symbol of initialization routine when loading plugins
60 #ifndef SC_PLUGIN_LOAD_SYM
61 #define SC_PLUGIN_LOAD_SYM "load"
62 #endif
64 #ifndef _WIN32
65 # include <sys/param.h>
66 #endif
68 #ifdef __APPLE__
69 extern "C" {
70 #include <mach-o/dyld.h>
71 #include <mach-o/getsect.h>
73 char gTempVal;
74 #endif
76 Malloc gMalloc;
77 HashTable<SC_LibCmd, Malloc> *gCmdLib;
78 HashTable<struct UnitDef, Malloc> *gUnitDefLib = 0;
79 HashTable<struct BufGen, Malloc> *gBufGenLib = 0;
80 HashTable<struct PlugInCmd, Malloc> *gPlugInCmds = 0;
81 extern struct InterfaceTable gInterfaceTable;
82 SC_LibCmd* gCmdArray[NUMBER_OF_COMMANDS];
84 void initMiscCommands();
85 static bool PlugIn_LoadDir(const char *dirname, bool reportError);
87 #ifdef __APPLE__
88 void read_section(const struct mach_header *mhp, unsigned long slide, const char *segname, const char *sectname)
90 u_int32_t size;
91 char *sect = getsectdatafromheader(mhp, segname, sectname, &size);
92 if(!sect) return;
94 char *start = sect + slide;
95 char *end = start + size;
97 while(start != end) {
98 gTempVal += *(char *)start;
99 start++;
102 #endif
104 extern void IO_Load(InterfaceTable *table);
105 extern void Osc_Load(InterfaceTable *table);
106 extern void Delay_Load(InterfaceTable *table);
107 extern void BinaryOp_Load(InterfaceTable *table);
108 extern void Filter_Load(InterfaceTable *table);
109 extern void Gendyn_Load(InterfaceTable *table);
110 extern void LF_Load(InterfaceTable *table);
111 extern void Noise_Load(InterfaceTable *table);
112 extern void MulAdd_Load(InterfaceTable *table);
113 extern void Grain_Load(InterfaceTable *table);
114 extern void Pan_Load(InterfaceTable *table);
115 extern void Reverb_Load(InterfaceTable *table);
116 extern void Trigger_Load(InterfaceTable *table);
117 extern void UnaryOp_Load(InterfaceTable *table);
118 extern void DiskIO_Load(InterfaceTable *table);
119 extern void Test_Load(InterfaceTable *table);
120 extern void PhysicalModeling_Load(InterfaceTable *table);
121 extern void Demand_Load(InterfaceTable *table);
122 extern void DynNoise_Load(InterfaceTable *table);
123 extern void FFT_UGens_Load(InterfaceTable *table);
124 extern void iPhone_Load(InterfaceTable *table);
126 void initialize_library(const char *uGensPluginPath)
128 gCmdLib = new HashTable<SC_LibCmd, Malloc>(&gMalloc, 64, true);
129 gUnitDefLib = new HashTable<UnitDef, Malloc>(&gMalloc, 512, true);
130 gBufGenLib = new HashTable<BufGen, Malloc>(&gMalloc, 512, true);
131 gPlugInCmds = new HashTable<PlugInCmd, Malloc>(&gMalloc, 64, true);
133 initMiscCommands();
135 #ifdef STATIC_PLUGINS
136 IO_Load(&gInterfaceTable);
137 Osc_Load(&gInterfaceTable);
138 Delay_Load(&gInterfaceTable);
139 BinaryOp_Load(&gInterfaceTable);
140 Filter_Load(&gInterfaceTable);
141 Gendyn_Load(&gInterfaceTable);
142 LF_Load(&gInterfaceTable);
143 Noise_Load(&gInterfaceTable);
144 MulAdd_Load(&gInterfaceTable);
145 Grain_Load(&gInterfaceTable);
146 Pan_Load(&gInterfaceTable);
147 Reverb_Load(&gInterfaceTable);
148 Trigger_Load(&gInterfaceTable);
149 UnaryOp_Load(&gInterfaceTable);
150 DiskIO_Load(&gInterfaceTable);
151 PhysicalModeling_Load(&gInterfaceTable);
152 Test_Load(&gInterfaceTable);
153 Demand_Load(&gInterfaceTable);
154 DynNoise_Load(&gInterfaceTable);
155 #if defined(SC_IPHONE) && !TARGET_IPHONE_SIMULATOR
156 iPhone_Load(&gInterfaceTable);
157 #endif
158 FFT_UGens_Load(&gInterfaceTable);
159 return;
160 #endif
162 // If uGensPluginPath is supplied, it is exclusive.
163 bool loadUGensExtDirs = true;
164 if(uGensPluginPath){
165 loadUGensExtDirs = false;
166 SC_StringParser sp(uGensPluginPath, SC_STRPARSE_PATHDELIMITER);
167 while (!sp.AtEnd()) {
168 PlugIn_LoadDir(const_cast<char *>(sp.NextToken()), true);
172 if(loadUGensExtDirs) {
173 #ifdef SC_PLUGIN_DIR
174 // load globally installed plugins
175 if (sc_DirectoryExists(SC_PLUGIN_DIR)) {
176 PlugIn_LoadDir(SC_PLUGIN_DIR, true);
178 #endif
179 // load default plugin directory
180 char pluginDir[MAXPATHLEN];
181 sc_GetResourceDirectory(pluginDir, MAXPATHLEN);
182 sc_AppendToPath(pluginDir, MAXPATHLEN, SC_PLUGIN_DIR_NAME);
184 if (sc_DirectoryExists(pluginDir)) {
185 PlugIn_LoadDir(pluginDir, true);
189 // get extension directories
190 char extensionDir[MAXPATHLEN];
191 if (!sc_IsStandAlone() && loadUGensExtDirs) {
192 // load system extension plugins
193 sc_GetSystemExtensionDirectory(extensionDir, MAXPATHLEN);
194 PlugIn_LoadDir(extensionDir, false);
196 // load user extension plugins
197 sc_GetUserExtensionDirectory(extensionDir, MAXPATHLEN);
198 PlugIn_LoadDir(extensionDir, false);
200 // load user plugin directories
201 SC_StringParser sp(getenv("SC_PLUGIN_PATH"), SC_STRPARSE_PATHDELIMITER);
202 while (!sp.AtEnd()) {
203 PlugIn_LoadDir(const_cast<char *>(sp.NextToken()), true);
206 #ifdef __APPLE__
207 /* on darwin plugins are lazily loaded (dlopen uses mmap internally), which can produce audible
208 glitches when UGens have to be paged-in. to work around this we preload all the plugins by
209 iterating through their memory space. */
211 unsigned long images = _dyld_image_count();
212 for(unsigned long i = 0; i < images; i++) {
213 const mach_header *hdr = _dyld_get_image_header(i);
214 unsigned long slide = _dyld_get_image_vmaddr_slide(i);
215 const char *name = _dyld_get_image_name(i);
216 uint32_t size;
217 char *sect;
219 if(!strcmp(name + (strlen(name) - 4), ".scx")) {
220 read_section(hdr, slide, "__TEXT", "__text");
221 read_section(hdr, slide, "__TEXT", "__const");
222 read_section(hdr, slide, "__TEXT", "__cstring");
223 read_section(hdr, slide, "__TEXT", "__picsymbol_stub");
224 read_section(hdr, slide, "__TEXT", "__symbol_stub");
225 read_section(hdr, slide, "__TEXT", "__const");
226 read_section(hdr, slide, "__TEXT", "__literal4");
227 read_section(hdr, slide, "__TEXT", "__literal8");
229 read_section(hdr, slide, "__DATA", "__data");
230 read_section(hdr, slide, "__DATA", "__la_symbol_ptr");
231 read_section(hdr, slide, "__DATA", "__nl_symbol_ptr");
232 read_section(hdr, slide, "__DATA", "__dyld");
233 read_section(hdr, slide, "__DATA", "__const");
234 read_section(hdr, slide, "__DATA", "__mod_init_func");
235 read_section(hdr, slide, "__DATA", "__bss");
236 read_section(hdr, slide, "__DATA", "__common");
238 read_section(hdr, slide, "__IMPORT", "__jump_table");
239 read_section(hdr, slide, "__IMPORT", "__pointers");
242 #endif
245 static bool PlugIn_Load(const char *filename)
247 #ifdef _WIN32
249 HINSTANCE hinstance = LoadLibrary( filename );
250 if (!hinstance) {
251 char *s;
252 DWORD lastErr = GetLastError();
253 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
254 0, lastErr , 0, (char*)&s, 1, 0 );
255 scprintf("*** ERROR: LoadLibrary '%s' err '%s'\n", filename, s);
256 LocalFree( s );
257 return false;
260 void *ptr = (void *)GetProcAddress( hinstance, SC_PLUGIN_LOAD_SYM );
261 if (!ptr) {
262 char *s;
263 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
264 0, GetLastError(), 0, (char*)&s, 1, 0 );
265 scprintf("*** ERROR: GetProcAddress %s err '%s'\n", SC_PLUGIN_LOAD_SYM, s);
266 LocalFree( s );
268 FreeLibrary(hinstance);
269 return false;
272 LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr;
273 (*loadFunc)(&gInterfaceTable);
275 // FIXME: at the moment we never call FreeLibrary() on a loaded plugin
277 return true;
279 #else
281 void* handle = dlopen(filename, RTLD_NOW);
283 if (!handle) {
284 scprintf("*** ERROR: dlopen '%s' err '%s'\n", filename, dlerror());
285 dlclose(handle);
286 return false;
289 void *ptr;
291 ptr = dlsym(handle, SC_PLUGIN_LOAD_SYM);
292 if (!ptr) {
293 scprintf("*** ERROR: dlsym %s err '%s'\n", SC_PLUGIN_LOAD_SYM, dlerror());
294 dlclose(handle);
295 return false;
298 LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr;
299 (*loadFunc)(&gInterfaceTable);
301 return true;
303 #endif
306 static bool PlugIn_LoadDir(const char *dirname, bool reportError)
308 bool success = true;
310 SC_DirHandle *dir = sc_OpenDir(dirname);
311 if (!dir) {
312 if (reportError) {
313 scprintf("*** ERROR: open directory failed '%s'\n", dirname); fflush(stdout);
315 return false;
318 int firstCharOffset = strlen(dirname)+1;
320 for (;;) {
321 char diritem[MAXPATHLEN];
322 bool skipItem = true;
323 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
324 if (!validItem) break;
325 if (skipItem || (*(diritem+firstCharOffset) == '.')) continue; // skip files+folders whose first char is a dot
327 if (sc_DirectoryExists(diritem)) {
328 success = PlugIn_LoadDir(diritem, reportError);
329 } else {
330 int dnamelen = strlen(diritem);
331 int extlen = strlen(SC_PLUGIN_EXT);
332 char *extptr = diritem+dnamelen-extlen;
333 if (strncmp(extptr, SC_PLUGIN_EXT, extlen) == 0) {
334 success = PlugIn_Load(diritem);
338 if (!success) continue;
341 sc_CloseDir(dir);
342 return success;