Skip to content

Commit cf50df8

Browse files
committed
Raise EncodingError at parse time for a Hash literal with invalid Symbol key
1 parent 290aac3 commit cf50df8

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Compatibility:
7070
* Fix `IO#write` and support multiple arguments with different encodings (#2829, @andrykonchin).
7171
* Fix `Array` methods `reject`, `reject!`, `inject`, `map`, `select`, `each_index` and handle a case when array is modified by a passed block like CRuby does (#2822, andrykonchin, @eregon).
7272
* Fix `EncodingError` exception message when Symbol has invalid encoding (#2850, @andrykonchin).
73+
* Raise `EncodingError` at parse time when Hash literal contains a Symbol key with invalid encoding (#2848, @andrykonchin).
7374

7475
Performance:
7576

spec/ruby/language/hash_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ def h.to_hash; {:b => 2, :c => 3}; end
177177
utf8_hash.keys.first.should == usascii_hash.keys.first
178178
usascii_hash.keys.first.encoding.should == Encoding::US_ASCII
179179
end
180+
181+
it "raises an EncodingError at parse time when Symbol key with invalid bytes" do
182+
ScratchPad.record []
183+
-> {
184+
eval 'ScratchPad << 1; {:"\xC3" => 1}'
185+
}.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
186+
ScratchPad.recorded.should == []
187+
end
188+
189+
it "raises an EncodingError at parse time when Symbol key with invalid bytes and 'key: value' syntax used" do
190+
ScratchPad.record []
191+
-> {
192+
eval 'ScratchPad << 1; {"\xC3": 1}'
193+
}.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
194+
ScratchPad.recorded.should == []
195+
end
180196
end
181197

182198
describe "The ** operator" do

src/main/java/org/truffleruby/parser/BodyTranslator.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,13 +1307,38 @@ public RubyNode visitDStrNode(DStrParseNode node) {
13071307
public RubyNode visitDSymbolNode(DSymbolParseNode node) {
13081308
SourceIndexLength sourceSection = node.getPosition();
13091309

1310+
// A special case for a symbol in Hash literal {"key": value}
1311+
if (node.size() == 1 && node.getLast() instanceof StrParseNode) {
1312+
final StrParseNode strParseNode = (StrParseNode) node.getLast();
1313+
final SymbolParseNode symbolParseNode = asSymbol(sourceSection, strParseNode);
1314+
return visitSymbolNode(symbolParseNode);
1315+
}
1316+
13101317
final RubyNode stringNode = translateInterpolatedString(sourceSection, node.getEncoding(), node.children());
13111318

13121319
final RubyNode ret = StringToSymbolNodeGen.create(stringNode);
13131320
ret.unsafeSetSourceSection(sourceSection);
13141321
return addNewlineIfNeeded(node, ret);
13151322
}
13161323

1324+
/** Same as {@link ParserSupport#asSymbol(SourceIndexLength position, ParseNode value)} but without needing a
1325+
* ParserSupport instance and only for StrParseNode argument. */
1326+
private SymbolParseNode asSymbol(SourceIndexLength position, StrParseNode value) {
1327+
final SymbolParseNode symbolParseNode = new SymbolParseNode(position, value.getValue(),
1328+
value.encoding);
1329+
1330+
if (!symbolParseNode.getTString().isValidUncached(symbolParseNode.getRubyEncoding().tencoding)) {
1331+
final RubyContext context = RubyLanguage.getCurrentContext();
1332+
throw new RaiseException(
1333+
RubyLanguage.getCurrentContext(),
1334+
context.getCoreExceptions().encodingError(
1335+
symbolParseNode.getTString(),
1336+
symbolParseNode.getRubyEncoding(),
1337+
null));
1338+
}
1339+
return symbolParseNode;
1340+
}
1341+
13171342
private RubyNode translateInterpolatedString(SourceIndexLength sourceSection,
13181343
Encoding encoding, ParseNode[] childNodes) {
13191344
final ToSNode[] children = new ToSNode[childNodes.length];

0 commit comments

Comments
 (0)