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
24 changes: 24 additions & 0 deletions mrbgems/mruby-compiler/src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,12 @@ scope_finish(mrc_codegen_scope *s)
static mrc_pool_value*
lit_pool_extend(mrc_codegen_scope *s)
{
/* `plen` is what the dump writes the pool count into, and it is 16 bits
wide there and here, so the 65536th entry would wrap it to zero and leave
every OP_LOADL past that pointing outside the pool. */
if (s->irep->plen == 0xffff) {
codegen_error(s, "too many literals");
}
if (s->irep->plen == s->pcapa) {
s->pcapa *= 2;
s->pool = (mrc_pool_value*)mrc_realloc(s->c, s->pool, sizeof(mrc_pool_value)*s->pcapa);
Expand Down Expand Up @@ -1305,6 +1311,18 @@ new_sym(mrc_codegen_scope *s, mrc_sym sym)
for (i=0; i<len; i++) {
if (s->syms[i] == sym) return i;
}
{
/* The dump writes a symbol name's length in 16 bits, and then walks the
cursor by the truncated count while copying the name in full, so a
longer name leaves the rest of the symbol block written over itself.
0xffff is one short of that, and spoken for: it is the length the dump
writes for a null symbol (MRC_DUMP_NULL_SYM_LEN), so a name that long
is read back as no symbol at all. */
mrc_int nlen = 0;
if (mrc_sym_name_len(s->c, sym, &nlen) && nlen >= MRC_DUMP_NULL_SYM_LEN) {
codegen_error(s, "symbol name too long");
}
}
if (s->irep->slen >= s->scapa) {
s->scapa *= 2;
if (s->scapa > 0xffff) {
Expand Down Expand Up @@ -1556,6 +1574,12 @@ new_lit_str(mrc_codegen_scope *s, const char *str, mrc_int len)
int i;
mrc_pool_value *pv;

/* The dump writes a pool string's length in 16 bits, so a longer one is
recorded truncated while its bytes are written in full, and every field
after it is read from the wrong offset. */
if (len > UINT16_MAX) {
codegen_error(s, "string literal too long");
}
for (i=0; i<s->irep->plen; i++) {
pv = &s->pool[i];
if (pv->tt & IREP_TT_NFLAG) continue;
Expand Down
19 changes: 19 additions & 0 deletions mrbgems/mruby-eval/test/eval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,25 @@
end
end

assert 'eval a string literal at the width of the pool length' do
# The dump records a pool string's length in 16 bits, so 65535 bytes is the
# longest one that survives the round trip into an mrb_irep.
assert_equal 65535, eval('"' + 'x' * 65535 + '"').size
assert_raise(SyntaxError) do
eval('"' + 'x' * 65536 + '"')
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.
end

assert 'eval a symbol name at the width of the symbol length' do
# The dump records a symbol name's length in 16 bits too, and 0xffff of them
# is the length it writes for a null symbol, so 65534 bytes is the longest
# name that comes back as itself.
assert_equal 65534, eval(':"' + 'x' * 65534 + '"').to_s.size
assert_raise(SyntaxError) do
eval(':"' + 'x' * 65535 + '"')
end
end

assert('String instance_eval') do
obj = Object.new
obj.instance_eval{ @test = 'test' }
Expand Down
Loading