Skip to content

Commit 373d2d3

Browse files
authored
Merge pull request #68 from mortie/feature/handle-malloc-error
Handle malloc failures
2 parents 4e8cc00 + c8d5b43 commit 373d2d3

File tree

1 file changed

+83
-7
lines changed

1 file changed

+83
-7
lines changed

tinyexpr.c

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,15 @@ typedef struct state {
8282
#define IS_CLOSURE(TYPE) (((TYPE) & TE_CLOSURE0) != 0)
8383
#define ARITY(TYPE) ( ((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) & 0x00000007) : 0 )
8484
#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__})
85+
#define CHECK_NULL(ptr, ...) if ((ptr) == NULL) { __VA_ARGS__; return NULL; }
8586

8687
static te_expr *new_expr(const int type, const te_expr *parameters[]) {
8788
const int arity = ARITY(type);
8889
const int psize = sizeof(void*) * arity;
8990
const int size = (sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0);
9091
te_expr *ret = malloc(size);
92+
CHECK_NULL(ret);
93+
9194
memset(ret, 0, size);
9295
if (arity && parameters) {
9396
memcpy(ret->parameters, parameters, psize);
@@ -312,19 +315,25 @@ static te_expr *base(state *s) {
312315
switch (TYPE_MASK(s->type)) {
313316
case TOK_NUMBER:
314317
ret = new_expr(TE_CONSTANT, 0);
318+
CHECK_NULL(ret);
319+
315320
ret->value = s->value;
316321
next_token(s);
317322
break;
318323

319324
case TOK_VARIABLE:
320325
ret = new_expr(TE_VARIABLE, 0);
326+
CHECK_NULL(ret);
327+
321328
ret->bound = s->bound;
322329
next_token(s);
323330
break;
324331

325332
case TE_FUNCTION0:
326333
case TE_CLOSURE0:
327334
ret = new_expr(s->type, 0);
335+
CHECK_NULL(ret);
336+
328337
ret->function = s->function;
329338
if (IS_CLOSURE(s->type)) ret->parameters[0] = s->context;
330339
next_token(s);
@@ -341,10 +350,13 @@ static te_expr *base(state *s) {
341350
case TE_FUNCTION1:
342351
case TE_CLOSURE1:
343352
ret = new_expr(s->type, 0);
353+
CHECK_NULL(ret);
354+
344355
ret->function = s->function;
345356
if (IS_CLOSURE(s->type)) ret->parameters[1] = s->context;
346357
next_token(s);
347358
ret->parameters[0] = power(s);
359+
CHECK_NULL(ret->parameters[0], te_free(ret));
348360
break;
349361

350362
case TE_FUNCTION2: case TE_FUNCTION3: case TE_FUNCTION4:
@@ -354,6 +366,8 @@ static te_expr *base(state *s) {
354366
arity = ARITY(s->type);
355367

356368
ret = new_expr(s->type, 0);
369+
CHECK_NULL(ret);
370+
357371
ret->function = s->function;
358372
if (IS_CLOSURE(s->type)) ret->parameters[arity] = s->context;
359373
next_token(s);
@@ -365,6 +379,8 @@ static te_expr *base(state *s) {
365379
for(i = 0; i < arity; i++) {
366380
next_token(s);
367381
ret->parameters[i] = expr(s);
382+
CHECK_NULL(ret->parameters[i], te_free(ret));
383+
368384
if(s->type != TOK_SEP) {
369385
break;
370386
}
@@ -381,6 +397,8 @@ static te_expr *base(state *s) {
381397
case TOK_OPEN:
382398
next_token(s);
383399
ret = list(s);
400+
CHECK_NULL(ret);
401+
384402
if (s->type != TOK_CLOSE) {
385403
s->type = TOK_ERROR;
386404
} else {
@@ -390,6 +408,8 @@ static te_expr *base(state *s) {
390408

391409
default:
392410
ret = new_expr(0, 0);
411+
CHECK_NULL(ret);
412+
393413
s->type = TOK_ERROR;
394414
ret->value = NAN;
395415
break;
@@ -412,7 +432,12 @@ static te_expr *power(state *s) {
412432
if (sign == 1) {
413433
ret = base(s);
414434
} else {
415-
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
435+
te_expr *b = base(s);
436+
CHECK_NULL(b);
437+
438+
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, b);
439+
CHECK_NULL(ret, te_free(b));
440+
416441
ret->function = negate;
417442
}
418443

@@ -423,6 +448,7 @@ static te_expr *power(state *s) {
423448
static te_expr *factor(state *s) {
424449
/* <factor> = <power> {"^" <power>} */
425450
te_expr *ret = power(s);
451+
CHECK_NULL(ret);
426452

427453
int neg = 0;
428454

@@ -441,19 +467,33 @@ static te_expr *factor(state *s) {
441467

442468
if (insertion) {
443469
/* Make exponentiation go right-to-left. */
444-
te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s));
470+
te_expr *p = power(s);
471+
CHECK_NULL(p, te_free(ret));
472+
473+
te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], p);
474+
CHECK_NULL(insert, te_free(p), te_free(ret));
475+
445476
insert->function = t;
446477
insertion->parameters[1] = insert;
447478
insertion = insert;
448479
} else {
449-
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
480+
te_expr *p = power(s);
481+
CHECK_NULL(p, te_free(ret));
482+
483+
te_expr *prev = ret;
484+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, p);
485+
CHECK_NULL(ret, te_free(p), te_free(prev));
486+
450487
ret->function = t;
451488
insertion = ret;
452489
}
453490
}
454491

455492
if (neg) {
493+
te_expr *prev = ret;
456494
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
495+
CHECK_NULL(ret, te_free(prev));
496+
457497
ret->function = negate;
458498
}
459499

@@ -463,11 +503,18 @@ static te_expr *factor(state *s) {
463503
static te_expr *factor(state *s) {
464504
/* <factor> = <power> {"^" <power>} */
465505
te_expr *ret = power(s);
506+
CHECK_NULL(ret);
466507

467508
while (s->type == TOK_INFIX && (s->function == pow)) {
468509
te_fun2 t = s->function;
469510
next_token(s);
470-
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
511+
te_expr *p = power(s);
512+
CHECK_NULL(p, te_free(ret));
513+
514+
te_expr *prev = ret;
515+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, p);
516+
CHECK_NULL(ret, te_free(p), te_free(prev));
517+
471518
ret->function = t;
472519
}
473520

@@ -480,11 +527,18 @@ static te_expr *factor(state *s) {
480527
static te_expr *term(state *s) {
481528
/* <term> = <factor> {("*" | "/" | "%") <factor>} */
482529
te_expr *ret = factor(s);
530+
CHECK_NULL(ret);
483531

484532
while (s->type == TOK_INFIX && (s->function == mul || s->function == divide || s->function == fmod)) {
485533
te_fun2 t = s->function;
486534
next_token(s);
487-
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s));
535+
te_expr *f = factor(s);
536+
CHECK_NULL(f, te_free(ret));
537+
538+
te_expr *prev = ret;
539+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, f);
540+
CHECK_NULL(ret, te_free(f), te_free(prev));
541+
488542
ret->function = t;
489543
}
490544

@@ -495,11 +549,18 @@ static te_expr *term(state *s) {
495549
static te_expr *expr(state *s) {
496550
/* <expr> = <term> {("+" | "-") <term>} */
497551
te_expr *ret = term(s);
552+
CHECK_NULL(ret);
498553

499554
while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
500555
te_fun2 t = s->function;
501556
next_token(s);
502-
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s));
557+
te_expr *te = term(s);
558+
CHECK_NULL(te, te_free(ret));
559+
560+
te_expr *prev = ret;
561+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, te);
562+
CHECK_NULL(ret, te_free(te), te_free(prev));
563+
503564
ret->function = t;
504565
}
505566

@@ -510,10 +571,17 @@ static te_expr *expr(state *s) {
510571
static te_expr *list(state *s) {
511572
/* <list> = <expr> {"," <expr>} */
512573
te_expr *ret = expr(s);
574+
CHECK_NULL(ret);
513575

514576
while (s->type == TOK_SEP) {
515577
next_token(s);
516-
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s));
578+
te_expr *e = expr(s);
579+
CHECK_NULL(e, te_free(ret));
580+
581+
te_expr *prev = ret;
582+
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, e);
583+
CHECK_NULL(ret, te_free(e), te_free(prev));
584+
517585
ret->function = comma;
518586
}
519587

@@ -602,6 +670,10 @@ te_expr *te_compile(const char *expression, const te_variable *variables, int va
602670

603671
next_token(&s);
604672
te_expr *root = list(&s);
673+
if (root == NULL) {
674+
if (error) *error = -1;
675+
return NULL;
676+
}
605677

606678
if (s.type != TOK_END) {
607679
te_free(root);
@@ -620,6 +692,10 @@ te_expr *te_compile(const char *expression, const te_variable *variables, int va
620692

621693
double te_interp(const char *expression, int *error) {
622694
te_expr *n = te_compile(expression, 0, 0, error);
695+
if (n == NULL) {
696+
return NAN;
697+
}
698+
623699
double ret;
624700
if (n) {
625701
ret = te_eval(n);

0 commit comments

Comments
 (0)