Skip to main content

bugs - How to uncompress strings safely (without any evaluation)?


Compressed strings are often used to exchange Mathematica expressions on the Internet. It is, however, not easy to see what such expression will do after decompression. Resulting code can perform unwanted evaluations.


Here is a (somewhat stupid) example:


Warning: This will open a Youtube music video when decompressed!


str = "1:eJx9jt0KgkAQhbUfiC6CegOvA70Pogu1CARBX6BNZ1Fad8Wd9e/p200ouvHmY87MnMNxniKhtmVZcqMRtoQpgkAXZnPQ8EVVC8XzsK8bkLIUnFrmtte4c4SGE/ZIyuyVCMYm20rj1pT5FGtUVEr8V+laD8bi/DyJYiB3egiAEsUwZFABR7qc6fIxbzVSwAAYGSCf62d/3weJUMU18PSoZYFYy5PndV3nDkKheoKbicrrCGbFpT0H0dg349UfYjkTn5r4/g2cBFpg";


To see the uncompressed content without evaluation, I have tried to use Defer (as suggested in this answer):


Uncompress[str, Defer]

but it does not prevent the video from being played.


How can I uncompress strings from internet safely, i.e. without any evaluation taking place?



Answer



This is definitely a bug. Here's a slightly simpler workaround than those suggested in the comments:


Uncompress[str, HoldComplete] // InputForm

Generally speaking, InputForm and OutputForm are safer than StandardForm. This is for a couple of reasons. Much more of those textual formats happens inside the raw kernel, where evaluation leaks are easier to control. (I know of a couple, but really only because I can read the source code.) The second reason is that there is a class of evaluation which is allowed to happen during formatting, namely Dynamic evaluation--this allows the FE to ask the kernel to evaluate pieces of the expression in order to display them or respond to user actions. Since the frontend will only do this for box-type (e.g, StandardForm) cells, using InputForm or OutputForm will prevent these evaluations.



Edit and expansion in response to @Kuba's comment:


We do try hard to avoid evaluation leaks during formatting, but it can be quite challenging while also make things look "right" in the way most people want them to. And in, fact, this case (as well as Kuba's) shows one of the design issues that hasn't been quite solved.


DefaultElement is an option to GridBox. Options to boxes generally want expressions, not other boxes, as values. So we don't run MakeBoxes on the input. But if the particular box is not HoldAll, the expression isn't protected from further evaluation once MakeBoxes is done. On the other hand, if the value isn't valid (whatever that means) there basically two possibilities: either disable formatting completely, or format with the value protected somehow (say replacing the Rule by RuleDelayed). But that will result in pink boxing in the FE. You'll notice that completely invalid inputs to typeset generators (say, Grid[{a}]) don't format at all. In other cases, you get pinking (e.g., Hold[Graphics[{Red, Disk[]}]]) (because GraphicsBox is HoldAll). Getting it completely right in all cases? Hard.


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...

Is there a way to do conditional matrix loop using 'continue'

I have the following: n = 3; m = 5; ww = RandomReal[{0, 0.1}, {n, n}]; uu = RandomReal[{0, 1}, {m, n}]; pp = RandomReal[{0, 1}, {n, n}]; ss = RandomInteger[{0, 5}, {m, n}]; Grid[{{"ww", "uu", "pp", "ss"}, {ww // TableForm, uu // TableForm, pp // TableForm, ss // TableForm}}, Spacings -> {5, 2}, Dividers -> All] where I would like to look at every element of matrix ss and produce a matrix tt , with zeroes at the locations in ss which have zeroes, and in all other positions do the following: tt = (-1/Subscript[ww, m]) Log[(1 - uu)/(Subscript[pp, m - 1])], where Subscript[ww, m] is the value at index of ww matrix and where Subscript[pp, m - 1] is the value at index-1 of pp matrix. So for example if the first value ever read from matrix ss happens to be 2, then value taken from matrix ww would be from the row 2, but from pp would be from row 1. Also how to tell difference between a 0 as a valid value from within the matrix elemen...