changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/gs/src/ztype.c

changeset 7254: 03b53375c4f5
parent: eaccc3e8d226
author: cinap_lenrek@felloff.net
date: Fri, 24 May 2019 14:17:18 +0200
permissions: -rw-r--r--
description: gs: fix missing type check in ztype (thanks jsmoody)

to reproduce:

gs <<.
null [[][][][][][][][][][][][][][][]] .type
.
1 /* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
2 
3  This software is provided AS-IS with no warranty, either express or
4  implied.
5 
6  This software is distributed under license and may not be copied,
7  modified or distributed except as expressly authorized under the terms
8  of the license contained in the file LICENSE in this distribution.
9 
10  For more information about licensing, please refer to
11  http://www.ghostscript.com/licensing/. For information on
12  commercial licensing, go to http://www.artifex.com/licensing/ or
13  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14  San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: ztype.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18 /* Type, attribute, and conversion operators */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "string_.h"
22 #include "gsexit.h"
23 #include "ghost.h"
24 #include "oper.h"
25 #include "imemory.h" /* for register_ref_root */
26 #include "idict.h"
27 #include "iname.h"
28 #include "stream.h" /* for iscan.h */
29 #include "strimpl.h" /* for sfilter.h for picky compilers */
30 #include "sfilter.h" /* ditto */
31 #include "iscan.h"
32 #include "iutil.h"
33 #include "dstack.h" /* for dict_set_top */
34 #include "store.h"
35 
36 /*
37  * Some of the procedures in this file are public only so they can be
38  * called from the FunctionType 4 interpreter (zfunc4.c).
39  */
40 
41 /* Forward references */
42 private int access_check(i_ctx_t *, int, bool);
43 private int convert_to_string(const gs_memory_t *mem, os_ptr, os_ptr);
44 
45 /*
46  * Max and min integer values expressed as reals.
47  * Note that these are biased by 1 to allow for truncation.
48  * They should be #defines rather than static consts, but
49  * several of the SCO Unix compilers apparently can't handle this.
50  * On the other hand, the DEC compiler can't handle casts in
51  * constant expressions, so we can't use min_long and max_long.
52  * What a nuisance!
53  */
54 #define ALT_MIN_LONG (-1L << (arch_sizeof_long * 8 - 1))
55 #define ALT_MAX_LONG (~(ALT_MIN_LONG))
56 private const double min_int_real = (ALT_MIN_LONG * 1.0 - 1);
57 private const double max_int_real = (ALT_MAX_LONG * 1.0 + 1);
58 
59 #define REAL_CAN_BE_INT(v)\
60  ((v) > min_int_real && (v) < max_int_real)
61 
62 /* Get the pointer to the access flags for a ref. */
63 #define ACCESS_REF(opp)\
64  (r_has_type(opp, t_dictionary) ? dict_access_ref(opp) : opp)
65 
66 /* <obj> <typenames> .type <name> */
67 private int
68 ztype(i_ctx_t *i_ctx_p)
69 {
70  os_ptr op = osp;
71  ref tnref;
72  int code = array_get(imemory, op, (long)r_btype(op - 1), &tnref);
73 
74  if (code < 0)
75  return code;
76  if (!r_has_type(&tnref, t_name)) {
77  /* Must be either a stack underflow or a t_[a]struct. */
78  check_op(2);
79  { /* Get the type name from the structure. */
80  if ((r_has_type(&op[-1], t_struct) || r_has_type(&op[-1], t_astruct))
81  && op[-1].value.pstruct != 0x00) {
82  const char *sname =
83  gs_struct_type_name_string(gs_object_type(imemory, op[-1].value.pstruct));
84  code = name_ref(imemory, (const byte *)sname, strlen(sname), (ref *) (op - 1), 0);
85  if (code < 0)
86  return code;
87  } else
88  return_error(e_stackunderflow);
89  }
90  r_set_attrs(op - 1, a_executable);
91  } else {
92  ref_assign(op - 1, &tnref);
93  }
94  pop(1);
95  return 0;
96 }
97 
98 /* - .typenames <name1|null> ... <nameN|null> */
99 private int
100 ztypenames(i_ctx_t *i_ctx_p)
101 {
102  os_ptr op = osp;
103  static const char *const tnames[] = { REF_TYPE_NAME_STRINGS };
104  int i;
105 
106  check_ostack(t_next_index);
107  for (i = 0; i < t_next_index; i++) {
108  ref *const rtnp = op + 1 + i;
109 
110  if (i >= countof(tnames) || tnames[i] == 0)
111  make_null(rtnp);
112  else {
113  int code = name_enter_string(imemory, tnames[i], rtnp);
114 
115  if (code < 0)
116  return code;
117  r_set_attrs(rtnp, a_executable);
118  }
119  }
120  osp += t_next_index;
121  return 0;
122 }
123 
124 /* <obj> cvlit <obj> */
125 private int
126 zcvlit(i_ctx_t *i_ctx_p)
127 {
128  os_ptr op = osp;
129  ref *aop;
130 
131  check_op(1);
132  aop = ACCESS_REF(op);
133  r_clear_attrs(aop, a_executable);
134  return 0;
135 }
136 
137 /* <obj> cvx <obj> */
138 int
139 zcvx(i_ctx_t *i_ctx_p)
140 {
141  os_ptr op = osp;
142  ref *aop;
143  uint opidx;
144 
145  check_op(1);
146  /*
147  * If the object is an internal operator, we can't allow it to
148  * exist in executable form anywhere outside the e-stack.
149  */
150  if (r_has_type(op, t_operator) &&
151  ((opidx = op_index(op)) == 0 ||
152  op_def_is_internal(op_index_def(opidx)))
153  )
154  return_error(e_rangecheck);
155  aop = ACCESS_REF(op);
156  r_set_attrs(aop, a_executable);
157  return 0;
158 }
159 
160 /* <obj> xcheck <bool> */
161 private int
162 zxcheck(i_ctx_t *i_ctx_p)
163 {
164  os_ptr op = osp;
165 
166  check_op(1);
167  make_bool(op, (r_has_attr(ACCESS_REF(op), a_executable) ? 1 : 0));
168  return 0;
169 }
170 
171 /* <obj:array|packedarray|file|string> executeonly <obj> */
172 private int
173 zexecuteonly(i_ctx_t *i_ctx_p)
174 {
175  os_ptr op = osp;
176 
177  check_op(1);
178  if (r_has_type(op, t_dictionary))
179  return_error(e_typecheck);
180  return access_check(i_ctx_p, a_execute, true);
181 }
182 
183 /* <obj:array|packedarray|dict|file|string> noaccess <obj> */
184 private int
185 znoaccess(i_ctx_t *i_ctx_p)
186 {
187  os_ptr op = osp;
188 
189  check_op(1);
190  if (r_has_type(op, t_dictionary)) {
191  /*
192  * Setting noaccess on a read-only dictionary is an attempt to
193  * change its value, which is forbidden (this is a subtle
194  * point confirmed with Adobe). Also, don't allow removing
195  * read access to permanent dictionaries.
196  */
197  if (dict_is_permanent_on_dstack(op) ||
198  !r_has_attr(dict_access_ref(op), a_write)
199  )
200  return_error(e_invalidaccess);
201  }
202  return access_check(i_ctx_p, 0, true);
203 }
204 
205 /* <obj:array|packedarray|dict|file|string> readonly <obj> */
206 int
207 zreadonly(i_ctx_t *i_ctx_p)
208 {
209  return access_check(i_ctx_p, a_readonly, true);
210 }
211 
212 /* <array|packedarray|dict|file|string> rcheck <bool> */
213 private int
214 zrcheck(i_ctx_t *i_ctx_p)
215 {
216  os_ptr op = osp;
217  int code = access_check(i_ctx_p, a_read, false);
218 
219  if (code >= 0)
220  make_bool(op, code), code = 0;
221  return code;
222 }
223 
224 /* <array|packedarray|dict|file|string> wcheck <bool> */
225 private int
226 zwcheck(i_ctx_t *i_ctx_p)
227 {
228  os_ptr op = osp;
229  int code = access_check(i_ctx_p, a_write, false);
230 
231  if (code >= 0)
232  make_bool(op, code), code = 0;
233  return code;
234 }
235 
236 /* <num> cvi <int> */
237 /* <string> cvi <int> */
238 int
239 zcvi(i_ctx_t *i_ctx_p)
240 {
241  os_ptr op = osp;
242  float fval;
243 
244  switch (r_type(op)) {
245  case t_integer:
246  return 0;
247  case t_real:
248  fval = op->value.realval;
249  break;
250  default:
251  return_op_typecheck(op);
252  case t_string:
253  {
254  ref str, token;
255  int code;
256 
257  ref_assign(&str, op);
258  code = scan_string_token(i_ctx_p, &str, &token);
259  if (code > 0) /* anything other than a plain token */
260  code = gs_note_error(e_syntaxerror);
261  if (code < 0)
262  return code;
263  switch (r_type(&token)) {
264  case t_integer:
265  *op = token;
266  return 0;
267  case t_real:
268  fval = token.value.realval;
269  break;
270  default:
271  return_error(e_typecheck);
272  }
273  }
274  }
275  if (!REAL_CAN_BE_INT(fval))
276  return_error(e_rangecheck);
277  make_int(op, (long)fval); /* truncates towards 0 */
278  return 0;
279 }
280 
281 /* <string> cvn <name> */
282 private int
283 zcvn(i_ctx_t *i_ctx_p)
284 {
285  os_ptr op = osp;
286 
287  check_read_type(*op, t_string);
288  return name_from_string(imemory, op, op);
289 }
290 
291 /* <num> cvr <real> */
292 /* <string> cvr <real> */
293 int
294 zcvr(i_ctx_t *i_ctx_p)
295 {
296  os_ptr op = osp;
297 
298  switch (r_type(op)) {
299  case t_integer:
300  make_real(op, (float)op->value.intval);
301  case t_real:
302  return 0;
303  default:
304  return_op_typecheck(op);
305  case t_string:
306  {
307  ref str, token;
308  int code;
309 
310  ref_assign(&str, op);
311  code = scan_string_token(i_ctx_p, &str, &token);
312  if (code > 0) /* anything other than a plain token */
313  code = gs_note_error(e_syntaxerror);
314  if (code < 0)
315  return code;
316  switch (r_type(&token)) {
317  case t_integer:
318  make_real(op, (float)token.value.intval);
319  return 0;
320  case t_real:
321  *op = token;
322  return 0;
323  default:
324  return_error(e_typecheck);
325  }
326  }
327  }
328 }
329 
330 /* <num> <radix_int> <string> cvrs <substring> */
331 private int
332 zcvrs(i_ctx_t *i_ctx_p)
333 {
334  os_ptr op = osp;
335  int radix;
336 
337  check_type(op[-1], t_integer);
338  if (op[-1].value.intval < 2 || op[-1].value.intval > 36)
339  return_error(e_rangecheck);
340  radix = op[-1].value.intval;
341  check_write_type(*op, t_string);
342  if (radix == 10) {
343  switch (r_type(op - 2)) {
344  case t_integer:
345  case t_real:
346  {
347  int code = convert_to_string(imemory, op - 2, op);
348 
349  if (code < 0)
350  return code;
351  pop(2);
352  return 0;
353  }
354  case t__invalid:
355  return_error(e_stackunderflow);
356  default:
357  return_op_typecheck(op - 2);
358  }
359  } else {
360  ulong ival;
361  byte digits[sizeof(ulong) * 8];
362  byte *endp = &digits[countof(digits)];
363  byte *dp = endp;
364 
365  switch (r_type(op - 2)) {
366  case t_integer:
367  ival = (ulong) op[-2].value.intval;
368  break;
369  case t_real:
370  {
371  float fval = op[-2].value.realval;
372 
373  if (!REAL_CAN_BE_INT(fval))
374  return_error(e_rangecheck);
375  ival = (ulong) (long)fval;
376  } break;
377  case t__invalid:
378  return_error(e_stackunderflow);
379  default:
380  return_op_typecheck(op - 2);
381  }
382  do {
383  int dit = ival % radix;
384 
385  *--dp = dit + (dit < 10 ? '0' : ('A' - 10));
386  ival /= radix;
387  }
388  while (ival);
389  if (endp - dp > r_size(op))
390  return_error(e_rangecheck);
391  memcpy(op->value.bytes, dp, (uint) (endp - dp));
392  r_set_size(op, endp - dp);
393  }
394  op[-2] = *op;
395  pop(2);
396  return 0;
397 }
398 
399 /* <any> <string> cvs <substring> */
400 private int
401 zcvs(i_ctx_t *i_ctx_p)
402 {
403  os_ptr op = osp;
404  int code;
405 
406  check_op(2);
407  check_write_type(*op, t_string);
408  code = convert_to_string(imemory, op - 1, op);
409  if (code >= 0)
410  pop(1);
411  return code;
412 }
413 
414 /* ------ Initialization procedure ------ */
415 
416 const op_def ztype_op_defs[] =
417 {
418  {"1cvi", zcvi},
419  {"1cvlit", zcvlit},
420  {"1cvn", zcvn},
421  {"1cvr", zcvr},
422  {"3cvrs", zcvrs},
423  {"2cvs", zcvs},
424  {"1cvx", zcvx},
425  {"1executeonly", zexecuteonly},
426  {"1noaccess", znoaccess},
427  {"1rcheck", zrcheck},
428  {"1readonly", zreadonly},
429  {"2.type", ztype},
430  {"0.typenames", ztypenames},
431  {"1wcheck", zwcheck},
432  {"1xcheck", zxcheck},
433  op_def_end(0)
434 };
435 
436 /* ------ Internal routines ------ */
437 
438 /* Test or modify the access of an object. */
439 /* If modify = true, restrict to the selected access and return 0; */
440 /* if modify = false, do not change the access, and return 1 */
441 /* if the object had the access. */
442 /* Return an error code if the object is not of appropriate type, */
443 /* or if the object did not have the access already when modify=1. */
444 private int
445 access_check(i_ctx_t *i_ctx_p,
446  int access, /* mask for attrs */
447  bool modify) /* if true, reduce access */
448 {
449  os_ptr op = osp;
450  ref *aop;
451 
452  switch (r_type(op)) {
453  case t_dictionary:
454  aop = dict_access_ref(op);
455  if (modify) {
456  if (!r_has_attrs(aop, access))
457  return_error(e_invalidaccess);
458  ref_save(op, aop, "access_check(modify)");
459  r_clear_attrs(aop, a_all);
460  r_set_attrs(aop, access);
461  dict_set_top();
462  return 0;
463  }
464  break;
465  case t_array:
466  case t_file:
467  case t_string:
468  case t_mixedarray:
469  case t_shortarray:
470  case t_astruct:
471  case t_device:;
472  if (modify) {
473  if (!r_has_attrs(op, access))
474  return_error(e_invalidaccess);
475  r_clear_attrs(op, a_all);
476  r_set_attrs(op, access);
477  return 0;
478  }
479  aop = op;
480  break;
481  default:
482  return_op_typecheck(op);
483  }
484  return (r_has_attrs(aop, access) ? 1 : 0);
485 }
486 
487 /* Do all the work of cvs. The destination has been checked, but not */
488 /* the source. This is a separate procedure so that */
489 /* cvrs can use it when the radix is 10. */
490 private int
491 convert_to_string(const gs_memory_t *mem, os_ptr op1, os_ptr op)
492 {
493  uint len;
494  const byte *pstr = 0;
495  int code = obj_cvs(mem, op1, op->value.bytes, r_size(op), &len, &pstr);
496 
497  if (code < 0) {
498  /*
499  * Some common downloaded error handlers assume that
500  * operator names don't exceed a certain fixed size.
501  * To work around this bit of bad design, we implement
502  * a special hack here: if we got a rangecheck, and
503  * the object is an operator whose name begins with
504  * %, ., or @, we just truncate the name.
505  */
506  if (code == e_rangecheck)
507  switch (r_btype(op1)) {
508  case t_oparray:
509  case t_operator:
510  if (pstr != 0)
511  switch (*pstr) {
512  case '%':
513  case '.':
514  case '@':
515  len = r_size(op);
516  memcpy(op->value.bytes, pstr, len);
517  goto ok;
518  }
519  }
520  return code;
521  }
522 ok:
523  *op1 = *op;
524  r_set_size(op1, len);
525  return 0;
526 }