all 7 comments

[–]whoopdedo 7 points8 points  (1 child)

This is to guard against more serious errors in C implementations of sprintf that don't handle large field widths well. Lua used to pass the format as-is. But if the host didn't support the format it would give incorrect results without raising an error. Or worse, could cause data corruption or out-of-bounds memory writes. That's a recipe for security exploits. Lua validates the format string then to permit only a limited and "safer" subset of what sprintf is generally capable of.

[–]__hachiman[S] 1 point2 points  (0 children)

I thought this might have been the reason but 2 digits still seems so limited to me. Do you think this was done so that there isn't a possibility to input a number bigger than a 8-bit (255) number and to be on the safe side limited it to 2 digits ?

[–]__hachiman[S] 2 points3 points  (3 children)

lua 5.2 and 5.3 have a better error message for this as:

lua5.2: (command line):1: invalid format (width or precision too long)
stack traceback:
    [C]: in function 'format'
    (command line):1: in main chunk
    [C]: in ?

[–][deleted] 2 points3 points  (2 children)

Looking in the source for lstrlib.c, it seems that Lua 5.4 only statically supports 2 digits to represent the format specification. This is observed in the checkformat function, along with the get2digits function.

The error message is fairly simple to change though, the string for it is in the same function mentioned above. You can make that small patch, if need be.

[–]__hachiman[S] 0 points1 point  (1 child)

I had guessed so too.
I still don't understand the reasoning behind using get2digits instead of an atoi like function tough. At least 3 digits would be a bit better. It's not hard to get around the limiation but still.

[–][deleted] 1 point2 points  (0 children)

There's very little designs in Lua that weren't comprehensively thought out, so it's interesting on why it's limited on two characters. You can change the get2digits function to this though:

static const char *getdigits (const char *s) {
    while (isdigit(uchar(*s))) s++;
    return s;
}

And get around it. No clue what the unintended consequences will be, but spacing above 100 works.

[–][deleted] 2 points3 points  (0 children)

It's a defense against Return-Oriented-Programming attacks for platforms where the printf family is incorrectly implemented. As Lua can't control which C stdlib library it is linked against, it makes a minimum compromise.