A checked view over picoc's (Param, NumArgs) argument array. Every native binding receives its arguments the same way — an array of struct Value*, each one's payload reached through ->Val->Integer or ->Val->Pointer. Spelling that out per binding meant ~60 unchecked casts: a script passing NULL where a char* was expected, or a count that does not match the array beside it, dereferenced straight th
| 61 | // strArray/intArray take that count and the binding must have obtained it from |
| 62 | // count(), which is what rejects the absurd values. |
| 63 | class ScriptArgs { |
| 64 | public: |
| 65 | // Upper bound on any element count a script passes in. Nothing legitimate |
| 66 | // comes close — a pick list is tens of entries, the largest bundled script |
| 67 | // builds a few thousand — while an uninitialised or miscomputed count is |
| 68 | // usually huge or negative. The point is to fail loudly at the boundary |
| 69 | // instead of walking off the end of the array. |
| 70 | static constexpr int kMaxListItems = 65536; |
| 71 | |
| 72 | // `binding` is the script-visible name (the one in library_checkpoint.c's |
| 73 | // table, not the ckpt_ symbol): it is what the user sees in the message and |
| 74 | // what they can search for in the API header. |
| 75 | ScriptArgs(struct ParseState* parser, struct Value** param, int numArgs, const char* binding) |
| 76 | : mParser(parser), mParam(param), mNumArgs(numArgs), mBinding(binding) |
| 77 | { |
| 78 | } |
| 79 | |
| 80 | /* ---- integers ------------------------------------------------------ */ |
| 81 | |
| 82 | int num(int i) const; |
| 83 | // Fails with both bounds in the message, so the script author is told the |
| 84 | // contract rather than just that they broke it. |
| 85 | int numInRange(int i, int min, int max) const; |
| 86 | // A byte count: non-negative, widened once here so no binding has to cast a |
| 87 | // signed script int to size_t itself. |
| 88 | size_t byteCount(int i) const; |
| 89 | // An element count for the array argument beside it: non-negative and below |
| 90 | // kMaxListItems. |
| 91 | int count(int i) const; |
| 92 | |
| 93 | /* ---- strings ------------------------------------------------------- */ |
| 94 | |
| 95 | // A NUL-terminated string argument. NULL fails the run. |
| 96 | const char* str(int i) const; |
| 97 | // Same, but NULL reads as `fallback` — for text a script may legitimately |
| 98 | // omit (a progress label). |
| 99 | const char* strOr(int i, const char* fallback) const; |
| 100 | |
| 101 | /* ---- pointers ------------------------------------------------------ */ |
| 102 | |
| 103 | void* ptr(int i) const; |
| 104 | void* ptrOrNull(int i) const; |
| 105 | |
| 106 | // Out parameters, by what the binding stores through them. |
| 107 | char** outStr(int i) const; |
| 108 | // For an out parameter a script is allowed to skip by passing NULL. |
| 109 | char** outStrOrNull(int i) const; |
| 110 | int* outInt(int i) const; |
| 111 | // A caller-supplied char buffer of `size` bytes, terminator included. |
| 112 | // `size` must come from a numInRange/num on the argument that carries it. |
| 113 | char* outBuf(int i, int size) const; |
| 114 | |
| 115 | /* ---- arrays -------------------------------------------------------- */ |
| 116 | |
| 117 | // `count` elements, none of them NULL: the check the pick-list bindings |
| 118 | // used to skip before indexing straight into the array. |
| 119 | char* const* strArray(int i, int count) const; |
| 120 | int* intArray(int i, int count) const; |
no outgoing calls
no test coverage detected