summaryrefslogtreecommitdiffstats
path: root/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch')
-rw-r--r--meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch156
1 files changed, 156 insertions, 0 deletions
diff --git a/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch b/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch
new file mode 100644
index 0000000000..f942e21cba
--- /dev/null
+++ b/meta/recipes-support/re2c/re2c/CVE-2018-21232-3.patch
@@ -0,0 +1,156 @@
1From 4d9c809355b574f2a58eac119f5e076c48e4d1e2 Mon Sep 17 00:00:00 2001
2From: Ulya Trofimovich <skvadrik@gmail.com>
3Date: Thu, 23 Apr 2020 22:16:51 +0100
4Subject: [PATCH] Rewrite recursion into iteration (nullable RE).
5
6This is to avoid stack overflow on large RE (especially on instrumented
7builds that have larger stack frames, like AddressSanitizer).
8
9Partial fix for #219 "overflow-1.re test fails on system with small stack".
10
11Upstream-Status: Backport:
12https://github.com/skvadrik/re2c/commit/4d9c809355b574f2a58eac119f5e076c48e4d1e2
13
14CVE: CVE-2018-21232
15
16Signed-off-by: Davide Gardenal <davide.gardenal@huawei.com>
17---
18diff --git a/src/re/nullable.cc b/src/re/nullable.cc
19--- a/src/re/nullable.cc (revision e58939b34bb4c37cd990f82dc286f21cb405743e)
20+++ b/src/re/nullable.cc (date 1647253886226)
21@@ -9,43 +9,100 @@
22 #include "src/re/tag.h"
23
24 namespace re2c {
25+ namespace {
26+
27+ struct StackItem {
28+ const RE *re; // current sub-RE
29+ uint8_t succ; // index of the next sucessor to be visited
30+ };
31
32-static bool nullable(const RESpec &spec, const RE *re, bool &trail)
33-{
34- if (trail) return true;
35+ static bool nullable(const RESpec &spec, std::vector<StackItem> &stack, const RE *re0)
36+ {
37+ // the "nullable" status of the last sub-RE visited by DFS
38+ bool null = false;
39
40- switch (re->type) {
41- case RE::NIL: return true;
42- case RE::SYM: return false;
43- case RE::ITER:
44- return nullable(spec, re->iter.re, trail);
45- case RE::TAG:
46- trail |= trailing(spec.tags[re->tag.idx]);
47- return true;
48- case RE::ALT:
49- return nullable(spec, re->alt.re1, trail)
50- || nullable(spec, re->alt.re2, trail);
51- case RE::CAT:
52- return nullable(spec, re->cat.re1, trail)
53- && nullable(spec, re->cat.re2, trail);
54- }
55- return false; /* unreachable */
56-}
57+ const StackItem i0 = {re0, 0};
58+ stack.push_back(i0);
59+
60+ while (!stack.empty()) {
61+ const StackItem i = stack.back();
62+ stack.pop_back();
63+
64+ const RE *re = i.re;
65+ if (re->type == RE::NIL) {
66+ null = true;
67+ }
68+ else if (re->type == RE::SYM) {
69+ null = false;
70+ }
71+ else if (re->type == RE::TAG) {
72+ null = true;
73
74-/*
75- * warn about rules that match empty string
76- * (including rules with nonempty trailing context)
77- * false positives on partially self-shadowed rules like [^]?
78- */
79-void warn_nullable(const RESpec &spec, const std::string &cond)
80-{
81- const size_t nre = spec.res.size();
82- for (size_t i = 0; i < nre; ++i) {
83- bool trail = false;
84- if (nullable(spec, spec.res[i], trail)) {
85- spec.warn.match_empty_string(spec.rules[i].code->fline, cond);
86- }
87- }
88-}
89+ // Trailing context is always in top-level concatenation, and sub-RE
90+ // are visited from left to right. Since we are here, sub-RE to the
91+ // left of the trailing context is nullable (otherwise we would not
92+ // recurse into the right sub-RE), therefore the whole RE is nullable.
93+ if (trailing(spec.tags[re->tag.idx])) {
94+ //DASSERT(stack.size() == 1 && stack.back().re->type == RE::CAT);
95+ stack.pop_back();
96+ break;
97+ }
98+ }
99+ else if (re->type == RE::ALT) {
100+ if (i.succ == 0) {
101+ // recurse into the left sub-RE
102+ StackItem k = {re, 1};
103+ stack.push_back(k);
104+ StackItem j = {re->alt.re1, 0};
105+ stack.push_back(j);
106+ }
107+ else if (!null) {
108+ // if the left sub-RE is nullable, so is alternative, so stop
109+ // recursion; otherwise recurse into the right sub-RE
110+ StackItem j = {re->alt.re2, 0};
111+ stack.push_back(j);
112+ }
113+ }
114+ else if (re->type == RE::CAT) {
115+ if (i.succ == 0) {
116+ // recurse into the left sub-RE
117+ StackItem k = {re, 1};
118+ stack.push_back(k);
119+ StackItem j = {re->cat.re1, 0};
120+ stack.push_back(j);
121+ }
122+ else if (null) {
123+ // if the left sub-RE is not nullable, neither is concatenation,
124+ // so stop recursion; otherwise recurse into the right sub-RE
125+ StackItem j = {re->cat.re2, 0};
126+ stack.push_back(j);
127+ }
128+ }
129+ else if (re->type == RE::ITER) {
130+ // iteration is nullable if the sub-RE is nullable
131+ // (zero repetitions is represented with alternative)
132+ StackItem j = {re->iter.re, 0};
133+ stack.push_back(j);
134+ }
135+ }
136+
137+ //DASSERT(stack.empty());
138+ return null;
139+ }
140+
141+ } // anonymous namespace
142+
143+// Warn about rules that match empty string (including rules with nonempty
144+// trailing context). False positives on partially self-shadowed rules like [^]?
145+ void warn_nullable(const RESpec &spec, const std::string &cond)
146+ {
147+ std::vector<StackItem> stack;
148+ const size_t nre = spec.res.size();
149+ for (size_t i = 0; i < nre; ++i) {
150+ if (nullable(spec, stack, spec.res[i])) {
151+ spec.warn.match_empty_string(spec.rules[i].code->fline, cond);
152+ }
153+ }
154+ }
155
156 } // namespace re2c