I wouldn’t rate those as very serious issues for this project. They’ll only be triggered if there are over MAX_INT lines or depth levels in the input. Yes, an attacker might be able to do that, but you’d have to put that input in a memory buffer to call this code. On many smaller systems, that will OOM.

Skimming the code, they also are loose in parsing incorrect json, it seems:

    static bool sj__is_number_cont(char c) {
        return (c >= '0' && c <= '9')
            ||  c == 'e' || c == 'E' || c == '.' || c == '-' || c == '+';
    }

    case '-': case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
        res.type = SJ_NUMBER;
        while (r->cur != r->end && sj__is_number_cont(*r->cur)) { r->cur++; }
        break;
that seems to imply it treats “00.-E.e-8..7-E7E12” as a valid json number.

    case '}': case ']':
        res.type = SJ_END;
        if (--r->depth < 0) {
            r->error = (*r->cur == '}') ? "stray '}'" : "stray ']'";
            goto top;
        }
        r->cur++;
        break;
I think that means the code finds [1,2} a valid array and {"foo": 42] a valid struct (maybe, it even is happy with [1,2,"foo":42})

Those, to me, seem a more likely attack vector. The example code, for example, calls atoi on something parsed by the first piece of code.

⇒ I only would use this for parsing json config files.

Being tiny is one thing, but the json grammar isn’t that complex. They could easily do a better job at this without adding zillions of lines of code.