Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions core/src/main/java/org/jruby/RubyGlobal.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public static void createGlobals(Ruby runtime) {
runtime.defineVariable(new BacktraceGlobalVariable(runtime, "$@"), THREAD);

initSTDIO(runtime, globals);

runtime.defineVariable(new LoadedFeatures(runtime, "$\""), GLOBAL);
runtime.defineVariable(new LoadedFeatures(runtime, "$LOADED_FEATURES"), GLOBAL);

Expand Down Expand Up @@ -431,6 +431,9 @@ public CaseInsensitiveStringOnlyRubyHash(Ruby runtime, Map<RubyString, RubyStrin
public IRubyObject op_aref(ThreadContext context, IRubyObject arg) {
IRubyObject key = arg.convertToString();
IRubyObject value = internalGet(key);

EnvStringValidation.ensureValidEnvString(context.runtime, key, "key");

if (value == null) return context.nil;

RubyString string = (RubyString) newName(context, key, value);
Expand All @@ -450,11 +453,35 @@ public IRubyObject freeze(ThreadContext context) {

@JRubyMethod(name = "assoc")
public IRubyObject assoc(final ThreadContext context, IRubyObject obj) {
return super.assoc(context, verifyStringLike(context, obj).convertToString());
RubyString expected = verifyStringLike(context, obj).convertToString();
EnvStringValidation.ensureValidEnvString(context.getRuntime(), obj, "value");

return super.assoc(context, expected);
}

@JRubyMethod(name = "fetch", required = 1, optional = 2)
public IRubyObject fetch(ThreadContext context, IRubyObject[] args, Block block) {
EnvStringValidation.ensureValidEnvString(context.runtime, args[0], "key");

switch(args.length) {
case 1: return super.fetch(context, args[0], block);
case 2: return super.fetch(context, args[0], args[1], block);
}

return null;
}

@JRubyMethod(name = "fetch", required = 1)
public IRubyObject fetch(ThreadContext context, IRubyObject key, Block block) {
EnvStringValidation.ensureValidEnvString(context.getRuntime(), key, "key");

return super.fetch(context, verifyStringLike(context, key.convertToString()), block);
}

@JRubyMethod
public IRubyObject delete(ThreadContext context, IRubyObject key, Block block) {
EnvStringValidation.ensureValidEnvString(context.getRuntime(), key, "key");

return super.delete(context, verifyStringLike(context, key), block);
}

Expand Down Expand Up @@ -488,13 +515,19 @@ public IRubyObject rassoc(final ThreadContext context, IRubyObject obj) {

@JRubyMethod(name = {"has_key?", "key?", "include?", "member?"})
public RubyBoolean has_key_p(ThreadContext context, IRubyObject key) {
return internalGetEntry(verifyStringLike(context, key)) == NO_ENTRY ? context.fals : context.tru;
IRubyObject expected = verifyStringLike(context, key);

EnvStringValidation.ensureValidEnvString(context.runtime, key, "key");

return internalGetEntry(expected) == NO_ENTRY ? context.fals : context.tru;
}

@JRubyMethod(name = {"has_value?", "value?"})
public IRubyObject has_value_pp(ThreadContext context, IRubyObject expected) {
if (!isStringLike(expected)) return context.nil;

EnvStringValidation.ensureValidEnvString(context.runtime, expected, "value");

return super.has_value_p(context, expected.convertToString());
}

Expand Down Expand Up @@ -720,6 +753,9 @@ private IRubyObject case_aware_op_aset(ThreadContext context, IRubyObject key, f
if (valueAsStr == context.nil) {
synchronized (Object.class) { posix.unsetenv(keyAsJava); }
} else {
EnvStringValidation.ensureValidEnvString(context.getRuntime(), value, "value");
EnvStringValidation.ensureValidEnvString(context.getRuntime(), key, "key");

final String valueAsJava = valueAsStr.asJavaString();
synchronized (Object.class) { posix.setenv(keyAsJava, valueAsJava, 1); }
}
Expand Down Expand Up @@ -1245,4 +1281,18 @@ public IRubyObject setValue(IRubyObject newValue) {
"$.", "$INPUT_LINE_NUMBER", // ARGF current line number
"$FILENAME" // ARGF current file name
));

private static class EnvStringValidation {
public static void ensureValidEnvString(Ruby runtime, IRubyObject str, String type) {
RubyString value = str.asString();

if(!value.getByteList().getEncoding().isAsciiCompatible()){
throw runtime.newArgumentError("bad environment variable " + type + ": ASCII incompatible encoding: " + value.getByteList().getEncoding().toString());
}

if (value.toString().contains("\0")) {
throw runtime.newArgumentError("bad environment variable " + type + ": contains null byte");
}
}
}
}
7 changes: 0 additions & 7 deletions test/mri/excludes/TestEnv.rb

This file was deleted.