Skip to content

Commit f8cad4e

Browse files
committed
Merge pull request #2024 from mgreter/bugfix/issue_2016
Improve error handling in C-API to be more robust
2 parents 86b0ded + 1a4dd3b commit f8cad4e

File tree

4 files changed

+50
-31
lines changed

4 files changed

+50
-31
lines changed

src/json.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
#include "json.hpp"
3030

31+
// include utf8 library used by libsass
32+
// ToDo: replace internal json utf8 code
33+
#include "utf8.h"
34+
3135
#include <assert.h>
3236
#include <stdint.h>
3337
#include <stdio.h>
@@ -548,7 +552,7 @@ static void append_node(JsonNode *parent, JsonNode *child)
548552
child->parent = parent;
549553
child->prev = parent->children.tail;
550554
child->next = NULL;
551-
555+
552556
if (parent->children.tail != NULL)
553557
parent->children.tail->next = child;
554558
else
@@ -563,7 +567,7 @@ static void prepend_node(JsonNode *parent, JsonNode *child)
563567
child->parent = parent;
564568
child->prev = NULL;
565569
child->next = parent->children.head;
566-
570+
567571
if (parent->children.head != NULL)
568572
parent->children.head->prev = child;
569573
else
@@ -585,7 +589,7 @@ void json_append_element(JsonNode *array, JsonNode *element)
585589
if (array != NULL && element !=NULL) {
586590
assert(array->tag == JSON_ARRAY);
587591
assert(element->parent == NULL);
588-
592+
589593
append_node(array, element);
590594
}
591595
}
@@ -603,7 +607,7 @@ void json_append_member(JsonNode *object, const char *key, JsonNode *value)
603607
if (object != NULL && key != NULL && value != NULL) {
604608
assert(object->tag == JSON_OBJECT);
605609
assert(value->parent == NULL);
606-
610+
607611
append_member(object, json_strdup(key), value);
608612
}
609613
}
@@ -613,7 +617,7 @@ void json_prepend_member(JsonNode *object, const char *key, JsonNode *value)
613617
if (object != NULL && key != NULL && value != NULL) {
614618
assert(object->tag == JSON_OBJECT);
615619
assert(value->parent == NULL);
616-
620+
617621
value->key = json_strdup(key);
618622
prepend_node(object, value);
619623
}
@@ -623,20 +627,20 @@ void json_remove_from_parent(JsonNode *node)
623627
{
624628
if (node != NULL) {
625629
JsonNode *parent = node->parent;
626-
630+
627631
if (parent != NULL) {
628632
if (node->prev != NULL)
629633
node->prev->next = node->next;
630634
else
631635
parent->children.head = node->next;
632-
636+
633637
if (node->next != NULL)
634638
node->next->prev = node->prev;
635639
else
636640
parent->children.tail = node->prev;
637-
641+
638642
free(node->key);
639-
643+
640644
node->parent = NULL;
641645
node->prev = node->next = NULL;
642646
node->key = NULL;
@@ -1141,6 +1145,13 @@ void emit_string(SB *out, const char *str)
11411145
const char *s = str;
11421146
char *b;
11431147

1148+
// make assertion catchable
1149+
#ifndef NDEBUG
1150+
if (!utf8_validate(str)) {
1151+
throw utf8::invalid_utf8(0);
1152+
}
1153+
#endif
1154+
11441155
assert(utf8_validate(str));
11451156

11461157
/*

src/json.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,21 @@ struct JsonNode
4343
/* only if parent is an object or array (NULL otherwise) */
4444
JsonNode *parent;
4545
JsonNode *prev, *next;
46-
46+
4747
/* only if parent is an object (NULL otherwise) */
4848
char *key; /* Must be valid UTF-8. */
49-
49+
5050
JsonTag tag;
5151
union {
5252
/* JSON_BOOL */
5353
bool bool_;
54-
54+
5555
/* JSON_STRING */
5656
char *string_; /* Must be valid UTF-8. */
57-
57+
5858
/* JSON_NUMBER */
5959
double number_;
60-
60+
6161
/* JSON_ARRAY */
6262
/* JSON_OBJECT */
6363
struct {

src/sass_context.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ extern "C" {
3636
type sass_context_take_##option (struct Sass_Context* ctx) \
3737
{ type foo = ctx->option; ctx->option = 0; return foo; }
3838

39-
static int handle_errors(Sass_Context* c_ctx) {
39+
static int handle_error(Sass_Context* c_ctx) {
4040
try {
4141
throw;
4242
}
@@ -194,6 +194,14 @@ extern "C" {
194194
return c_ctx->error_status;
195195
}
196196

197+
// allow one error handler to throw another error
198+
// this can happen with invalid utf8 and json lib
199+
static int handle_errors(Sass_Context* c_ctx) {
200+
try { return handle_error(c_ctx); }
201+
catch (...) { return handle_error(c_ctx); }
202+
return c_ctx->error_status;
203+
}
204+
197205
// generic compilation function (not exported, use file/data compile instead)
198206
static Sass_Compiler* sass_prepare_context (Sass_Context* c_ctx, Context* cpp_ctx) throw()
199207
{

src/utf8/unchecked.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ DEALINGS IN THE SOFTWARE.
3232

3333
namespace utf8
3434
{
35-
namespace unchecked
35+
namespace unchecked
3636
{
3737
template <typename octet_iterator>
3838
octet_iterator append(uint32_t cp, octet_iterator result)
3939
{
4040
if (cp < 0x80) // one octet
41-
*(result++) = static_cast<uint8_t>(cp);
41+
*(result++) = static_cast<uint8_t>(cp);
4242
else if (cp < 0x800) { // two octets
4343
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
4444
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
@@ -70,28 +70,28 @@ namespace utf8
7070
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
7171
break;
7272
case 3:
73-
++it;
73+
++it;
7474
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
7575
++it;
7676
cp += (*it) & 0x3f;
7777
break;
7878
case 4:
7979
++it;
80-
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
80+
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
8181
++it;
8282
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
8383
++it;
84-
cp += (*it) & 0x3f;
84+
cp += (*it) & 0x3f;
8585
break;
8686
}
8787
++it;
88-
return cp;
88+
return cp;
8989
}
9090

9191
template <typename octet_iterator>
9292
uint32_t peek_next(octet_iterator it)
9393
{
94-
return utf8::unchecked::next(it);
94+
return utf8::unchecked::next(it);
9595
}
9696

9797
template <typename octet_iterator>
@@ -121,14 +121,14 @@ namespace utf8
121121
distance (octet_iterator first, octet_iterator last)
122122
{
123123
typename std::iterator_traits<octet_iterator>::difference_type dist;
124-
for (dist = 0; first < last; ++dist)
124+
for (dist = 0; first < last; ++dist)
125125
utf8::unchecked::next(first);
126126
return dist;
127127
}
128128

129129
template <typename u16bit_iterator, typename octet_iterator>
130130
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
131-
{
131+
{
132132
while (start != end) {
133133
uint32_t cp = utf8::internal::mask16(*start++);
134134
// Take care of surrogate pairs first
@@ -138,7 +138,7 @@ namespace utf8
138138
}
139139
result = utf8::unchecked::append(cp, result);
140140
}
141-
return result;
141+
return result;
142142
}
143143

144144
template <typename u16bit_iterator, typename octet_iterator>
@@ -176,7 +176,7 @@ namespace utf8
176176

177177
// The iterator class
178178
template <typename octet_iterator>
179-
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
179+
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
180180
octet_iterator it;
181181
public:
182182
iterator () {}
@@ -188,15 +188,15 @@ namespace utf8
188188
octet_iterator temp = it;
189189
return utf8::unchecked::next(temp);
190190
}
191-
bool operator == (const iterator& rhs) const
192-
{
191+
bool operator == (const iterator& rhs) const
192+
{
193193
return (it == rhs.it);
194194
}
195195
bool operator != (const iterator& rhs) const
196196
{
197197
return !(operator == (rhs));
198198
}
199-
iterator& operator ++ ()
199+
iterator& operator ++ ()
200200
{
201201
::std::advance(it, utf8::internal::sequence_length(it));
202202
return *this;
@@ -206,7 +206,7 @@ namespace utf8
206206
iterator temp = *this;
207207
::std::advance(it, utf8::internal::sequence_length(it));
208208
return temp;
209-
}
209+
}
210210
iterator& operator -- ()
211211
{
212212
utf8::unchecked::prior(it);
@@ -221,7 +221,7 @@ namespace utf8
221221
}; // class iterator
222222

223223
} // namespace utf8::unchecked
224-
} // namespace utf8
224+
} // namespace utf8
225225

226226

227227
#endif // header guard

0 commit comments

Comments
 (0)