3

Consider the following:

example.txt

{TextStyle -> {FontFamily -> "Times"}, Axes -> False, AspectRatio -> Automatic}  
{TextStyle -> {FontFamily -> "Arial", FontSize -> 12}, Axes -> True, AspectRatio -> 1}  
{Frame -> True, Background -> RGBColor[1, 0, 0]}  
{Background -> Red, Axes -> False, AspectRatio -> Automatic}  
  • you have a large text file (example.txt) with several inputs from non-secure users
  • entries that does not correspond to options should be discarded

At first glance you might solve that with OptionQ + ToExpression:

OptionQ[ ToExpression[ line1 ] ]

If line1 is an option then the output is True, otherwise the output is False. However, there is a drawback in this approach. The built-in function ToExpression actualy evaluates the user input, which cause a serious security flaw. Malicious users might run whatever they like in your machine, for example:

{DeleteFile[FileNames[]]}

In this case, ToExpression will evaluate this line and delete all files in your folder, and later OptionQ will tell you that this line is not an option and should be ignored.

Issue
Is there a simple way to check if a text entry is an option without evaluating it?

Mark Messa
  • 753
  • 5
  • 14
  • 2
    You can use ToExpression with 3 arguments, for example like ToExpression[codestring, StandardForm, HoldComplete], in which case the code will be parsed but not executed, and will be returned to you wrapped in HoldComplete. You can then analyze the code without evaluating it. – Leonid Shifrin Jan 04 '16 at 16:34
  • @LeonidShifrin I've just tried the following: msg = "{Method->Automatic}"; OptionQ[ ToExpression[ msg, StandardForm, HoldComplete ] ]; However, the result is False. If you remove the HoldComplete, then the result correctly states True. The same is true with Unevaluated. – Mark Messa Jan 04 '16 at 16:55
  • Well, of course OptionQ gives False on an expression with the HoldComplete head. What you may need is slightly more complex, I just suggested the main idea of the solution. The actual code you may need can be something like Select[ StringSplit[text, "\n"], ToExpression[#, StandardForm, Function[expr, OptionQ[Unevaluated[expr]], HoldAllComplete]] &]. – Leonid Shifrin Jan 04 '16 at 17:03
  • Or, if you want the kept options in already parsed form (which you probably do), you can use e.g. this code: Cases[Map[ToExpression[#, StandardForm, HoldComplete] &, StringSplit[text, "\n"]], HoldComplete[opt_ /; OptionQ[Unevaluated[opt]]] :> opt]. – Leonid Shifrin Jan 04 '16 at 17:06
  • @LeonidShifrin Great, I've tried the first one and it seems to be working. However, I'm gonna need some time to understand what you have done. Thanks. – Mark Messa Jan 04 '16 at 17:13
  • The first one leaves results as strings, while the second version gives you a list of already parsed options (as a single Mathematica expression). Re - understand - well, you will have to go down this road some distance anyway, if you have to seriously use Mathematica. What better time than the present? :) – Leonid Shifrin Jan 04 '16 at 17:31
  • @LeonidShifrin What better time than the present? Happy new year for you too! :-) – Mark Messa Jan 04 '16 at 17:40
  • @LeonidShifrin By the way, the email in your profile is updated? – Mark Messa Jan 04 '16 at 17:46
  • Thanks! Re - email: I have added it to my profile, you will have to Uncompress the string. – Leonid Shifrin Jan 04 '16 at 17:52
  • @LeonidShifrin The only issue with those expressions is that, depending on the user input, they might cause an error message. For example: ToExpression[ "Method->All,", StandardForm, Function[ expr, OptionQ[ Unevaluated[expr] ], HoldAllComplete ]]. Fortunately it seems that this can be easily solved including braces over the string: ToExpression[ "{Method->All,}", StandardForm, Function[ expr, OptionQ[ Unevaluated[expr] ], HoldAllComplete ]] – Mark Messa Jan 04 '16 at 18:30
  • You can also modify the code like so: replace StringSplit[text, "\n"] with Select[StringSplit[text, "\n"], SyntaxQ]] in the code I suggested. This pre-filtering stage will remove all strings which do not represent valid Mathematica syntax. – Leonid Shifrin Jan 04 '16 at 19:04
  • @LeonidShifrin Yes, SyntaxQ is the way to go. The only drawback is the annoying "beep" each time the input text is strange, ex: msg = "Method->()". In this case Select[StringSplit[msg, "\n"], SyntaxQ] will make a "beep". Of course it can be turn off in 'Option Inspector' -> 'Global Options' -> 'MessageOptions' -> "WarningAction" -> {} – Mark Messa Jan 04 '16 at 19:49
  • @MarkMessa Be aware that even "valid" option i.e. one passing OptionQ test, can still contain dangerous code, in right hand side of Rule/RuleDelayed, that will be evaluated when option is un-held, or when option value used. To be safe you would need to know exactly what values of options are acceptable and test them on held option. If an option can, for example, accept a function, then it could be extremely difficult to test whether it contains malicious code. – jkuczm Jan 06 '16 at 13:10
  • @jkuczm one passing OptionQ test, can still contain dangerous code Ok, you are right. I was considering using options because it's fast to program and gives a reasonably high level interface with users. However, test all acceptable values beforehand doesn't seem that fast to program. Unfortunately, I'll have to migrate to a lower level user input. – Mark Messa Jan 06 '16 at 13:55
  • Have you seen How can I evaluate untrusted Mathematica code in a sandbox?? Sandboxing might be only reliable way of evaluating untrusted expressions. – jkuczm Jan 06 '16 at 14:25
  • @jkuczm Ok, I've just read it. However, using MathLink for this task seems to be a rough ride (at least is my guess). – Mark Messa Jan 06 '16 at 14:36
  • It really depends on what you're going to do with those options. Do you need to, for example, perform some file-system related task using them, or maybe you can do everything in a sandbox. – jkuczm Jan 06 '16 at 15:51
  • @jkuczm Ok, I agree it really depends on the kind of task. In my case is just some simple manipulation of strings and vectors. Nothing that complicated. But, most important above all, is a prototype before implementing in compiled languages, therefore, it must be fast to program. – Mark Messa Jan 06 '16 at 16:04

0 Answers0