Skip to content

Commit

Permalink
Make PARSE protect rules from modification while they are running
Browse files Browse the repository at this point in the history
  • Loading branch information
hostilefork committed Apr 1, 2015
1 parent 25033f8 commit 9ee2695
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 18 deletions.
7 changes: 4 additions & 3 deletions src/boot/errors.r
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Script: [
parse-variable: [{PARSE - expected a variable, not:} :arg1]
parse-command: [{PARSE - command cannot be used as variable:} :arg1]
parse-series: [{PARSE - input must be a series:} :arg1]
parse-unprotect: [{PARSE - executing rule block was UNPROTECTed} :arg1]

; bad-prompt: [{Error executing prompt block}]
; bad-port-action: [{Cannot use} :arg1 {on this type port}]
Expand Down Expand Up @@ -170,9 +171,9 @@ Access: [
bad-file-mode: [{bad file mode:} :arg1]
; protocol: [{protocol error} :arg1]

security: [{security violation:} :arg1 { (refer to SECURE function)}]
security-level: [{attempt to lower security to} :arg1]
security-error: [{invalid} :arg1 {security policy:} :arg2]
security: [{security violation:} :arg1 { (refer to SECURE function)}]
security-level: [{attempt to lower security to} :arg1]
security-error: [{invalid} :arg1 {security policy:} :arg2]

no-codec: [{cannot decode or encode (no codec):} :arg1]
bad-media: [{bad media data (corrupt image, sound, video)}]
Expand Down
53 changes: 38 additions & 15 deletions src/core/u-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#include "sys-core.h"
#include "sys-state.h"

// We protect rule blocks while they are on the parse stack
extern void Protect_Series(REBVAL *val, REBCNT flags);

// Parser flags:
enum Parse_Flags {
PF_ALL = 1,
Expand Down Expand Up @@ -69,7 +72,7 @@ enum parse_flags {
#define SKIP_TO_BAR(r) while (NOT_END(r) && !IS_SAME_WORD(r, SYM_OR_BAR)) r++;
#define IS_BLOCK_INPUT(p) (p->type >= REB_BLOCK)

static REBCNT Parse_Rules_Loop(REBPARSE *parse, REBCNT index, REBVAL *rules, REBCNT depth);
static REBCNT Parse_Rules_Loop(REBPARSE *parse, REBCNT index, REBVAL *rules, REBVAL *ruleblk, REBCNT depth);

void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
{
Expand All @@ -82,7 +85,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)

/***********************************************************************
**
*/ static REBCNT Parse_Series(REBVAL *val, REBVAL *rules, REBCNT flags, REBCNT depth)
*/ static REBCNT Parse_Series(REBVAL *val, REBVAL *ruleblk, REBCNT flags, REBCNT depth)
/*
***********************************************************************/
{
Expand All @@ -93,7 +96,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
parse.flags = flags;
parse.result = 0;

return Parse_Rules_Loop(&parse, VAL_INDEX(val), rules, depth);
return Parse_Rules_Loop(&parse, VAL_INDEX(val), VAL_BLK_DATA(ruleblk), ruleblk, depth);
}


Expand Down Expand Up @@ -238,14 +241,14 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)

// Parse a sub-rule block:
case REB_BLOCK:
index = Parse_Rules_Loop(parse, index, VAL_BLK_DATA(item), depth);
index = Parse_Rules_Loop(parse, index, VAL_BLK_DATA(item), item, depth);
break;

// Do an expression:
case REB_PAREN:
item = Do_Block_Value_Throw(item); // might GC
// old: if (IS_ERROR(item)) Throw_Error(VAL_ERR_OBJECT(item));
index = MIN(index, series->tail); // may affect tail
index = MIN(index, series->tail); // may affect tail
break;

default:
Expand Down Expand Up @@ -304,14 +307,14 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)

// Parse a sub-rule block:
case REB_BLOCK:
index = Parse_Rules_Loop(parse, index, VAL_BLK_DATA(item), depth);
index = Parse_Rules_Loop(parse, index, VAL_BLK_DATA(item), item, depth);
break;

// Do an expression:
case REB_PAREN:
item = Do_Block_Value_Throw(item); // might GC
// old: if (IS_ERROR(item)) Throw_Error(VAL_ERR_OBJECT(item));
index = MIN(index, series->tail); // may affect tail
index = MIN(index, series->tail); // may affect tail
break;

// Match with some other value:
Expand Down Expand Up @@ -602,7 +605,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
item = Get_Parse_Value(item); // sub-rules
if (!IS_BLOCK(item)) Trap1(RE_PARSE_RULE, item-2);
if (!ANY_BINSTR(&value) && !ANY_BLOCK(&value)) return NOT_FOUND;
return (Parse_Series(&value, VAL_BLK_DATA(item), parse->flags, 0) == VAL_TAIL(&value))
return (Parse_Series(&value, item, parse->flags, 0) == VAL_TAIL(&value))
? index : NOT_FOUND;
}
else if (n > 0)
Expand Down Expand Up @@ -636,7 +639,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)

/***********************************************************************
**
*/ static REBCNT Parse_Rules_Loop(REBPARSE *parse, REBCNT index, REBVAL *rules, REBCNT depth)
*/ static REBCNT Parse_Rules_Loop(REBPARSE *parse, REBCNT index, REBVAL *rules, REBVAL *ruleblk, REBCNT depth)
/*
***********************************************************************/
{
Expand All @@ -658,6 +661,13 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
REBVAL *rule_head = rules;

CHECK_STACK(&flags);

// Protect the series to prevent the user from modifying a
// rule currently executing (if not already protected)
REBOOL protect = (REBOOL)IS_PROTECT_SERIES(VAL_SERIES(ruleblk));
if (!protect)
Protect_Series(ruleblk, 1);

//if (depth > MAX_PARSE_DEPTH) Trap_Word(RE_LIMIT_HIT, SYM_PARSE, 0);
flags = 0;
word = 0;
Expand Down Expand Up @@ -907,7 +917,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
val = BLK_SKIP(series, index);
i = (
(ANY_BINSTR(val) || ANY_BLOCK(val))
&& (Parse_Series(val, VAL_BLK_DATA(item), parse->flags, depth+1) == VAL_TAIL(val))
&& (Parse_Series(val, item, parse->flags, depth+1) == VAL_TAIL(val))
) ? index+1 : NOT_FOUND;
break;

Expand All @@ -922,12 +932,12 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
}
}
else if (IS_BLOCK(item)) {
item = VAL_BLK_DATA(item);
//if (IS_END(rules) && item == rule_head) {
// rules = item;
// goto top;
//}
i = Parse_Rules_Loop(parse, index, item, depth+1);
i = Parse_Rules_Loop(parse, index, VAL_BLK_DATA(item), item, depth+1);

if (parse->result) {
index = (parse->result > 0) ? i : NOT_FOUND;
parse->result = 0;
Expand Down Expand Up @@ -1073,13 +1083,26 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
mincount = maxcount = 1;

}
return index;
goto success;

bad_rule:
Trap1(RE_PARSE_RULE, rules-1);
bad_end:
Trap1(RE_PARSE_END, rules-1);
return 0;
index = 0;
success:
// Catch the case where the user unprotected the rule block out from
// under us. This does not catch the case if they UNPROTECT, MODIFY,
// and then PROTECT back (doing so requires a system-only protect bit)
if (!IS_PROTECT_SERIES(VAL_SERIES(ruleblk)))
Trap1(RE_PARSE_UNPROTECT, ruleblk);

// If this call had to protect the series (vs having it protected by
// the user already, or more likely by another Parse_Rules_Loop higher up
// on the stack), put it back to how it was when we found it.
if (!protect)
Protect_Series(ruleblk, 0);
return index;
}


Expand Down Expand Up @@ -1269,7 +1292,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
Throw_Error(VAL_ERR_OBJECT(DS_RETURN));
}
SET_STATE(state, Saved_State);
n = Parse_Series(val, VAL_BLK_DATA(arg), (opts & PF_CASE) ? AM_FIND_CASE : 0, 0);
n = Parse_Series(val, arg, (opts & PF_CASE) ? AM_FIND_CASE : 0, 0);
SET_LOGIC(DS_RETURN, n >= VAL_TAIL(val) && n != NOT_FOUND);
POP_STATE(state, Saved_State);
}
Expand Down

0 comments on commit 9ee2695

Please sign in to comment.