Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb-dap] Fix: disableASLR launch argument not working. #129753

Merged

Conversation

da-viper
Copy link
Contributor

@da-viper da-viper commented Mar 4, 2025

Fixes #94338

disable_aslr.mp4

i used pidof a.out | xargs pmap to show the memory map of the binary

@llvmbot
Copy link
Member

llvmbot commented Mar 4, 2025

@llvm/pr-subscribers-lldb

Author: None (Da-Viper)

Changes

Fixes #94338

disable_aslr.mp4

i used pidof a.out | xargs pmap to show the memory map of the binary


Full diff: https://github.com/llvm/llvm-project/pull/129753.diff

1 Files Affected:

  • (modified) lldb/tools/lldb-dap/Handler/RequestHandler.cpp (+3)
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 606ada90ce2e5..f56821ec03e27 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -175,6 +175,9 @@ RequestHandler::LaunchProcess(const llvm::json::Object &request) const {
 
   if (GetBoolean(arguments, "disableASLR", true))
     flags |= lldb::eLaunchFlagDisableASLR;
+  else
+    flags &= ~lldb::eLaunchFlagDisableASLR;
+
   if (GetBoolean(arguments, "disableSTDIO", false))
     flags |= lldb::eLaunchFlagDisableSTDIO;
   if (GetBoolean(arguments, "shellExpandArguments", false))

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to suggest two improvements:

  1. Add an overload to GetBoolean that returns an std::optional<bool> so we know if the value was not set, or explicitly set to true or false.
  2. Have a helper that does the same thing for all the flags: set or clear it depending on whether the value was set, or do nothing if it wasn't set.

WDYT?

@da-viper
Copy link
Contributor Author

da-viper commented Mar 4, 2025

I'd like to suggest two improvements:

  1. Add an overload to GetBoolean that returns an std::optional<bool> so we know if the value was not set, or explicitly set to true or false.
  2. Have a helper that does the same thing for all the flags: set or clear it depending on whether the value was set, or do nothing if it wasn't set.

WDYT?

  1. I am not sure if it is useful since the boolean will have to be either true or false.

  2. Will the helper functions be scoped to the RequestHandler.cpp class and be something like

   SetMask(uint32_t &flags, LaunchInfo mask);
   ClearMask(uint32_t &flags, LaunchInfo mask);

@JDevlieghere
Copy link
Member

JDevlieghere commented Mar 4, 2025

  1. I am not sure if it is useful since the boolean will have to be either true or false.

Okay, just to confirm, you're saying that's it's not possible for these values not to be set?

  1. Will the helper functions be scoped to the RequestHandler.cpp class and be something like

I was thinking something like:

SetLaunchFlag(llvm::StringRef key, uint32_t flag, bool default) {
    if (GetBoolean(arguments, key, default))
     flags |= flag;
   else
     flags &= ~flag;
}
// Used like this:
SetLaunchFlag("disableASLR", lldb::eLaunchFlagDisableASLR, true);
SetLaunchFlag("disableSTDIO", lldb::eLaunchFlagDisableSTDIO, false);

Edit: this could probably be a lambda.

@da-viper
Copy link
Contributor Author

da-viper commented Mar 4, 2025

Okay, just to confirm, you're saying that's it's not possible for these values not to be set?

Yes because lldb has default values for all its settings. using settings show ....
Also internally when fetching a value for the first time it uses a predefined default if it is not set.

see

def DisableASLR: Property<"disable-aslr", "Boolean">,
DefaultTrue,
Desc<"Disable Address Space Layout Randomization (ASLR)">;

@walter-erquinigo
Copy link
Member

I kind of agree with Jonas' initial remark. Wouldn't it be better to conceptually have something like this:

if (HasBoolean(arguments, key)) {
  if (GetBoolean(arguments, key))
     flags |= flag;
   else
     flags &= ~flag;
}

that way you can let LLDB set the flag value on its own. An interesting case when this might be useful is if one of the initCommands sets the default value for this setting, then you don't want to change this unless the disableASLR field in the debug config is set explicitly

@da-viper
Copy link
Contributor Author

da-viper commented Mar 4, 2025

Alright.

One more thing if it is better to return a flag from function or pass a reference.

static setLaunchFlag(uint32_t &flags, const llvm::json::Object *obj,
                              llvm::StringRef key, lldb::LaunchFlags mask,
                              bool default_value) {
  if (HasBoolean(obj, key))
    if (GetBoolean(obj, key, default_value))
      flags |= mask;
    else
      flags &= ~mask;
}

setLaunchFlag(flags, arguments, "disableASLR",
                        lldb::eLaunchFlagDisableASLR, false);

vs

static uint32_t setLaunchFlag(uint32_t flags, const llvm::json::Object *obj,
                              llvm::StringRef key, lldb::LaunchFlags mask,
                              bool default_value) {
  if (HasBoolean(obj, key))
    if (GetBoolean(obj, key, default_value))
      flags |= mask;
    else
      flags &= ~mask;

  return flags;
}

flags = setLaunchFlag(flags, arguments, "disableASLR",
                        lldb::eLaunchFlagDisableASLR, false);

@JDevlieghere
Copy link
Member

I don't think we need to have both the HasBoolean and GetBoolean. I think we should rewrite GetBoolean from this:

bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
                bool fail_value) {
  if (auto value = obj.getBoolean(key))
    return *value;
  if (auto value = obj.getInteger(key))
    return *value != 0;
  return fail_value;
}

to this:

std::optional<bool> GetBoolean(const llvm::json::Object &obj, llvm::StringRef key) {
    if (auto value = obj.getBoolean(key))
    return *value;
  if (auto value = obj.getInteger(key))
    return *value != 0;
  return std::nullopt;
}

All existing uses of GetBoolean(obj, key, fail_value) can be rewritten as GetBoolean(obj, key).value_or(fail_value).

FWIW this applies to all the GetFoo helpers in JSONUtils.cpp, but obviously that should be a separate PR and I'm not trying to sign up for that work. I think we can add the overload for GetBoolean as part of this PR and cleanup the rest in another one.

@walter-erquinigo
Copy link
Member

Oh yes, I completely agree with std::optional<bool> being the best choice. My example was just something conceptual and easy to read.
And indeed, as you say, all the fields should return an optional because the client just sends a blob of JSON and you can't make any guarantees on whether it makes sense or not.

Copy link
Member

@walter-erquinigo walter-erquinigo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requesting changes given the existing discussion

@JDevlieghere
Copy link
Member

#129818

JDevlieghere added a commit that referenced this pull request Mar 5, 2025
Return a std::optional<bool> from GetBoolean so you can distinguish
between the value not being present and it being explicitly set to true
or false. All existing uses are replaced by calling
`value_or(fail_value`).

Motivated by #129753
@da-viper da-viper force-pushed the fix-disableAslr-launchArgument#94338 branch from 22aede0 to 2f773de Compare March 5, 2025 10:35
@da-viper
Copy link
Contributor Author

da-viper commented Mar 5, 2025

Different timezone, updated the commit with the new changes.

Comment on lines 34 to 43
static uint32_t SetLaunchFlag(uint32_t flags, const llvm::json::Object *obj,
llvm::StringRef key, lldb::LaunchFlags mask,
bool default_value) {
if (GetBoolean(obj, key).value_or(default_value))
flags |= mask;
else
flags &= ~mask;

return flags;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still doesn't distinguish between the value not being set and the value being set to true or false. Here's what I was suggesting:

Suggested change
static uint32_t SetLaunchFlag(uint32_t flags, const llvm::json::Object *obj,
llvm::StringRef key, lldb::LaunchFlags mask,
bool default_value) {
if (GetBoolean(obj, key).value_or(default_value))
flags |= mask;
else
flags &= ~mask;
return flags;
}
static uint32_t SetLaunchFlag(uint32_t flags, const llvm::json::Object *obj,
llvm::StringRef key, lldb::LaunchFlags mask) {
if (auto b = GetBoolean(obj, key)) {
if (*b)
flags |= mask;
else
flags &= ~mask;
}
return flags;
}

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for bearing with me.

@JDevlieghere JDevlieghere merged commit 5d8b4ea into llvm:main Mar 5, 2025
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

LLDB-DAP in VSC doesn't respect "disableASLR": false unless you also do settings set target.disable-aslr false
4 participants