Bug Summary

File:tools/lldb/source/Target/TargetList.cpp
Location:line 346, column 20
Description:Array access (from variable 'user_exe_path') results in a null pointer dereference

Annotated Source Code

1//===-- TargetList.cpp ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/lldb-python.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/Broadcaster.h"
17#include "lldb/Core/Debugger.h"
18#include "lldb/Core/Event.h"
19#include "lldb/Core/Module.h"
20#include "lldb/Core/ModuleSpec.h"
21#include "lldb/Core/State.h"
22#include "lldb/Core/Timer.h"
23#include "lldb/Host/Host.h"
24#include "lldb/Interpreter/CommandInterpreter.h"
25#include "lldb/Interpreter/OptionGroupPlatform.h"
26#include "lldb/Symbol/ObjectFile.h"
27#include "lldb/Target/Platform.h"
28#include "lldb/Target/Process.h"
29#include "lldb/Target/TargetList.h"
30
31#include "llvm/ADT/SmallString.h"
32
33using namespace lldb;
34using namespace lldb_private;
35
36ConstString &
37TargetList::GetStaticBroadcasterClass ()
38{
39 static ConstString class_name ("lldb.targetList");
40 return class_name;
41}
42
43//----------------------------------------------------------------------
44// TargetList constructor
45//----------------------------------------------------------------------
46TargetList::TargetList(Debugger &debugger) :
47 Broadcaster(&debugger, TargetList::GetStaticBroadcasterClass().AsCString()),
48 m_target_list(),
49 m_target_list_mutex (Mutex::eMutexTypeRecursive),
50 m_selected_target_idx (0)
51{
52 CheckInWithManager();
53}
54
55//----------------------------------------------------------------------
56// Destructor
57//----------------------------------------------------------------------
58TargetList::~TargetList()
59{
60 Mutex::Locker locker(m_target_list_mutex);
61 m_target_list.clear();
62}
63
64Error
65TargetList::CreateTarget (Debugger &debugger,
66 const char *user_exe_path,
67 const char *triple_cstr,
68 bool get_dependent_files,
69 const OptionGroupPlatform *platform_options,
70 TargetSP &target_sp)
71{
72 Error error;
73 PlatformSP platform_sp;
74
75 // This is purposely left empty unless it is specified by triple_cstr.
76 // If not initialized via triple_cstr, then the currently selected platform
77 // will set the architecture correctly.
78 const ArchSpec arch(triple_cstr);
79 if (triple_cstr && triple_cstr[0])
80 {
81 if (!arch.IsValid())
82 {
83 error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr);
84 return error;
85 }
86 }
87
88 ArchSpec platform_arch(arch);
89
90 bool prefer_platform_arch = false;
91
92 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
93 if (platform_options && platform_options->PlatformWasSpecified ())
94 {
95 const bool select_platform = true;
96 platform_sp = platform_options->CreatePlatformWithOptions (interpreter,
97 arch,
98 select_platform,
99 error,
100 platform_arch);
101 if (!platform_sp)
102 return error;
103 }
104
105 if (user_exe_path && user_exe_path[0])
106 {
107 ModuleSpecList module_specs;
108 ModuleSpec module_spec;
109 module_spec.GetFileSpec().SetFile(user_exe_path, true);
110
111 // Resolve the executable in case we are given a path to a application bundle
112 // like a .app bundle on MacOSX
113 Host::ResolveExecutableInBundle (module_spec.GetFileSpec());
114
115 lldb::offset_t file_offset = 0;
116 lldb::offset_t file_size = 0;
117 const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs);
118 if (num_specs > 0)
119 {
120 ModuleSpec matching_module_spec;
121
122 if (num_specs == 1)
123 {
124 if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec))
125 {
126 if (platform_arch.IsValid())
127 {
128 if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture()))
129 {
130 // If the OS or vendor weren't specified, then adopt the module's
131 // architecture so that the platform matching can be more accurate
132 if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified())
133 {
134 prefer_platform_arch = true;
135 platform_arch = matching_module_spec.GetArchitecture();
136 }
137 }
138 else
139 {
140 error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'",
141 platform_arch.GetTriple().str().c_str(),
142 matching_module_spec.GetArchitecture().GetTriple().str().c_str(),
143 module_spec.GetFileSpec().GetPath().c_str());
144 return error;
145 }
146 }
147 else
148 {
149 // Only one arch and none was specified
150 prefer_platform_arch = true;
151 platform_arch = matching_module_spec.GetArchitecture();
152 }
153 }
154 }
155 else
156 {
157 if (arch.IsValid())
158 {
159 module_spec.GetArchitecture() = arch;
160 if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec))
161 {
162 prefer_platform_arch = true;
163 platform_arch = matching_module_spec.GetArchitecture();
164 }
165 }
166 else
167 {
168 // No architecture specified, check if there is only one platform for
169 // all of the architectures.
170
171 typedef std::vector<PlatformSP> PlatformList;
172 PlatformList platforms;
173 PlatformSP host_platform_sp = Platform::GetHostPlatform();
174 for (size_t i=0; i<num_specs; ++i)
175 {
176 ModuleSpec module_spec;
177 if (module_specs.GetModuleSpecAtIndex(i, module_spec))
178 {
179 // See if there was a selected platform and check that first
180 // since the user may have specified it.
181 if (platform_sp)
182 {
183 if (platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL__null))
184 {
185 platforms.push_back(platform_sp);
186 continue;
187 }
188 }
189
190 // Next check the host platform it if wasn't already checked above
191 if (host_platform_sp && (!platform_sp || host_platform_sp->GetName() != platform_sp->GetName()))
192 {
193 if (host_platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, NULL__null))
194 {
195 platforms.push_back(host_platform_sp);
196 continue;
197 }
198 }
199
200 // Just find a platform that matches the architecture in the executable file
201 platforms.push_back(Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr));
202 }
203 }
204
205 Platform *platform_ptr = NULL__null;
206 for (const auto &the_platform_sp : platforms)
207 {
208 if (platform_ptr)
209 {
210 if (platform_ptr->GetName() != the_platform_sp->GetName())
211 {
212 platform_ptr = NULL__null;
213 break;
214 }
215 }
216 else
217 {
218 platform_ptr = the_platform_sp.get();
219 }
220 }
221
222 if (platform_ptr)
223 {
224 // All platforms for all modules in the exectuable match, so we can select this platform
225 platform_sp = platforms.front();
226 }
227 else
228 {
229 // More than one platform claims to support this file, so the --platform option must be specified
230 StreamString error_strm;
231 std::set<Platform *> platform_set;
232 error_strm.Printf ("more than one platform supports this executable (");
233 for (const auto &the_platform_sp : platforms)
234 {
235 if (platform_set.find(the_platform_sp.get()) == platform_set.end())
236 {
237 if (!platform_set.empty())
238 error_strm.PutCString(", ");
239 error_strm.PutCString(the_platform_sp->GetName().GetCString());
240 platform_set.insert(the_platform_sp.get());
241 }
242 }
243 error_strm.Printf("), use the --platform option to specify a platform");
244 error.SetErrorString(error_strm.GetString().c_str());
245 return error;
246 }
247 }
248 }
249 }
250 }
251
252 if (!platform_sp)
253 {
254 // Get the current platform and make sure it is compatible with the
255 // current architecture if we have a valid architecture.
256 platform_sp = debugger.GetPlatformList().GetSelectedPlatform ();
257
258 if (!prefer_platform_arch && arch.IsValid())
259 {
260 if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
261 {
262 platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
263 if (platform_sp)
264 debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
265 }
266 }
267 else if (platform_arch.IsValid())
268 {
269 // if "arch" isn't valid, yet "platform_arch" is, it means we have an executable file with
270 // a single architecture which should be used
271 ArchSpec fixed_platform_arch;
272 if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch))
273 {
274 platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch);
275 if (platform_sp)
276 debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
277 }
278 }
279 }
280
281 if (!platform_arch.IsValid())
282 platform_arch = arch;
283
284 error = TargetList::CreateTarget (debugger,
285 user_exe_path,
286 platform_arch,
287 get_dependent_files,
288 platform_sp,
289 target_sp);
290 return error;
291}
292
293Error
294TargetList::CreateTarget (Debugger &debugger,
295 const char *user_exe_path,
296 const ArchSpec& specified_arch,
297 bool get_dependent_files,
298 PlatformSP &platform_sp,
299 TargetSP &target_sp)
300{
301 Timer scoped_timer (__PRETTY_FUNCTION__,
302 "TargetList::CreateTarget (file = '%s', arch = '%s')",
303 user_exe_path,
304 specified_arch.GetArchitectureName());
305 Error error;
306
307 ArchSpec arch(specified_arch);
308
309 if (arch.IsValid())
1
Taking false branch
310 {
311 if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, NULL__null))
312 platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
313 }
314
315 if (!platform_sp)
2
Taking false branch
316 platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
317
318 if (!arch.IsValid())
3
Taking true branch
319 arch = specified_arch;
320
321 FileSpec file (user_exe_path, false);
322 if (!file.Exists() && user_exe_path && user_exe_path[0] == '~')
4
Assuming pointer value is null
323 {
324 // we want to expand the tilde but we don't want to resolve any symbolic links
325 // so we can't use the FileSpec constructor's resolve flag
326 llvm::SmallString<64> unglobbed_path(user_exe_path);
327 FileSpec::ResolveUsername(unglobbed_path);
328
329 if (unglobbed_path.empty())
330 file = FileSpec(user_exe_path, false);
331 else
332 file = FileSpec(unglobbed_path.c_str(), false);
333 }
334
335 bool user_exe_path_is_bundle = false;
336 char resolved_bundle_exe_path[PATH_MAX4096];
337 resolved_bundle_exe_path[0] = '\0';
338 if (file)
5
Taking true branch
339 {
340 if (file.GetFileType() == FileSpec::eFileTypeDirectory)
6
Taking false branch
341 user_exe_path_is_bundle = true;
342
343 if (file.IsRelativeToCurrentWorkingDirectory())
7
Taking true branch
344 {
345 // Ignore paths that start with "./" and "../"
346 if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') ||
8
Array access (from variable 'user_exe_path') results in a null pointer dereference
347 (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/')))
348 {
349 char cwd[PATH_MAX4096];
350 if (getcwd (cwd, sizeof(cwd)))
351 {
352 std::string cwd_user_exe_path (cwd);
353 cwd_user_exe_path += '/';
354 cwd_user_exe_path += user_exe_path;
355 FileSpec cwd_file (cwd_user_exe_path.c_str(), false);
356 if (cwd_file.Exists())
357 file = cwd_file;
358 }
359 }
360 }
361
362 ModuleSP exe_module_sp;
363 if (platform_sp)
364 {
365 FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
366 error = platform_sp->ResolveExecutable (file,
367 arch,
368 exe_module_sp,
369 executable_search_paths.GetSize() ? &executable_search_paths : NULL__null);
370 }
371
372 if (error.Success() && exe_module_sp)
373 {
374 if (exe_module_sp->GetObjectFile() == NULL__null)
375 {
376 if (arch.IsValid())
377 {
378 error.SetErrorStringWithFormat("\"%s\" doesn't contain architecture %s",
379 file.GetPath().c_str(),
380 arch.GetArchitectureName());
381 }
382 else
383 {
384 error.SetErrorStringWithFormat("unsupported file type \"%s\"",
385 file.GetPath().c_str());
386 }
387 return error;
388 }
389 target_sp.reset(new Target(debugger, arch, platform_sp));
390 target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
391 if (user_exe_path_is_bundle)
392 exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path));
393 }
394 }
395 else
396 {
397 // No file was specified, just create an empty target with any arch
398 // if a valid arch was specified
399 target_sp.reset(new Target(debugger, arch, platform_sp));
400 }
401
402 if (target_sp)
403 {
404 // Set argv0 with what the user typed, unless the user specified a
405 // directory. If the user specified a directory, then it is probably a
406 // bundle that was resolved and we need to use the resolved bundle path
407 if (user_exe_path)
408 {
409 // Use exactly what the user typed as the first argument when we exec or posix_spawn
410 if (user_exe_path_is_bundle && resolved_bundle_exe_path[0])
411 {
412 target_sp->SetArg0 (resolved_bundle_exe_path);
413 }
414 else
415 {
416 // Use resolved path
417 target_sp->SetArg0 (file.GetPath().c_str());
418 }
419 }
420 if (file.GetDirectory())
421 {
422 FileSpec file_dir;
423 file_dir.GetDirectory() = file.GetDirectory();
424 target_sp->GetExecutableSearchPaths ().Append (file_dir);
425 }
426 Mutex::Locker locker(m_target_list_mutex);
427 m_selected_target_idx = m_target_list.size();
428 m_target_list.push_back(target_sp);
429
430
431 }
432
433 return error;
434}
435
436bool
437TargetList::DeleteTarget (TargetSP &target_sp)
438{
439 Mutex::Locker locker(m_target_list_mutex);
440 collection::iterator pos, end = m_target_list.end();
441
442 for (pos = m_target_list.begin(); pos != end; ++pos)
443 {
444 if (pos->get() == target_sp.get())
445 {
446 m_target_list.erase(pos);
447 return true;
448 }
449 }
450 return false;
451}
452
453
454TargetSP
455TargetList::FindTargetWithExecutableAndArchitecture
456(
457 const FileSpec &exe_file_spec,
458 const ArchSpec *exe_arch_ptr
459) const
460{
461 Mutex::Locker locker (m_target_list_mutex);
462 TargetSP target_sp;
463 bool full_match = (bool)exe_file_spec.GetDirectory();
464
465 collection::const_iterator pos, end = m_target_list.end();
466 for (pos = m_target_list.begin(); pos != end; ++pos)
467 {
468 Module *exe_module = (*pos)->GetExecutableModulePointer();
469
470 if (exe_module)
471 {
472 if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match))
473 {
474 if (exe_arch_ptr)
475 {
476 if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture()))
477 continue;
478 }
479 target_sp = *pos;
480 break;
481 }
482 }
483 }
484 return target_sp;
485}
486
487TargetSP
488TargetList::FindTargetWithProcessID (lldb::pid_t pid) const
489{
490 Mutex::Locker locker(m_target_list_mutex);
491 TargetSP target_sp;
492 collection::const_iterator pos, end = m_target_list.end();
493 for (pos = m_target_list.begin(); pos != end; ++pos)
494 {
495 Process* process = (*pos)->GetProcessSP().get();
496 if (process && process->GetID() == pid)
497 {
498 target_sp = *pos;
499 break;
500 }
501 }
502 return target_sp;
503}
504
505
506TargetSP
507TargetList::FindTargetWithProcess (Process *process) const
508{
509 TargetSP target_sp;
510 if (process)
511 {
512 Mutex::Locker locker(m_target_list_mutex);
513 collection::const_iterator pos, end = m_target_list.end();
514 for (pos = m_target_list.begin(); pos != end; ++pos)
515 {
516 if (process == (*pos)->GetProcessSP().get())
517 {
518 target_sp = *pos;
519 break;
520 }
521 }
522 }
523 return target_sp;
524}
525
526TargetSP
527TargetList::GetTargetSP (Target *target) const
528{
529 TargetSP target_sp;
530 if (target)
531 {
532 Mutex::Locker locker(m_target_list_mutex);
533 collection::const_iterator pos, end = m_target_list.end();
534 for (pos = m_target_list.begin(); pos != end; ++pos)
535 {
536 if (target == (*pos).get())
537 {
538 target_sp = *pos;
539 break;
540 }
541 }
542 }
543 return target_sp;
544}
545
546uint32_t
547TargetList::SendAsyncInterrupt (lldb::pid_t pid)
548{
549 uint32_t num_async_interrupts_sent = 0;
550
551 if (pid != LLDB_INVALID_PROCESS_ID0)
552 {
553 TargetSP target_sp(FindTargetWithProcessID (pid));
554 if (target_sp.get())
555 {
556 Process* process = target_sp->GetProcessSP().get();
557 if (process)
558 {
559 process->SendAsyncInterrupt();
560 ++num_async_interrupts_sent;
561 }
562 }
563 }
564 else
565 {
566 // We don't have a valid pid to broadcast to, so broadcast to the target
567 // list's async broadcaster...
568 BroadcastEvent (Process::eBroadcastBitInterrupt, NULL__null);
569 }
570
571 return num_async_interrupts_sent;
572}
573
574uint32_t
575TargetList::SignalIfRunning (lldb::pid_t pid, int signo)
576{
577 uint32_t num_signals_sent = 0;
578 Process *process = NULL__null;
579 if (pid == LLDB_INVALID_PROCESS_ID0)
580 {
581 // Signal all processes with signal
582 Mutex::Locker locker(m_target_list_mutex);
583 collection::iterator pos, end = m_target_list.end();
584 for (pos = m_target_list.begin(); pos != end; ++pos)
585 {
586 process = (*pos)->GetProcessSP().get();
587 if (process)
588 {
589 if (process->IsAlive())
590 {
591 ++num_signals_sent;
592 process->Signal (signo);
593 }
594 }
595 }
596 }
597 else
598 {
599 // Signal a specific process with signal
600 TargetSP target_sp(FindTargetWithProcessID (pid));
601 if (target_sp.get())
602 {
603 process = target_sp->GetProcessSP().get();
604 if (process)
605 {
606 if (process->IsAlive())
607 {
608 ++num_signals_sent;
609 process->Signal (signo);
610 }
611 }
612 }
613 }
614 return num_signals_sent;
615}
616
617int
618TargetList::GetNumTargets () const
619{
620 Mutex::Locker locker (m_target_list_mutex);
621 return m_target_list.size();
622}
623
624lldb::TargetSP
625TargetList::GetTargetAtIndex (uint32_t idx) const
626{
627 TargetSP target_sp;
628 Mutex::Locker locker (m_target_list_mutex);
629 if (idx < m_target_list.size())
630 target_sp = m_target_list[idx];
631 return target_sp;
632}
633
634uint32_t
635TargetList::GetIndexOfTarget (lldb::TargetSP target_sp) const
636{
637 Mutex::Locker locker (m_target_list_mutex);
638 size_t num_targets = m_target_list.size();
639 for (size_t idx = 0; idx < num_targets; idx++)
640 {
641 if (target_sp == m_target_list[idx])
642 return idx;
643 }
644 return UINT32_MAX(4294967295U);
645}
646
647uint32_t
648TargetList::SetSelectedTarget (Target* target)
649{
650 Mutex::Locker locker (m_target_list_mutex);
651 collection::const_iterator pos,
652 begin = m_target_list.begin(),
653 end = m_target_list.end();
654 for (pos = begin; pos != end; ++pos)
655 {
656 if (pos->get() == target)
657 {
658 m_selected_target_idx = std::distance (begin, pos);
659 return m_selected_target_idx;
660 }
661 }
662 m_selected_target_idx = 0;
663 return m_selected_target_idx;
664}
665
666lldb::TargetSP
667TargetList::GetSelectedTarget ()
668{
669 Mutex::Locker locker (m_target_list_mutex);
670 if (m_selected_target_idx >= m_target_list.size())
671 m_selected_target_idx = 0;
672 return GetTargetAtIndex (m_selected_target_idx);
673}