Fix head-use-after-free issue detected by ASAN
[platform/core/uifw/isf.git] / ism / src / scim_module.cpp
1 /* ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. */
2
3 /*
4  * Smart Common Input Method
5  *
6  * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
7  *
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this program; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22  * Boston, MA  02111-1307  USA
23  *
24  * $Id: scim_module.cpp,v 1.26 2005/05/24 12:22:51 suzhe Exp $
25  *
26  */
27
28 #define Uses_SCIM_MODULE
29 #define Uses_STL_ALGORITHM
30 #include "scim_private.h"
31 #include "scim.h"
32 #include "ltdl.h"
33 #include <dirent.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <scim_panel_common.h>
38 #include "isf_query_utility.h"
39
40 namespace scim {
41
42 typedef void (*ModuleInitFunc) (void);
43 typedef void (*ModuleExitFunc) (void);
44
45 struct Module::ModuleImpl
46 {
47     lt_dlhandle handle;
48     ModuleInitFunc init;
49     ModuleExitFunc exit;
50     String path;
51     String name;
52
53     ModuleImpl () : handle (0), init (0), exit (0) { }
54 };
55
56 static std::vector <ModuleInitFunc> _scim_modules;
57
58 static void
59 _scim_get_module_paths (std::vector <String> &paths, const String &type)
60 {
61     const char *module_path_env;
62
63     std::vector <String> module_paths;
64     std::vector <String>::iterator it;
65
66     paths.clear ();
67
68     module_paths.push_back (String (SCIM_MODULE_PATH));
69
70     module_path_env = getenv ("SCIM_MODULE_PATH");
71
72     if (module_path_env) {
73         module_paths.push_back (String (module_path_env));
74     }
75
76     // append version to the end of the paths
77     for (it = module_paths.begin (); it != module_paths.end (); ++it) {
78         String tmp_dir;
79
80         tmp_dir = *it + String (SCIM_PATH_DELIM_STRING) +
81                     String (SCIM_BINARY_VERSION) +
82                     String (SCIM_PATH_DELIM_STRING) + type;
83
84         paths.push_back (tmp_dir);
85
86         tmp_dir = *it + String (SCIM_PATH_DELIM_STRING) + type;
87         paths.push_back (tmp_dir);
88     }
89 }
90
91 EXAPI int
92 scim_get_module_list (std::vector <String>& mod_list, const String& type)
93 {
94     unsigned int i = 0;
95     std::vector<String> mname;
96     std::vector<String> paths;
97
98     mod_list.clear ();
99
100     if (type.compare("Helper") == 0) {
101         isf_db_select_module_name_by_mode(TOOLBAR_HELPER_MODE, mname);
102         for (i = 0; i < mname.size(); i++)
103             mod_list.push_back(mname[i]);
104     }
105     else if (type.compare("IMEngine") == 0) {
106         isf_db_select_module_name_by_mode(TOOLBAR_KEYBOARD_MODE, mname);
107         for (i = 0; i < mname.size(); i++)
108             mod_list.push_back(mname[i]);
109
110         struct stat sb;
111         if (stat ("/usr/lib/scim-1.0/1.4.0/IMEngine/socket.so", &sb) == 0) {
112             if (S_ISREG(sb.st_mode))
113                 mod_list.push_back("socket");
114         }
115     }
116     else {
117         _scim_get_module_paths (paths, type);
118
119         for (std::vector<String>::iterator i = paths.begin (); i!= paths.end (); ++i) {
120             DIR *dir = opendir (i->c_str ());
121             if (dir) {
122                 struct dirent *file = readdir (dir);
123
124                 while (file) {
125                     struct stat filestat;
126                     String absfn = *i + String (SCIM_PATH_DELIM_STRING) + file->d_name;
127                     if (stat (absfn.c_str (), &filestat) == 0) {
128                         if (S_ISREG (filestat.st_mode)) {
129                             String mod_name = String (file->d_name);
130                             mod_list.push_back (mod_name.substr (0, mod_name.find_last_of ('.')));
131                         }
132                     }
133                     file = readdir (dir);
134                 }
135                 closedir (dir);
136             }
137         }
138     }
139     std::sort (mod_list.begin (), mod_list.end ());
140     mod_list.erase (std::unique (mod_list.begin (), mod_list.end ()), mod_list.end ());
141     return mod_list.size ();
142 }
143
144 Module::Module ()
145     : m_impl (new ModuleImpl)
146 {
147     lt_dlinit ();
148 }
149
150 Module::Module (const String &name, const String &type)
151     : m_impl (new ModuleImpl)
152 {
153     if (!m_impl) return;
154
155     lt_dlinit ();
156     if (!load (name, type))
157         std::cerr << "Load name:" << name << " type:" << type << " is failed!!!";
158 }
159
160 Module::~Module ()
161 {
162     unload ();
163     lt_dlexit ();
164     delete m_impl;
165 }
166
167 static String
168 _concatenate_ltdl_prefix (const String &name, const String &symbol)
169 {
170     String prefix (name);
171
172     for (size_t i=0; i<prefix.length (); i++)
173         if (!isalnum ((int)prefix[i]))
174             prefix[i] = '_';
175
176     return prefix + String ("_LTX_") + symbol;
177 }
178
179 bool
180 Module::load (const String &name, const String &type)
181 {
182     // If cannot unload original module (it's resident), then return false.
183     if (is_resident ())
184         return false;
185
186     unsigned int i = 0;
187     std::vector<String> mpath;
188     std::vector <String> paths;
189     std::vector <String>::iterator it;
190
191     String module_path;
192
193     lt_dlhandle    new_handle = 0;
194
195     ModuleInitFunc new_init;
196     ModuleExitFunc new_exit;
197
198     if (type.compare("Helper") == 0) {
199         isf_db_select_module_path_by_mode(TOOLBAR_HELPER_MODE, mpath);
200         mpath.push_back(String(SCIM_MODULE_PATH) + String(SCIM_PATH_DELIM_STRING) + String(SCIM_BINARY_VERSION)
201             + String(SCIM_PATH_DELIM_STRING) + String("Helper"));
202         for (i = 0; i < mpath.size(); i++) {
203             module_path = mpath[i] + String (SCIM_PATH_DELIM_STRING) + name;
204             new_handle = lt_dlopenext (module_path.c_str ());
205             if (new_handle)
206                 break;
207         }
208     }
209     else if (type.compare("IMEngine") == 0 && name.compare("socket")) {
210         mpath.push_back(String(SCIM_MODULE_PATH) + String(SCIM_PATH_DELIM_STRING) + String(SCIM_BINARY_VERSION)
211             + String(SCIM_PATH_DELIM_STRING) + String("IMEngine"));
212         for (i = 0; i < mpath.size(); i++) {
213             module_path = mpath[i] + String (SCIM_PATH_DELIM_STRING) + name;
214             new_handle = lt_dlopenext (module_path.c_str ());
215             if (new_handle)
216                 break;
217         }
218     }
219     else {
220         _scim_get_module_paths (paths, type);
221
222         for (it = paths.begin (); it != paths.end (); ++it) {
223             module_path = *it + String (SCIM_PATH_DELIM_STRING) + name;
224             new_handle = lt_dlopenext (module_path.c_str ());
225             if (new_handle)
226                 break;
227         }
228     }
229
230     if (!new_handle) {
231         new_handle = lt_dlopenext (name.c_str ());
232     }
233
234     if (!new_handle)
235         return false;
236
237     String l_symbol;
238
239     // Try to load the symbol scim_module_init
240     l_symbol = "scim_module_init";
241     new_init = (ModuleInitFunc) lt_dlsym (new_handle, l_symbol.c_str ());
242
243     // If symbol load failed, try to add LTX prefix and load again.
244     // This will occurred when name.la is missing.
245     if (!new_init) {
246         l_symbol = _concatenate_ltdl_prefix (name, l_symbol);
247         new_init = (ModuleInitFunc) lt_dlsym (new_handle, l_symbol.c_str ());
248
249         // Failed again? Try to prepend a under score to the symbol name.
250         if (!new_init) {
251             l_symbol.insert (l_symbol.begin (),'_');
252             new_init = (ModuleInitFunc) lt_dlsym (new_handle, l_symbol.c_str ());
253         }
254     }
255
256     // Could not load the module!
257     if (!new_init) {
258         lt_dlclose (new_handle);
259         return false;
260     }
261
262     // Try to load the symbol scim_module_exit
263     l_symbol = "scim_module_exit";
264     new_exit = (ModuleExitFunc) lt_dlsym (new_handle, l_symbol.c_str ());
265
266     // If symbol load failed, try to add LTX prefix and load again.
267     // This will occurred when name.la is missing.
268     if (!new_exit) {
269         l_symbol = _concatenate_ltdl_prefix (name, l_symbol);
270         new_exit = (ModuleExitFunc) lt_dlsym (new_handle, l_symbol.c_str ());
271
272         // Failed again? Try to prepend a under score to the symbol name.
273         if (!new_exit) {
274             l_symbol.insert (l_symbol.begin (),'_');
275             new_exit = (ModuleExitFunc) lt_dlsym (new_handle, l_symbol.c_str ());
276         }
277     }
278
279     //Check if the module is already loaded.
280     if (std::find (_scim_modules.begin (), _scim_modules.end (), new_init)
281         != _scim_modules.end ()) {
282         lt_dlclose (new_handle);
283         return false;
284     }
285
286     if (unload ()) {
287         _scim_modules.push_back (new_init);
288
289         const lt_dlinfo *info = lt_dlgetinfo (new_handle);
290
291         m_impl->handle = new_handle;
292         m_impl->init   = new_init;
293         m_impl->exit   = new_exit;
294         m_impl->path   = String (info->filename);
295         m_impl->name   = name;
296
297         try {
298             m_impl->init ();
299             return true;
300         } catch (...) {
301             unload ();
302         }
303     } else {
304         lt_dlclose (new_handle);
305     }
306
307     return false;
308 }
309
310 bool
311 Module::unload ()
312 {
313     if (!m_impl || !m_impl->handle)
314         return true;
315
316     if (is_resident ())
317         return false;
318
319     std::vector <ModuleInitFunc>::iterator it =
320         std::find (_scim_modules.begin (), _scim_modules.end (), m_impl->init);
321
322     if (m_impl->exit) {
323         try { m_impl->exit (); } catch (...) { }
324     }
325
326     lt_dlclose (m_impl->handle);
327
328     if (it != _scim_modules.end ())
329         _scim_modules.erase (it);
330
331     m_impl->handle = 0;
332     m_impl->init   = 0;
333     m_impl->exit   = 0;
334     m_impl->path   = String ();
335     m_impl->name   = String ();
336
337     return true;
338 }
339
340 bool
341 Module::make_resident () const
342 {
343     if (m_impl && m_impl->handle) {
344         return lt_dlmakeresident (m_impl->handle) == 0;
345     }
346     return false;
347 }
348
349 bool
350 Module::is_resident () const
351 {
352     if (m_impl && m_impl->handle) {
353         return lt_dlisresident (m_impl->handle) == 1;
354     }
355     return false;
356 }
357
358 bool
359 Module::valid () const
360 {
361     return (m_impl && m_impl->handle && m_impl->init);
362 }
363
364 String
365 Module::get_path () const
366 {
367     return m_impl->path;
368 }
369
370 void *
371 Module::symbol (const String & sym) const
372 {
373     void * func = 0;
374
375     if (m_impl->handle) {
376         String l_symbol = sym;
377         func = lt_dlsym (m_impl->handle, l_symbol.c_str ());
378         if (!func) {
379             l_symbol = _concatenate_ltdl_prefix (m_impl->name, l_symbol);
380             func = lt_dlsym (m_impl->handle, l_symbol.c_str ());
381             if (!func) {
382                 l_symbol.insert (l_symbol.begin (), '_');
383                 func = lt_dlsym (m_impl->handle, l_symbol.c_str ());
384             }
385         }
386     }
387     return func;
388 }
389
390 } // namespace scim
391
392 /*
393 vi:ts=4:nowrap:ai:expandtab
394 */