Check if the symbol can be evaluated safely.

I have a string x . I think x is a string representation of a type that is a subtype of Number . For example, x may be set to "Float64" . I could check this using:

 eval(parse(x)) <: Number 

However, it is possible that x contains something dangerous, for example, some variant on "rm(something_important)" , so using eval is a bad idea until I'm sure x is safe.

Is it safe to check if x string representation of the Number subtype?

(except for building an array of strings of all possible subtypes of Number and comparing ...)

+1
julia-lang
source share
2 answers

The HDF5.jl package must deal with this. He processes it by parsing the string and then checking the result before eval . If the parsed string is what it considers valid_type_expression , then it knows that it should be evaluated in the Main namespace. This allows you to display custom types from the main namespace, which will not be accessible from the baremodule .


Details: after you parse an arbitrary string, you can check the returned object to see if it can be "safely":

 julia> dump(parse("Int")) Symbol Int julia> dump(parse("Vector{Int}")) Expr head: Symbol curly args: Array(Any,(2,)) 1: Symbol Vector 2: Symbol Int typ: Any julia> dump(parse("""rm("/")""")) Expr head: Symbol call args: Array(Any,(2,)) 1: Symbol rm 2: ASCIIString "/" typ: Any 

We want to guarantee that we will never be an eval expression that could cause arbitrary behavior. Depending on how carefully you want to maintain the type syntax, your solution may be quite simple or it may be as complex as the HDF5 solution that I linked above. If you are just after simple, non-parameterized types, we can greatly simplify the situation:

 is_valid_type_expression(ex::Symbol) = true is_valid_type_expression(ex) = false function julia_type(string) ex = parse(string) if is_valid_type_expression(ex) try typ = eval(Main, ex) isa(typ, Type) && typ <: Number && return typ end end error("unsupported type: $string") end julia> julia_type("String") ERROR: unsupported type: String in julia_type at none:9 julia> julia_type("Int") Int64 julia> julia_type("""rm("/")""") ERROR: unsupported type: rm("/") in julia_type at none:9 

Note that nothing more complicated than a character cannot be eval 'ed. And after the eval expression, we check that the type is a type and that it is a subtype of Number . It will also allow you to customize the Number subtypes in addition to the built-in ones, as we evaluate it in the Main namespace.

+4
source share

Edit: This solution is unsafe. Read the comments. I leave him because he is still instructive.

eval does not necessarily take a module as the first argument.

You can evaluate it in a bare module, so the team does not have access to the standard library (then it cannot harm).

 julia> baremodule M end julia> x = :(rm("/")) :(rm("/")) julia> eval(M, x) ERROR: rm not defined julia> x = :"Float64" "Float64" julia> eval(M, x) "Float64" 
+1
source share

All Articles