1

I have an AWS lambda function that receives user's code from a browser as a string and runs eval in a sandboxed environment as in a standard REPL. I am not trying to interpolate a string. I am trying to have eval recognize and perform operations on strings.

I am somewhat limited in the operations I can perform. Basic regex replacement is cool, but I don't think I would be able to do anything more involved than that, but perhaps I'm mistaken.

This works for basic arithmetic operations, the creation of class instances, etc. However, it fails to perform string operations properly. When I pass:

eval `("3*4")`

it returns 12, which is great. However, if I pass:

eval(""str:" + " test"")

it fails to return "str: test". In fact it returns nothing.

It has been suggested that I escape the double quotes. In a REPL, replacing all double quotes with escaped ones, such as \", works.

eval("\"str \" + \"test\"") # => "str test"

However, when I try this with AWS, it returns "\"str \" + \"test\"".

I look forward to hearing your responses.

sawa
  • 165,429
  • 45
  • 277
  • 381
Durry
  • 21
  • 6
  • Also, I should put out there. I initially discovered this issue not with concatenation but instead when trying to get it to return a string that was saved as a data attribute on a class. So concatenation is not the sole issue here – Durry Mar 22 '19 at 00:21
  • 1
    You need to write `eval("\"str:\" + \" test\"")` or `eval('"str:" + " test"')`. Be careful when you use `eval`. If the string to `eval` were, say, `"launch ICBMs"`, the consequences may be undesireable. More generally, `eval`'ed strings that are not vetted could result in security issues. – Cary Swoveland Mar 22 '19 at 00:40
  • Hey, @CarySwoveland, thanks for your reply. In the second paragraph, I mentioned that I have done that, and while it works great in a REPL, such as pry; it is failing to work in AWS. – Durry Mar 22 '19 at 00:45
  • I missed that but there's no point in even trying it without escaping the inner double-quotes. – Cary Swoveland Mar 22 '19 at 01:14
  • Why can't you make sure your string is valid executable ruby code before passing it to ruby? – lacostenycoder Mar 22 '19 at 01:18
  • Possible duplicate of [Ruby: eval with string interpolation](https://stackoverflow.com/questions/17169671/ruby-eval-with-string-interpolation) – lacostenycoder Mar 22 '19 at 01:20
  • You should probably read this https://stackoverflow.com/questions/1902744/when-is-eval-in-ruby-justified – lacostenycoder Mar 22 '19 at 01:22
  • @lacostenycoder If you read the post you have told me to read, you will note it says eval is to be used for this exact purpose (making your own REPL). – Durry Mar 22 '19 at 06:53
  • @lacostenycoder Thank you though. Also, I had already consulted https://stackoverflow.com/questions/17169671/ruby-eval-with-string-interpolation prior to posting my question and deemed it to be unrelated. – Durry Mar 22 '19 at 06:54

3 Answers3

1

You shouldn't expect eval(""str:" + " test"") to work. The problem is not related to AWS lambda. If you try this on your own machine, using pry or irb, you will get a SyntaxError. That's because your interpreter can't understand that you are only passing one unified string to eval. So you need to escape all quotation marks inside your string:

eval("\"str \" + \"test\"")

If you have tested it in a REPL without escaping, and it worked, it seems that the REPL you are using, somehow changes your input before sending it to interpreter.

Sajad Rastegar
  • 3,014
  • 3
  • 25
  • 36
  • Thanks for your feedback Sajad. If you look at the second paragraph, you'll note that I have already tried that. Thank you, though. – Durry Mar 22 '19 at 06:48
1

I have seemed to find a work around.

To begin, I will first clarify what my issue was. Say a user entered the following:

class Test
   attr_accesssor :data
   def initialize(data = nil)
      @data = data
   end
end

Followed by

Test.new(4).data

eval would properly return 4.

Now say, however, that the user instead wrote

Test.new("A nice, fine string").data

eval would return nothing.

I noticed, however, that if I tacked on a .inspect, as shown below:

Test.new("A nice, fine string").data.inspect

I would be returned A nice, fine string.

So my solution was to wrap the entirety of the user's code in parenthesis and then call .inspect.

Which was accomplished by the following line

code = "(" << code << ").inspect"

Thank you to everyone who took the time to help me out. I really appreciate all of the feedback and suggestions.

Durry
  • 21
  • 6
  • Also, please note. I still have no idea why it was comfortable returning numbers but not strings. So any insight into that would be appreciated. – Durry Mar 22 '19 at 07:25
0

You need to be careful about string interpolation when using eval on strings:

str = %(This is my String. It's name is string. Now I can eval "Hooray for my string")
eval(str.inspect)
#=> "This is my String. It's name is string. Now I can eval \"Hooray for my string\""

however these will raise errors

eval(str)
#=> SyntaxError: (eval):1: unterminated string meets end of file

eval(puts str) # will output the string but raise an error after it.
#=> This is my String. It's name is string. Now I can eval "Hooray for my string"
#  TypeError: no implicit conversion of nil into String

but this will work

eval("puts #{str.inspect}")
#=> This is my String. It's name is string. Now I can eval "Hooray for my string"
lacostenycoder
  • 10,623
  • 4
  • 31
  • 48