Index: examples/plugins/commands/fooplugin.cpp =================================================================== --- examples/plugins/commands/fooplugin.cpp +++ examples/plugins/commands/fooplugin.cpp @@ -25,8 +25,8 @@ class ChildCommand : public lldb::SBCommandPluginInterface { public: - virtual bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { + bool DoExecute(lldb::SBDebugger debugger, const char **command, + lldb::SBCommandReturnObject &result) override { if (command) { const char *arg = *command; while (arg) { Index: include/lldb/API/SBCommandInterpreter.h =================================================================== --- include/lldb/API/SBCommandInterpreter.h +++ include/lldb/API/SBCommandInterpreter.h @@ -233,7 +233,8 @@ public: virtual ~SBCommandPluginInterface() = default; - virtual bool DoExecute(lldb::SBDebugger /*debugger*/, char ** /*command*/, + virtual bool DoExecute(lldb::SBDebugger /*debugger*/, + const char ** /*command*/, lldb::SBCommandReturnObject & /*result*/) { return false; } Index: include/lldb/Host/OptionParser.h =================================================================== --- include/lldb/Host/OptionParser.h +++ include/lldb/Host/OptionParser.h @@ -36,7 +36,7 @@ static void EnableError(bool error); - static int Parse(int argc, char *const argv[], const char *optstring, + static int Parse(int argc, char const *const argv[], const char *optstring, const Option *longopts, int *longindex); static char *GetOptionArgument(); Index: include/lldb/Interpreter/Args.h =================================================================== --- include/lldb/Interpreter/Args.h +++ include/lldb/Interpreter/Args.h @@ -18,7 +18,9 @@ #include // Other libraries and framework includes +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" + // Project includes #include "lldb/Core/Error.h" #include "lldb/Host/OptionParser.h" @@ -146,26 +148,15 @@ /// \endcode /// /// @return - /// An array of NULL terminated C string argument pointers that - /// also has a terminating NULL C string pointer + /// A vector of NULL terminated C string argument pointers with + /// an equivalent in-memory layout to that of a C-style argv + /// array. Calling .size() on the return value produces the same + /// value as one would pass for argc, and calling .data() on the + /// return value is guaranteed to be null terminated (even though + /// the terminating null is not part of the vector, and as such + /// is not taken into consideration when calling .size()). //------------------------------------------------------------------ - char **GetArgumentVector(); - - //------------------------------------------------------------------ - /// Gets the argument vector. - /// - /// The value returned by this function can be used by any function - /// that takes and vector. The return value is just like \a argv - /// in the standard C entry point function: - /// \code - /// int main (int argc, const char **argv); - /// \endcode - /// - /// @return - /// An array of NULL terminate C string argument pointers that - /// also has a terminating NULL C string pointer - //------------------------------------------------------------------ - const char **GetConstArgumentVector() const; + std::vector GetArgumentVector() const; //------------------------------------------------------------------ /// Appends a new argument to the end of the list argument list. @@ -183,52 +174,7 @@ char quote_char = '\0'); void AppendArguments(const Args &rhs); - - void AppendArguments(const char **argv); - - // Delete const char* versions of StringRef functions. Normally this would - // not be necessary, as const char * is implicitly convertible to StringRef. - // However, since the use of const char* is so pervasive, and since StringRef - // will assert if you try to construct one from nullptr, this allows the - // compiler to catch instances of the function being invoked with a - // const char *, allowing us to replace them with explicit conversions at each - // call-site. This ensures that no callsites slip through the cracks where - // we would be trying to implicitly convert from nullptr, since it will force - // us to evaluate and explicitly convert each one. - // - // Once StringRef use becomes more pervasive, there will be fewer - // implicit conversions because we will be using StringRefs across the whole - // pipeline, so we won't have to have this "glue" that converts between the - // two, and at that point it becomes easy to just make sure you don't pass - // nullptr into the function on the odd occasion that you do pass a - // const char *. - // Call-site fixing methodology: - // 1. If you know the string cannot be null (e.g. it's a const char[], or - // it's been checked for null), use llvm::StringRef(ptr). - // 2. If you don't know if it can be null (e.g. it's returned from a - // function whose semantics are unclear), use - // llvm::StringRef::withNullAsEmpty(ptr). - // 3. If it's .c_str() of a std::string, just pass the std::string directly. - // 4. If it's .str().c_str() of a StringRef, just pass the StringRef - // directly. - void ReplaceArgumentAtIndex(size_t, const char *, char = '\0') = delete; - void AppendArgument(const char *arg_str, char quote_char = '\0') = delete; - void InsertArgumentAtIndex(size_t, const char *, char = '\0') = delete; - static bool StringToBoolean(const char *, bool, bool *) = delete; - static lldb::ScriptLanguage - StringToScriptLanguage(const char *, lldb::ScriptLanguage, bool *) = delete; - static lldb::Encoding - StringToEncoding(const char *, - lldb::Encoding = lldb::eEncodingInvalid) = delete; - static uint32_t StringToGenericRegister(const char *) = delete; - static bool StringToVersion(const char *, uint32_t &, uint32_t &, - uint32_t &) = delete; - const char *Unshift(const char *, char = '\0') = delete; - void AddOrReplaceEnvironmentVariable(const char *, const char *) = delete; - bool ContainsEnvironmentVariable(const char *, - size_t * = nullptr) const = delete; - static int64_t StringToOptionEnum(const char *, OptionEnumValueElement *, - int32_t, Error &) = delete; + void AppendArguments(llvm::ArrayRef args); //------------------------------------------------------------------ /// Insert the argument value at index \a idx to \a arg_cstr. @@ -287,9 +233,8 @@ // // FIXME: Handle the quote character somehow. //------------------------------------------------------------------ - void SetArguments(size_t argc, const char **argv); - - void SetArguments(const char **argv); + void SetArguments(llvm::ArrayRef args); + void SetArguments(const Args &other); //------------------------------------------------------------------ /// Shifts the first argument C string value of the array off the @@ -413,6 +358,8 @@ OptionEnumValueElement *enum_values, int32_t fail_value, Error &error); + static llvm::ArrayRef ArgvToArrayRef(const char **args); + static lldb::ScriptLanguage StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr); @@ -497,16 +444,12 @@ //------------------------------------------------------------------ // Classes that inherit from Args can see and modify these //------------------------------------------------------------------ - typedef std::list arg_sstr_collection; - typedef std::vector arg_cstr_collection; + typedef std::vector arg_sstr_collection; typedef std::vector arg_quote_char_collection; arg_sstr_collection m_args; - arg_cstr_collection m_argv; ///< The current argument vector. arg_quote_char_collection m_args_quote_char; - void UpdateArgsAfterOptionParsing(); - - void UpdateArgvFromArgs(); + void UpdateArgsAfterOptionParsing(llvm::ArrayRef new_argv); llvm::StringRef ParseSingleArgument(llvm::StringRef command); }; Index: source/API/SBCommandInterpreter.cpp =================================================================== --- source/API/SBCommandInterpreter.cpp +++ source/API/SBCommandInterpreter.cpp @@ -115,8 +115,8 @@ SBCommandReturnObject sb_return(&result); SBCommandInterpreter sb_interpreter(&m_interpreter); SBDebugger debugger_sb(m_interpreter.GetDebugger().shared_from_this()); - bool ret = m_backend->DoExecute( - debugger_sb, (char **)command.GetArgumentVector(), sb_return); + auto argv = command.GetArgumentVector(); + bool ret = m_backend->DoExecute(debugger_sb, &argv[0], sb_return); sb_return.Release(); return ret; } Index: source/API/SBLaunchInfo.cpp =================================================================== --- source/API/SBLaunchInfo.cpp +++ source/API/SBLaunchInfo.cpp @@ -19,8 +19,9 @@ SBLaunchInfo::SBLaunchInfo(const char **argv) : m_opaque_sp(new ProcessLaunchInfo()) { m_opaque_sp->GetFlags().Reset(eLaunchFlagDebug | eLaunchFlagDisableASLR); - if (argv && argv[0]) - m_opaque_sp->GetArguments().SetArguments(argv); + if (argv) { + m_opaque_sp->GetArguments().SetArguments(Args::ArgvToArrayRef(argv)); + } } SBLaunchInfo::~SBLaunchInfo() {} @@ -71,15 +72,11 @@ } void SBLaunchInfo::SetArguments(const char **argv, bool append) { - if (append) { - if (argv) - m_opaque_sp->GetArguments().AppendArguments(argv); - } else { - if (argv) - m_opaque_sp->GetArguments().SetArguments(argv); - else - m_opaque_sp->GetArguments().Clear(); - } + if (!append) + m_opaque_sp->GetArguments().Clear(); + + if (argv) + m_opaque_sp->GetArguments().AppendArguments(Args::ArgvToArrayRef(argv)); } uint32_t SBLaunchInfo::GetNumEnvironmentEntries() { @@ -91,15 +88,12 @@ } void SBLaunchInfo::SetEnvironmentEntries(const char **envp, bool append) { - if (append) { - if (envp) - m_opaque_sp->GetEnvironmentEntries().AppendArguments(envp); - } else { - if (envp) - m_opaque_sp->GetEnvironmentEntries().SetArguments(envp); - else - m_opaque_sp->GetEnvironmentEntries().Clear(); - } + if (!append) + m_opaque_sp->GetEnvironmentEntries().Clear(); + + if (envp) + m_opaque_sp->GetEnvironmentEntries().AppendArguments( + Args::ArgvToArrayRef(envp)); } void SBLaunchInfo::Clear() { m_opaque_sp->Clear(); } Index: source/API/SBProcess.cpp =================================================================== --- source/API/SBProcess.cpp +++ source/API/SBProcess.cpp @@ -136,9 +136,10 @@ if (exe_module) launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); if (argv) - launch_info.GetArguments().AppendArguments(argv); + launch_info.GetArguments().AppendArguments(Args::ArgvToArrayRef(argv)); if (envp) - launch_info.GetEnvironmentEntries().SetArguments(envp); + launch_info.GetEnvironmentEntries().SetArguments( + Args::ArgvToArrayRef(envp)); error.SetError(process_sp->Launch(launch_info)); } else { error.SetErrorString("must be in eStateConnected to call RemoteLaunch"); Index: source/API/SBTarget.cpp =================================================================== --- source/API/SBTarget.cpp +++ source/API/SBTarget.cpp @@ -287,9 +287,10 @@ if (exe_module) launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); if (argv) - launch_info.GetArguments().AppendArguments(argv); + launch_info.GetArguments().AppendArguments(Args::ArgvToArrayRef(argv)); if (envp) - launch_info.GetEnvironmentEntries().SetArguments(envp); + launch_info.GetEnvironmentEntries().SetArguments( + Args::ArgvToArrayRef(envp)); if (listener.IsValid()) launch_info.SetListener(listener.GetSP()); Index: source/Commands/CommandObjectBreakpoint.cpp =================================================================== --- source/Commands/CommandObjectBreakpoint.cpp +++ source/Commands/CommandObjectBreakpoint.cpp @@ -2423,8 +2423,8 @@ // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual // BreakpointIDList: - valid_ids->InsertStringArray(temp_args.GetConstArgumentVector(), - temp_args.GetArgumentCount(), result); + auto argv = temp_args.GetArgumentVector(); + valid_ids->InsertStringArray(&argv[0], temp_args.GetArgumentCount(), result); // At this point, all of the breakpoint ids that the user passed in have been // converted to breakpoint IDs Index: source/Commands/CommandObjectLog.cpp =================================================================== --- source/Commands/CommandObjectLog.cpp +++ source/Commands/CommandObjectLog.cpp @@ -190,9 +190,10 @@ m_options.log_file.GetPath(log_file, sizeof(log_file)); else log_file[0] = '\0'; + auto argv = args.GetArgumentVector(); bool success = m_interpreter.GetDebugger().EnableLog( - channel.c_str(), args.GetConstArgumentVector(), log_file, - m_options.log_options, result.GetErrorStream()); + channel.c_str(), &argv[0], log_file, m_options.log_options, + result.GetErrorStream()); if (success) result.SetStatus(eReturnStatusSuccessFinishNoResult); else @@ -250,18 +251,18 @@ std::string channel(args.GetArgumentAtIndex(0)); args.Shift(); // Shift off the channel + auto argv = args.GetArgumentVector(); + if (Log::GetLogChannelCallbacks(ConstString(channel.c_str()), log_callbacks)) { - log_callbacks.disable(args.GetConstArgumentVector(), - &result.GetErrorStream()); + log_callbacks.disable(&argv[0], &result.GetErrorStream()); result.SetStatus(eReturnStatusSuccessFinishNoResult); } else if (channel == "all") { Log::DisableAllLogChannels(&result.GetErrorStream()); } else { LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.c_str())); if (log_channel_sp) { - log_channel_sp->Disable(args.GetConstArgumentVector(), - &result.GetErrorStream()); + log_channel_sp->Disable(&argv[0], &result.GetErrorStream()); result.SetStatus(eReturnStatusSuccessFinishNoResult); } else result.AppendErrorWithFormat("Invalid log channel '%s'.\n", Index: source/Host/common/OptionParser.cpp =================================================================== --- source/Host/common/OptionParser.cpp +++ source/Host/common/OptionParser.cpp @@ -28,8 +28,9 @@ void OptionParser::EnableError(bool error) { opterr = error ? 1 : 0; } -int OptionParser::Parse(int argc, char *const argv[], const char *optstring, - const Option *longopts, int *longindex) { +int OptionParser::Parse(int argc, char const *const argv[], + const char *optstring, const Option *longopts, + int *longindex) { std::vector