diff options
author | Mike Dalessio <mike.dalessio@gmail.com> | 2023-06-07 10:05:04 -0400 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2023-08-10 09:38:11 +0900 |
commit | d2343368ab7e270118ea6baa9c6418bfed83135c (patch) | |
tree | 0e25287d42464b9812033f613234f3baa11c5517 /io.c | |
parent | 984109b8363790723693ec04897b1155d899115f (diff) | |
download | ruby-d2343368ab7e270118ea6baa9c6418bfed83135c.tar.gz |
Deprecate Kernel#open and IO support for subprocess creation/forking
Deprecate Kernel#open and IO support for subprocess creation and
forking. This deprecates subprocess creation and forking in
- Kernel#open
- URI.open
- IO.binread
- IO.foreach
- IO.readlines
- IO.read
- IO.write
This behavior is slated to be removed in Ruby 4.0
[Feature #19630]
Diffstat (limited to 'io.c')
-rw-r--r-- | io.c | 153 |
1 files changed, 12 insertions, 141 deletions
@@ -8109,20 +8109,10 @@ check_pipe_command(VALUE filename_or_command) * open(path, mode = 'r', perm = 0666, **opts) -> io or nil * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj * - * Creates an IO object connected to the given stream, file, or subprocess. + * Creates an IO object connected to the given file. * - * Required string argument +path+ determines which of the following occurs: - * - * - The file at the specified +path+ is opened. - * - The process forks. - * - A subprocess is created. - * - * Each of these is detailed below. - * - * <b>File Opened</b> - - * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>), - * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>. + * This method has potential security vulnerabilities if called with untrusted input; + * see {Command Injection}[rdoc-ref:command_injection.rdoc]. * * With no block given, file stream is returned: * @@ -8139,67 +8129,6 @@ check_pipe_command(VALUE filename_or_command) * * See File.open for details. * - * <b>Process Forked</b> - * - * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks - * and the child process is connected to the parent. - * - * With no block given: - * - * io = open('|-') - * if io - * $stderr.puts "In parent, child pid is #{io.pid}." - * else - * $stderr.puts "In child, pid is #{$$}." - * end - * - * Output: - * - * In parent, child pid is 27903. - * In child, pid is 27903. - * - * With a block given: - * - * open('|-') do |io| - * if io - * $stderr.puts "In parent, child pid is #{io.pid}." - * else - * $stderr.puts "In child, pid is #{$$}." - * end - * end - * - * Output: - * - * In parent, child pid is 28427. - * In child, pid is 28427. - * - * <b>Subprocess Created</b> - * - * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>), - * a new subprocess runs the command; its open stream is returned. - * Note that the command may be processed by shell if it contains - * shell metacharacters. - * - * With no block given: - * - * io = open('|echo "Hi!"') # => #<IO:fd 12> - * print io.gets - * io.close - * - * Output: - * - * "Hi!" - * - * With a block given, calls the block with the stream, then closes the stream: - * - * open('|echo "Hi!"') do |io| - * print io.gets - * end - * - * Output: - * - * "Hi!" - * */ static VALUE @@ -8222,6 +8151,8 @@ rb_f_open(int argc, VALUE *argv, VALUE _) else { VALUE cmd = check_pipe_command(tmp); if (!NIL_P(cmd)) { + // TODO: when removed in 4.0, update command_injection.rdoc + rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen"); argv[0] = cmd; return rb_io_s_popen(argc, argv, rb_cIO); } @@ -8259,6 +8190,8 @@ rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode, { VALUE cmd; if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) { + // TODO: when removed in 4.0, update command_injection.rdoc + rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen"); return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig); } else { @@ -11914,9 +11847,6 @@ io_s_foreach(VALUE v) * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil * IO.foreach(path, limit, **opts) {|line| block } -> nil * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil - * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil - * IO.foreach(command, limit, **opts) {|line| block } -> nil - * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil * IO.foreach(...) -> an_enumerator * * Calls the block with each successive line read from the stream. @@ -11925,16 +11855,7 @@ io_s_foreach(VALUE v) * this method has potential security vulnerabilities if called with untrusted input; * see {Command Injection}[rdoc-ref:command_injection.rdoc]. * - * The first argument must be a string that is one of the following: - * - * - Path: if +self+ is a subclass of \IO (\File, for example), - * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>), - * the string is the path to a file. - * - Command: if +self+ is the class \IO, - * and if the string starts with the pipe character, - * the rest of the string is a command to be executed as a subprocess. - * This usage has potential security vulnerabilities if called with untrusted input; - * see {Command Injection}[rdoc-ref:command_injection.rdoc]. + * The first argument must be a string that is the path to a file. * * With only argument +path+ given, parses lines from the file at the given +path+, * as determined by the default line separator, @@ -12028,9 +11949,6 @@ io_s_readlines(VALUE v) /* * call-seq: - * IO.readlines(command, sep = $/, **opts) -> array - * IO.readlines(command, limit, **opts) -> array - * IO.readlines(command, sep, limit, **opts) -> array * IO.readlines(path, sep = $/, **opts) -> array * IO.readlines(path, limit, **opts) -> array * IO.readlines(path, sep, limit, **opts) -> array @@ -12041,19 +11959,7 @@ io_s_readlines(VALUE v) * this method has potential security vulnerabilities if called with untrusted input; * see {Command Injection}[rdoc-ref:command_injection.rdoc]. * - * The first argument must be a string; - * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): - * - * - If so (and if +self+ is \IO), - * the rest of the string is a command to be executed as a subprocess. - * - Otherwise, the string is the path to a file. - * - * With only argument +command+ given, executes the command in a shell, - * parses its $stdout into lines, as determined by the default line separator, - * and returns those lines in an array: - * - * IO.readlines('| cat t.txt') - * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"] + * The first argument must be a string that is the path to a file. * * With only argument +path+ given, parses lines from the file at the given +path+, * as determined by the default line separator, @@ -12062,8 +11968,6 @@ io_s_readlines(VALUE v) * IO.readlines('t.txt') * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"] * - * For both forms, command and path, the remaining arguments are the same. - * * With argument +sep+ given, parses lines as determined by that line separator * (see {Line Separator}[rdoc-ref:IO@Line+Separator]): * @@ -12136,7 +12040,6 @@ seek_before_access(VALUE argp) /* * call-seq: - * IO.read(command, length = nil, offset = 0, **opts) -> string or nil * IO.read(path, length = nil, offset = 0, **opts) -> string or nil * * Opens the stream, reads and returns some or all of its content, @@ -12146,18 +12049,7 @@ seek_before_access(VALUE argp) * this method has potential security vulnerabilities if called with untrusted input; * see {Command Injection}[rdoc-ref:command_injection.rdoc]. * - * The first argument must be a string; - * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): - * - * - If so (and if +self+ is \IO), - * the rest of the string is a command to be executed as a subprocess. - * - Otherwise, the string is the path to a file. - * - * With only argument +command+ given, executes the command in a shell, - * returns its entire $stdout: - * - * IO.read('| cat t.txt') - * # => "First line\nSecond line\n\nThird line\nFourth line\n" + * The first argument must be a string that is the path to a file. * * With only argument +path+ given, reads in text mode and returns the entire content * of the file at the given path: @@ -12169,8 +12061,6 @@ seek_before_access(VALUE argp) * unread when encountering certain special bytes. Consider using * IO.binread if all bytes in the file should be read. * - * For both forms, command and path, the remaining arguments are the same. - * * With argument +length+, returns +length+ bytes if available: * * IO.read('t.txt', 7) # => "First l" @@ -12221,7 +12111,6 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io) /* * call-seq: - * IO.binread(command, length = nil, offset = 0) -> string or nil * IO.binread(path, length = nil, offset = 0) -> string or nil * * Behaves like IO.read, except that the stream is opened in binary mode @@ -12326,7 +12215,6 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary) /* * call-seq: - * IO.write(command, data, **opts) -> integer * IO.write(path, data, offset = 0, **opts) -> integer * * Opens the stream, writes the given +data+ to it, @@ -12336,25 +12224,9 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary) * this method has potential security vulnerabilities if called with untrusted input; * see {Command Injection}[rdoc-ref:command_injection.rdoc]. * - * The first argument must be a string; - * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>): - * - * - If so (and if +self+ is \IO), - * the rest of the string is a command to be executed as a subprocess. - * - Otherwise, the string is the path to a file. - * - * With argument +command+ given, executes the command in a shell, - * passes +data+ through standard input, writes its output to $stdout, - * and returns the length of the given +data+: - * - * IO.write('| cat', 'Hello World!') # => 12 - * - * Output: - * - * Hello World! + * The first argument must be a string that is the path to a file. * - * With argument +path+ given, writes the given +data+ to the file - * at that path: + * With only argument +path+ given, writes the given +data+ to the file at that path: * * IO.write('t.tmp', 'abc') # => 3 * File.read('t.tmp') # => "abc" @@ -12393,7 +12265,6 @@ rb_io_s_write(int argc, VALUE *argv, VALUE io) /* * call-seq: - * IO.binwrite(command, string, offset = 0) -> integer * IO.binwrite(path, string, offset = 0) -> integer * * Behaves like IO.write, except that the stream is opened in binary mode |