1
0
forked from 0ad/0ad

Removes dehydra build scripts following 53369d593b. Fixes #4446

Refs d7a057143d.

This was SVN commit r25523.
This commit is contained in:
Vladislav Belov 2021-05-22 14:25:53 +00:00
parent faca950e83
commit 2111f864d4
4 changed files with 0 additions and 415 deletions

View File

@ -1,48 +0,0 @@
Dehydra is a tool that allows custom static analysis of C++ code, with analysis code written in JavaScript, running as a GCC plugin.
This directory has some analysis scripts. The setup is a bit ad hoc and not well tested or integrated into the build system or anything, so use at your own risk.
General usage instructions:
* Run Linux. (It might work on OS X too.)
* Install Dehydra, as per https://developer.mozilla.org/En/Dehydra/Installing_Dehydra
* Build 0 A.D. from build/workspaces/gcc:
export CXX="$HOME/gcc-dehydra/installed/bin/g++ -fplugin=$HOME/gcc-dehydra/dehydra/gcc_treehydra.so -fplugin-arg-gcc_treehydra-script=../../dehydra/printf-type-check.js -DCONFIG_DEHYDRA=1"
make
# (or "make test -j3 -k" to build the engine and tests and to do 3 files in parallel and continue past errors, etc)
* Wait (it's quite slow) and look for the new compiler warnings/errors.
The "tests" directory doesn't actually contain any proper tests, just some example files and expected outputs for rough sanity checking.
Some Dehydra fixes might be needed, depending on what version you use, like:
diff -r 9871caaedb8f dehydra.c
--- a/dehydra.c Sat Mar 12 13:55:41 2011 -0500
+++ b/dehydra.c Wed May 18 19:27:23 2011 +0100
@@ -123,7 +123,7 @@
};
this->fndeclMap = pointer_map_create ();
- this->rt = JS_NewRuntime (0x32L * 1024L * 1024L);
+ this->rt = JS_NewRuntime (0x128L * 1024L * 1024L);
if (this->rt == NULL)
exit(1);
diff -r 9871caaedb8f libs/treehydra.js
--- a/libs/treehydra.js Sat Mar 12 13:55:41 2011 -0500
+++ b/libs/treehydra.js Wed May 18 19:27:23 2011 +0100
@@ -209,6 +209,9 @@
walk_tree (i.stmt (), func, guard, stack);
}
break;
+ case EXPR_STMT:
+ walk_tree (TREE_OPERAND(t, 0), func, guard, stack);
+ break;
case TEMPLATE_PARM_INDEX:
case PTRMEM_CST:
case USING_DECL:

View File

@ -1,302 +0,0 @@
// This script attempts to check argument types of printf/wprintf/scanf/wscanf style functions.
// Mostly it's similar to built-in GCC warning functionality, but with the benefit that it can check
// wchar_t* format strings too.
//
// (This is somewhat duplicating the functionality of https://bug493996.bugzilla.mozilla.org/attachment.cgi?id=388700)
include('treehydra.js');
include('gcc_compat.js');
include('gcc_util.js');
include('gcc_print.js');
// Get string corresponding to string literal expressions
function get_string_constant(expr) {
if (TREE_CODE(expr) == NOP_EXPR)
return get_string_constant(expr.operands()[0]);
else if (TREE_CODE(expr) == ADDR_EXPR && TREE_CODE(expr.operands()[0]) == STRING_CST) {
return expr.operands()[0].string.str;
}
}
function is_vararg(decl) {
// Non-vararg functions end with a VOID_TYPE sentinel
for (var t in flatten_chain(TYPE_ARG_TYPES(TREE_TYPE(decl)))) {
if (TREE_CODE(TREE_VALUE(t)) == VOID_TYPE)
return false;
}
return true;
}
// Return ['a' (ascii) or 'w' (wide), 'printf' or 'scanf', string-index, first-to-check] or undefined
function find_printf_type(decl, loc) {
if (! is_vararg(decl))
return;
var decl_attrs = translate_attributes(DECL_ATTRIBUTES(decl)); // 'user' attrs are here
var type_attrs = translate_attributes(TYPE_ATTRIBUTES(TREE_TYPE(decl))); // 'format' attrs are here
for each (var a in decl_attrs.concat(type_attrs)) {
if (a.name == 'format') {
var start = a.value[1];
var first = a.value[2];
if (a.value[0] == 'printf')
return ['a', 'printf', start, first];
else if (a.value[0] == 'scanf')
return ['a', 'scanf', start, first];
else
error('Unrecognised format attribute type "'+a.value[0]+'"', loc());
} else if (a.name == 'user' && a.value[0].match(/^format/)) {
var [ctype, functype, start, first] = a.value[0].split(/,\s*/).slice(1);
if (first == '+1') first = (+start) + 1; // bit ugly, but lets our macros work easily
return [ctype, functype, start, first];
}
}
var name = decl_name(decl);
// Special cases for functions we use and aren't declared with attributes:
if (name == 'sscanf')
return ['a', 'scanf', 2, 3];
else if (name == 'swscanf')
return ['w', 'scanf', 2, 3];
else if (name == 'snprintf')
return ['a', 'printf', 3, 4];
else if (name == 'wprintf')
return ['w', 'printf', 1, 2];
else if (name == 'fwprintf')
return ['w', 'printf', 2, 3];
else if (name == 'swprintf')
return ['w', 'printf', 3, 4];
// SpiderMonkey:
if (name == 'JS_ReportError')
return ['a', 'printf', 2, 3];
else if (name == 'JS_ReportWarning')
return ['a', 'printf', 2, 3];
// Mongoose:
if (name == 'mg_printf')
return ['a', 'printf', 2, 3];
else if (name == 'mg_snprintf')
return ['a', 'printf', 4, 5];
else if (name == 'send_http_error')
return ['a', 'printf', 4, 5];
else if (name == 'cry')
return ['a', 'printf', 2, 3];
else if (name == 'mg_md5')
return;
// Ignore vararg functions that we know aren't using normal format strings
if (name.match(/^(__builtin_va_start|execlp|open|fcntl|ioctl|sem_open|h_alloc|sys_wopen|ogl_HaveExtensions|JS_ConvertArguments|curl_easy_setopt|curl_easy_getinfo|SMBIOS::FieldInitializer::Read|SMBIOS::FieldStringizer::Write)$/))
return;
warning('Ignoring unannotated vararg function "'+name+'"', loc());
}
function compare_format_type(ctype, functype, fmt, arg, loc) {
var m, len, spec;
if (functype == 'printf') {
m = fmt.match(/^%([-+ #0]*)(\*|\d+)?(\.\*|\.-?\d+)?(hh|h|ll|l|j|z|t|L)?([diouxXfFeEgGaAcspn%])$/);
if (m) {
len = m[4] || '';
spec = m[5];
}
} else if (functype == 'scanf') {
m = fmt.match(/^%(\*?)(\d*)(hh|h|ll|l|j|z|t|L)?([diouxaefgcs[pn%])$/);
if (m) {
len = m[3] || '';
spec = m[4];
}
} else {
error('Internal error: unknown functype '+functype, loc());
return true;
}
if (! spec) {
error('Invalid format specifier "'+fmt+'"', loc());
return true;
}
var t = len+spec;
if (ctype == 'w' && t == 's')
error('Non-portable %s used in wprintf-style function', loc());
if (ctype == 'a' && t == 'hs')
error('Illegal %hs used in printf-style function', loc());
if (functype == 'printf') {
if (t.match(/^[dic]$/))
return (arg == 'int');
if (t.match(/^[ouxX]$/))
return (arg == 'unsigned int');
if (t.match(/^lc$/))
return (arg == 'int' || arg == 'unsigned int'); // spec says wint_t
if (t.match(/^l[di]$/))
return (arg == 'long int');
if (t.match(/^l[ouxX]$/))
return (arg == 'long unsigned int');
if (t.match(/^ll[di]$/))
return (arg == 'long long int');
if (t.match(/^ll[ouxX]$/))
return (arg == 'long long unsigned int');
if (t.match(/^[fFeEgGaA]$/))
return (arg == 'double');
if (t.match(/^p$/))
return (arg.match(/\*$/));
// ...
} else if (functype == 'scanf') {
if (t.match(/^[di]$/))
return (arg == 'int*');
if (t.match(/^[ouxX]$/))
return (arg == 'unsigned int*');
if (t.match(/^l[di]$/))
return (arg == 'long int*');
if (t.match(/^l[ouxX]$/))
return (arg == 'long unsigned int*');
if (t.match(/^z[diouxX]$/))
return (arg == 'long unsigned int*'); // spec says size_t*
if (t.match(/^[c[]$/))
return (arg == 'char*' || arg == 'unsigned char*');
if (t.match(/^l[c[]$/))
return (arg == 'wchar_t*');
if (t.match(/^[aefg]$/))
return (arg == 'float*');
if (t.match(/^l[aefg]$/))
return (arg == 'double*');
if (t.match(/^n$/))
return (arg == 'int*');
// ...
}
if (t.match(/^h?s$/))
return (arg.match(/^(const )?(unsigned )?char\*$/));
if (t.match(/^ls$/))
return (arg.match(/^(const )?(unsigned )?wchar_t\*$/));
error('Unrecognized format specifier "'+fmt+'"', loc());
return true;
}
function check_arg_types(ctype, functype, fmt_string, arg_type_names, loc) {
// Match a superset of printf and scanf format strings
var fmt_types = fmt_string.match(/%([-+ #0*]*)(\*|\d+)?(\.\*|\.-?\d+)?(hh|h|ll|l|j|z|t|L)?(.)/g);
var num_fmt_types = 0;
for each (var fmt_type in fmt_types) {
if (fmt_type != '%%')
++num_fmt_types;
if (functype == 'printf') {
// In printf, each '*' eats an extra argument
var stars = fmt_type.match(/\*/g);
if (stars)
num_fmt_types += stars.length;
} else if (functype == 'scanf') {
// In scanf, a '*' prefix means the argument is omitted
if (fmt_type.match(/^%\*/))
--num_fmt_types;
}
}
if (num_fmt_types != arg_type_names.length) {
error('Number of format string specifiers ('+num_fmt_types+') != number of format arguments ('+arg_type_names.length+')', loc());
return;
}
for each (var fmt_type in fmt_types) {
if (fmt_type != '%%') {
if (functype == 'printf') {
// In printf, each '*' eats an extra argument of type int
var stars = fmt_type.match(/\*/g);
if (stars) {
for (var s in stars) {
var arg = arg_type_names.shift();
if (! compare_format_type(ctype, functype, '%d', arg, loc)) {
error('Invalid argument type "'+arg+'" for format specifier "'+fmt_type+'"', loc());
}
}
}
} else if (functype == 'scanf') {
// In scanf, a '*' prefix means the argument is omitted
if (fmt_type.match(/^%\*/))
continue;
}
var arg = arg_type_names.shift();
if (! compare_format_type(ctype, functype, fmt_type, arg, loc)) {
error('Invalid argument type "'+arg+'" for format specifier "'+fmt_type+'"', loc());
}
}
}
if (arg_type_names.length) {
error('Internal error: got some arg types left over');
}
}
function type_string_without_typedefs(type) {
// Walk up the typedef chain
while (TYPE_NAME(type) && TREE_CODE(TYPE_NAME(type)) == TYPE_DECL && DECL_ORIGINAL_TYPE(TYPE_NAME(type)))
type = DECL_ORIGINAL_TYPE(TYPE_NAME(type));
// Recursively strip typedefs from pointer types
if (TREE_CODE(type) == POINTER_TYPE) {
// This bit is copied from type_string():
let quals = [];
if (TYPE_VOLATILE(type)) quals.push('volatile');
if (TYPE_RESTRICT(type)) quals.push('restrict');
if (TYPE_READONLY(type)) quals.push('const');
var suffix = quals.length ? ' ' + quals.join(' ') : '';
return type_string_without_typedefs(TREE_TYPE(type)) + '*' + suffix;
} else {
return type_string(type);
}
}
function walk_printfs(fndecl) {
function tree_walker(t, stack) {
function getLocation() {
var loc = location_of(t);
if (loc) return loc;
for (var i = stack.length - 1; i >= 0; --i) {
var loc = location_of(stack[i]);
if (loc) return loc;
}
return location_of(DECL_SAVED_TREE(fndecl));
}
var code = TREE_CODE(t);
if (code == CALL_EXPR) {
var decl = call_function_decl(t);
if (! decl)
return true;
var printf_type = find_printf_type(decl, getLocation);
if (! printf_type)
return true;
// print('--------------');
// print(rectify_function_decl(decl));
// print(printf_type);
var fmt_arg = CALL_EXPR_ARG(t, printf_type[2]-1);
var fmt_string = get_string_constant(fmt_arg);
if (typeof fmt_string == 'undefined') {
warning('Non-constant format string argument - can\'t check types', getLocation());
return true;
}
var arg_type_names = [];
for (var operand in call_arg_iterator(t)) {
var type = type_string_without_typedefs(TREE_TYPE(operand));
arg_type_names.push(type);
}
check_arg_types(printf_type[0], printf_type[1], fmt_string, arg_type_names.slice(printf_type[3]-1), getLocation);
}
return true;
}
walk_tree (DECL_SAVED_TREE(fndecl), tree_walker);
}
function process_cp_pre_genericize(fndecl) {
walk_printfs(fndecl);
}

View File

@ -1,45 +0,0 @@
#include <cstdio>
#include <cwchar>
extern void foo(const char*, ...) __attribute__((user("format, a, printf, 1, 2")));
extern void bar(const char*, ...) __attribute__((format(printf, 1, 2)));
extern void baz(const char*, ...);
extern void qux(const char*);
int main() {
const char* s = "%s";
char buf[256];
typedef int i32;
typedef unsigned char u8;
i32 n = 2;
printf("%d\n", 123);
printf("%z\n", 123);
printf("%d\n", (unsigned long)123);
printf("%lu\n", (long)123);
printf("%d%%\n", 123.0);
printf("%d %+02.7x\n", 123, 456);
foo("%s", 1);
foo("%s", n);
foo("%d", (u8*)"x");
foo("%s", (unsigned short)3);
bar("%s", 1);
baz("%s", 1);
qux("%s");
bar("xyz\0%s");
printf(s, "x");
printf("%s", "x");
printf("%d%d", 1, n);
printf("%s", L"x");
sprintf(buf, "%s", "x");
sprintf(buf, "%s", L"x");
wprintf(L"%s", "x");
wprintf(L"%s", L"x");
wprintf(L"%hs", "x");
wprintf(L"%hs", L"x");
wprintf(L"%ls", "x");
wprintf(L"%ls", L"x");
printf("%.*ls", 1, L"xy");
printf("%.*ls", L"z", L"xy");
printf("%.*ls", L"xy");
}

View File

@ -1,20 +0,0 @@
tests/printf-type-check.cpp: In function ‘int main()’:
tests/printf-type-check.cpp:17:23: error: Invalid format specifier "%z"
tests/printf-type-check.cpp:18:38: error: Invalid argument type "long unsigned int" for format specifier "%d"
tests/printf-type-check.cpp:20:27: error: Invalid argument type "double" for format specifier "%d"
tests/printf-type-check.cpp:22:16: error: Invalid argument type "int" for format specifier "%s"
tests/printf-type-check.cpp:23:16: error: Invalid argument type "int" for format specifier "%s"
tests/printf-type-check.cpp:24:23: error: Invalid argument type "unsigned char*" for format specifier "%d"
tests/printf-type-check.cpp:25:32: error: Invalid argument type "int" for format specifier "%s"
tests/printf-type-check.cpp:26:16: error: Invalid argument type "int" for format specifier "%s"
tests/printf-type-check.cpp:27:16: warning: Ignoring unannotated vararg function "baz"
tests/printf-type-check.cpp:29:18: error: Number of format string specifiers (1) != number of format arguments (0)
tests/printf-type-check.cpp:30:18: warning: Non-constant format string argument - can't check types
tests/printf-type-check.cpp:33:22: error: Invalid argument type "const wchar_t*" for format specifier "%s"
tests/printf-type-check.cpp:36:23: error: Non-portable %s used in wprintf-style function
tests/printf-type-check.cpp:37:24: error: Non-portable %s used in wprintf-style function
tests/printf-type-check.cpp:37:24: error: Invalid argument type "const wchar_t*" for format specifier "%s"
tests/printf-type-check.cpp:39:25: error: Invalid argument type "const wchar_t*" for format specifier "%hs"
tests/printf-type-check.cpp:40:24: error: Invalid argument type "const char*" for format specifier "%ls"
tests/printf-type-check.cpp:43:32: error: Invalid argument type "const wchar_t*" for format specifier "%.*ls"
tests/printf-type-check.cpp:44:26: error: Number of format string specifiers (2) != number of format arguments (1)