fix: hard crash on invalid command line switches (#46004)

* fix: hard crash on invalid command line switch

* Update docs/api/command-line.md

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

* chore: feedback from review

* docs: Add breaking change note

---------

Co-authored-by: Niklas Wenzel <dev@nikwen.de>
This commit is contained in:
Shelley Vohr 2025-03-26 14:14:03 +01:00 committed by GitHub
parent 8412d78310
commit d2c2261c58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 75 additions and 16 deletions

View file

@ -20,45 +20,87 @@ document.
#### `commandLine.appendSwitch(switch[, value])` #### `commandLine.appendSwitch(switch[, value])`
* `switch` string - A command-line switch, without the leading `--` * `switch` string - A command-line switch, without the leading `--`.
* `value` string (optional) - A value for the given switch * `value` string (optional) - A value for the given switch.
Append a switch (with optional `value`) to Chromium's command line. Append a switch (with optional `value`) to Chromium's command line.
**Note:** This will not affect `process.argv`. The intended usage of this function is to **Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior. control Chromium's behavior.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
```
#### `commandLine.appendArgument(value)` #### `commandLine.appendArgument(value)`
* `value` string - The argument to append to the command line * `value` string - The argument to append to the command line.
Append an argument to Chromium's command line. The argument will be quoted Append an argument to Chromium's command line. The argument will be quoted
correctly. Switches will precede arguments regardless of appending order. correctly. Switches will precede arguments regardless of appending order.
If you're appending an argument like `--switch=value`, consider using `appendSwitch('switch', 'value')` instead. If you're appending an argument like `--switch=value`, consider using `appendSwitch('switch', 'value')` instead.
```js
const { app } = require('electron')
app.commandLine.appendArgument('--enable-experimental-web-platform-features')
```
**Note:** This will not affect `process.argv`. The intended usage of this function is to **Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior. control Chromium's behavior.
#### `commandLine.hasSwitch(switch)` #### `commandLine.hasSwitch(switch)`
* `switch` string - A command-line switch * `switch` string - A command-line switch.
Returns `boolean` - Whether the command-line switch is present. Returns `boolean` - Whether the command-line switch is present.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
const hasPort = app.commandLine.hasSwitch('remote-debugging-port')
console.log(hasPort) // true
```
#### `commandLine.getSwitchValue(switch)` #### `commandLine.getSwitchValue(switch)`
* `switch` string - A command-line switch * `switch` string - A command-line switch.
Returns `string` - The command-line switch value. Returns `string` - The command-line switch value.
This function is meant to obtain Chromium command line switches. It is not
meant to be used for application-specific command line arguments. For the
latter, please use `process.argv`.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
const portValue = app.commandLine.getSwitchValue('remote-debugging-port')
console.log(portValue) // '8315'
```
**Note:** When the switch is not present or has no value, it returns empty string. **Note:** When the switch is not present or has no value, it returns empty string.
#### `commandLine.removeSwitch(switch)` #### `commandLine.removeSwitch(switch)`
* `switch` string - A command-line switch * `switch` string - A command-line switch.
Removes the specified switch from Chromium's command line. Removes the specified switch from Chromium's command line.
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
console.log(app.commandLine.hasSwitch('remote-debugging-port')) // true
app.commandLine.removeSwitch('remote-debugging-port')
console.log(app.commandLine.hasSwitch('remote-debugging-port')) // false
```
**Note:** This will not affect `process.argv`. The intended usage of this function is to **Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior. control Chromium's behavior.

View file

@ -19,6 +19,14 @@ This document uses the following convention to categorize breaking changes:
`BrowserWindow.IsVisibleOnAllWorkspaces()` will now return false on Linux if the `BrowserWindow.IsVisibleOnAllWorkspaces()` will now return false on Linux if the
window is not currently visible. window is not currently visible.
### Behavior Changes: `app.commandLine`
`app.commandLine` will convert upper-cases switches and arguments to lowercase.
`app.commandLine` was only meant to handle chromium switches (which aren't case-sensitive) and switches passed via `app.commandLine` will not be passed down to any of the child processes.
If you were using `app.commandLine` to control the behavior of the main process, you should do this via `process.argv`.
## Planned Breaking API Changes (36.0) ## Planned Breaking API Changes (36.0)
### Utility Process unhandled rejection behavior change ### Utility Process unhandled rejection behavior change

View file

@ -4,50 +4,59 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/network_switches.h"
#include "shell/common/gin_converters/base_converter.h" #include "shell/common/gin_converters/base_converter.h"
#include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"
#include "third_party/abseil-cpp/absl/strings/ascii.h"
namespace { namespace {
bool HasSwitch(const std::string& switch_string) {
auto switch_str = base::ToLowerASCII(switch_string);
bool HasSwitch(const std::string& name) { auto* command_line = base::CommandLine::ForCurrentProcess();
return base::CommandLine::ForCurrentProcess()->HasSwitch(name); return command_line->HasSwitch(switch_str);
} }
base::CommandLine::StringType GetSwitchValue(const std::string& name) { base::CommandLine::StringType GetSwitchValue(gin_helper::ErrorThrower thrower,
return base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(name); const std::string& switch_string) {
auto switch_str = base::ToLowerASCII(switch_string);
auto* command_line = base::CommandLine::ForCurrentProcess();
return command_line->GetSwitchValueNative(switch_str);
} }
void AppendSwitch(const std::string& switch_string, void AppendSwitch(const std::string& switch_string,
gin_helper::Arguments* args) { gin_helper::Arguments* args) {
auto switch_str = base::ToLowerASCII(switch_string);
auto* command_line = base::CommandLine::ForCurrentProcess(); auto* command_line = base::CommandLine::ForCurrentProcess();
if (base::EndsWith(switch_string, "-path", if (base::EndsWith(switch_string, "-path",
base::CompareCase::INSENSITIVE_ASCII) || base::CompareCase::INSENSITIVE_ASCII) ||
switch_string == network::switches::kLogNetLog) { switch_string == network::switches::kLogNetLog) {
base::FilePath path; base::FilePath path;
args->GetNext(&path); args->GetNext(&path);
command_line->AppendSwitchPath(switch_string, path); command_line->AppendSwitchPath(switch_str, path);
return; return;
} }
base::CommandLine::StringType value; base::CommandLine::StringType value;
if (args->GetNext(&value)) if (args->GetNext(&value))
command_line->AppendSwitchNative(switch_string, value); command_line->AppendSwitchNative(switch_str, value);
else else
command_line->AppendSwitch(switch_string); command_line->AppendSwitch(switch_str);
} }
void RemoveSwitch(const std::string& switch_string) { void RemoveSwitch(const std::string& switch_string) {
auto switch_str = base::ToLowerASCII(switch_string);
auto* command_line = base::CommandLine::ForCurrentProcess(); auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->RemoveSwitch(switch_string); command_line->RemoveSwitch(switch_str);
} }
void AppendArg(const std::string& arg) { void AppendArg(const std::string& arg) {
auto* command_line = base::CommandLine::ForCurrentProcess(); auto* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendArg(arg); command_line->AppendArg(arg);
} }