Commit 961e615e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #799 from kmod/format_checking

Enable validation of printf-style format strings
parents 3307cddc e087a276
...@@ -764,7 +764,8 @@ void addToSysArgv(const char* str); ...@@ -764,7 +764,8 @@ void addToSysArgv(const char* str);
// The traceback given to the user will include this, // The traceback given to the user will include this,
// even though the execution didn't actually arrive there. // even though the execution didn't actually arrive there.
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func); void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func);
void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...); void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...)
__attribute__((format(printf, 4, 5)));
struct LineInfo { struct LineInfo {
public: public:
......
...@@ -88,8 +88,7 @@ BoxedList* getSysPath() { ...@@ -88,8 +88,7 @@ BoxedList* getSysPath() {
assert(_sys_path); assert(_sys_path);
if (_sys_path->cls != list_cls) { if (_sys_path->cls != list_cls) {
fprintf(stderr, "RuntimeError: sys.path must be a list of directory name\n"); raiseExcHelper(RuntimeError, "sys.path must be a list of directory names");
raiseExcHelper(RuntimeError, "");
} }
assert(_sys_path->cls == list_cls); assert(_sys_path->cls == list_cls);
......
...@@ -604,14 +604,14 @@ void dictMergeFromSeq2(BoxedDict* self, Box* other) { ...@@ -604,14 +604,14 @@ void dictMergeFromSeq2(BoxedDict* self, Box* other) {
if (element->cls == list_cls) { if (element->cls == list_cls) {
BoxedList* list = static_cast<BoxedList*>(element); BoxedList* list = static_cast<BoxedList*>(element);
if (list->size != 2) if (list->size != 2)
raiseExcHelper(ValueError, "dictionary update sequence element #%d has length %d; 2 is required", idx, raiseExcHelper(ValueError, "dictionary update sequence element #%d has length %ld; 2 is required", idx,
list->size); list->size);
self->d[list->elts->elts[0]] = list->elts->elts[1]; self->d[list->elts->elts[0]] = list->elts->elts[1];
} else if (element->cls == tuple_cls) { } else if (element->cls == tuple_cls) {
BoxedTuple* tuple = static_cast<BoxedTuple*>(element); BoxedTuple* tuple = static_cast<BoxedTuple*>(element);
if (tuple->size() != 2) if (tuple->size() != 2)
raiseExcHelper(ValueError, "dictionary update sequence element #%d has length %d; 2 is required", idx, raiseExcHelper(ValueError, "dictionary update sequence element #%d has length %ld; 2 is required", idx,
tuple->size()); tuple->size());
self->d[tuple->elts[0]] = tuple->elts[1]; self->d[tuple->elts[0]] = tuple->elts[1];
......
...@@ -433,8 +433,7 @@ static PyObject* get_line(BoxedFile* f, int n) noexcept { ...@@ -433,8 +433,7 @@ static PyObject* get_line(BoxedFile* f, int n) noexcept {
Box* fileRead(BoxedFile* self, Box* _size) { Box* fileRead(BoxedFile* self, Box* _size) {
assert(self->cls == file_cls); assert(self->cls == file_cls);
if (_size->cls != int_cls) { if (_size->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n"); raiseExcHelper(TypeError, "an integer is required");
raiseExcHelper(TypeError, "");
} }
int64_t size = static_cast<BoxedInt*>(_size)->n; int64_t size = static_cast<BoxedInt*>(_size)->n;
...@@ -943,12 +942,10 @@ Box* fileNew(BoxedClass* cls, Box* s, Box* m, Box** args) { ...@@ -943,12 +942,10 @@ Box* fileNew(BoxedClass* cls, Box* s, Box* m, Box** args) {
m = _PyUnicode_AsDefaultEncodedString(m, NULL); m = _PyUnicode_AsDefaultEncodedString(m, NULL);
if (s->cls != str_cls) { if (s->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(s)); raiseExcHelper(TypeError, "coercing to Unicode: need string of buffer, %s found", getTypeName(s));
raiseExcHelper(TypeError, "");
} }
if (m->cls != str_cls) { if (m->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(m)); raiseExcHelper(TypeError, "coercing to Unicode: need string of buffer, %s found", getTypeName(m));
raiseExcHelper(TypeError, "");
} }
if (!PyInt_Check(buffering)) if (!PyInt_Check(buffering))
...@@ -1111,7 +1108,7 @@ Box* fileIterNext(BoxedFile* s) { ...@@ -1111,7 +1108,7 @@ Box* fileIterNext(BoxedFile* s) {
Box* rtn = fileReadline1(s); Box* rtn = fileReadline1(s);
assert(!rtn || rtn->cls == str_cls); assert(!rtn || rtn->cls == str_cls);
if (!rtn || ((BoxedString*)rtn)->s().empty()) if (!rtn || ((BoxedString*)rtn)->s().empty())
raiseExcHelper(StopIteration, ""); raiseExcHelper(StopIteration, (const char*)NULL);
return rtn; return rtn;
} }
......
...@@ -103,7 +103,7 @@ Box* seqiterNext(Box* s) { ...@@ -103,7 +103,7 @@ Box* seqiterNext(Box* s) {
else else
RELEASE_ASSERT(0, ""); RELEASE_ASSERT(0, "");
if (hasnext == False) if (hasnext == False)
raiseExcHelper(StopIteration, ""); raiseExcHelper(StopIteration, (const char*)NULL);
} }
RELEASE_ASSERT(self->next, ""); RELEASE_ASSERT(self->next, "");
......
...@@ -121,10 +121,9 @@ extern "C" Box* listPop(BoxedList* self, Box* idx) { ...@@ -121,10 +121,9 @@ extern "C" Box* listPop(BoxedList* self, Box* idx) {
if (n < 0 || n >= self->size) { if (n < 0 || n >= self->size) {
if (self->size == 0) if (self->size == 0)
fprintf(stderr, "IndexError: pop from empty list\n"); raiseExcHelper(IndexError, "pop from empty list");
else else
fprintf(stderr, "IndexError: pop index out of range\n"); raiseExcHelper(IndexError, "pop index out of range");
raiseExcHelper(IndexError, "");
} }
Box* rtn = self->elts->elts[n]; Box* rtn = self->elts->elts[n];
......
...@@ -668,9 +668,8 @@ BoxedLong* _longNew(Box* val, Box* _base) { ...@@ -668,9 +668,8 @@ BoxedLong* _longNew(Box* val, Box* _base) {
Box* r = callattr(val, long_str, callattr_flags, NULL, NULL, NULL, NULL, NULL); Box* r = callattr(val, long_str, callattr_flags, NULL, NULL, NULL, NULL, NULL);
if (!r) { if (!r) {
fprintf(stderr, "TypeError: long() argument must be a string or a number, not '%s'\n", raiseExcHelper(TypeError, "TypeError: long() argument must be a string or a number, not '%s'\n",
getTypeName(val)); getTypeName(val));
raiseExcHelper(TypeError, "");
} }
if (isSubclass(r->cls, int_cls)) { if (isSubclass(r->cls, int_cls)) {
......
...@@ -256,7 +256,7 @@ extern "C" void assertFail(Box* assertion_type, Box* msg) { ...@@ -256,7 +256,7 @@ extern "C" void assertFail(Box* assertion_type, Box* msg) {
BoxedString* tostr = str(msg); BoxedString* tostr = str(msg);
raiseExcHelper(static_cast<BoxedClass*>(assertion_type), "%s", tostr->data()); raiseExcHelper(static_cast<BoxedClass*>(assertion_type), "%s", tostr->data());
} else { } else {
raiseExcHelper(static_cast<BoxedClass*>(assertion_type), ""); raiseExcHelper(static_cast<BoxedClass*>(assertion_type), (const char*)NULL);
} }
} }
...@@ -1222,7 +1222,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1222,7 +1222,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
Box* rtn = *reinterpret_cast<Box**>((char*)obj + member_desc->offset); Box* rtn = *reinterpret_cast<Box**>((char*)obj + member_desc->offset);
if (rtn == NULL) { if (rtn == NULL) {
raiseExcHelper(AttributeError, "%.*s", attr_name->size(), attr_name->data()); assert(attr_name->data()[attr_name->size()] == '\0');
raiseExcHelper(AttributeError, "%s", attr_name->data());
} }
return rtn; return rtn;
} }
...@@ -1356,8 +1357,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1356,8 +1357,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
// is of that type. // is of that type.
if (getset_descr->get == NULL) { if (getset_descr->get == NULL) {
raiseExcHelper(AttributeError, "attribute '%.*s' of '%s' object is not readable", attr_name->size(), assert(attr_name->data()[attr_name->size()] == '\0');
attr_name->data(), getTypeName(getset_descr)); raiseExcHelper(AttributeError, "attribute '%s' of '%s' object is not readable", attr_name->data(),
getTypeName(getset_descr));
} }
// Abort because right now we can't call twice in a rewrite // Abort because right now we can't call twice in a rewrite
...@@ -2041,8 +2043,9 @@ bool dataDescriptorSetSpecialCases(Box* obj, Box* val, Box* descr, SetattrRewrit ...@@ -2041,8 +2043,9 @@ bool dataDescriptorSetSpecialCases(Box* obj, Box* val, Box* descr, SetattrRewrit
// TODO type checking goes here // TODO type checking goes here
if (getset_descr->set == NULL) { if (getset_descr->set == NULL) {
raiseExcHelper(AttributeError, "attribute '%.*s' of '%s' objects is not writable", attr_name->size(), assert(attr_name->data()[attr_name->size()] == '\0');
attr_name->data(), getTypeName(obj)); raiseExcHelper(AttributeError, "attribute '%s' of '%s' objects is not writable", attr_name->data(),
getTypeName(obj));
} }
if (rewrite_args) { if (rewrite_args) {
...@@ -3235,7 +3238,7 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name ...@@ -3235,7 +3238,7 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
Box* ovarargs = BoxedTuple::create(unused_positional.size(), &unused_positional[0]); Box* ovarargs = BoxedTuple::create(unused_positional.size(), &unused_positional[0]);
getArg(varargs_idx, oarg1, oarg2, oarg3, oargs) = ovarargs; getArg(varargs_idx, oarg1, oarg2, oarg3, oargs) = ovarargs;
} else if (unused_positional.size()) { } else if (unused_positional.size()) {
raiseExcHelper(TypeError, "%s() takes at most %d argument%s (%d given)", func_name, paramspec.num_args, raiseExcHelper(TypeError, "%s() takes at most %d argument%s (%ld given)", func_name, paramspec.num_args,
(paramspec.num_args == 1 ? "" : "s"), argspec.num_args + argspec.num_keywords + varargs.size()); (paramspec.num_args == 1 ? "" : "s"), argspec.num_args + argspec.num_keywords + varargs.size());
} }
...@@ -3335,7 +3338,7 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name ...@@ -3335,7 +3338,7 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
for (int i = 0; i < paramspec.num_args - paramspec.num_defaults; i++) { for (int i = 0; i < paramspec.num_args - paramspec.num_defaults; i++) {
if (params_filled[i]) if (params_filled[i])
continue; continue;
raiseExcHelper(TypeError, "%s() takes exactly %d arguments (%d given)", func_name, paramspec.num_args, raiseExcHelper(TypeError, "%s() takes exactly %d arguments (%ld given)", func_name, paramspec.num_args,
argspec.num_args + argspec.num_keywords + varargs.size()); argspec.num_args + argspec.num_keywords + varargs.size());
} }
...@@ -4902,8 +4905,8 @@ extern "C" void delattrGeneric(Box* obj, BoxedString* attr, DelattrRewriteArgs* ...@@ -4902,8 +4905,8 @@ extern "C" void delattrGeneric(Box* obj, BoxedString* attr, DelattrRewriteArgs*
} else { } else {
// the exception cpthon throws is different when the class contains the attribute // the exception cpthon throws is different when the class contains the attribute
if (clsAttr != NULL) { if (clsAttr != NULL) {
raiseExcHelper(AttributeError, "'%s' object attribute '%.*s' is read-only", getTypeName(obj), attr->size(), assert(attr->data()[attr->size()] == '\0');
attr->data()); raiseExcHelper(AttributeError, "'%s' object attribute '%s' is read-only", getTypeName(obj), attr->data());
} else { } else {
assert(attr->data()[attr->size()] == '\0'); assert(attr->data()[attr->size()] == '\0');
raiseAttributeError(obj, attr->s()); raiseAttributeError(obj, attr->s());
......
...@@ -46,7 +46,8 @@ void default_free(void*); ...@@ -46,7 +46,8 @@ void default_free(void*);
void dealloc_null(Box* box); void dealloc_null(Box* box);
// helper function for raising from the runtime: // helper function for raising from the runtime:
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__)); void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__))
__attribute__((format(printf, 2, 3)));
void raiseExcHelper(BoxedClass*, Box* arg) __attribute__((__noreturn__)); void raiseExcHelper(BoxedClass*, Box* arg) __attribute__((__noreturn__));
BoxedModule* getCurrentModule(); BoxedModule* getCurrentModule();
......
...@@ -1185,7 +1185,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1185,7 +1185,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
PyErr_SetString(TypeError, objectNewParameterTypeErrorMsg()); PyErr_SetString(TypeError, objectNewParameterTypeErrorMsg());
return NULL; return NULL;
} else } else
raiseExcHelper(TypeError, objectNewParameterTypeErrorMsg()); raiseExcHelper(TypeError, "%s", objectNewParameterTypeErrorMsg());
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment