зеркало из https://github.com/mozilla/pjs.git
Bug 572819 - static checking suite: port esp analyses to Dehydra with GCC 4.5 r=taras
This commit is contained in:
Родитель
a37e0d8fe3
Коммит
e3632c2b97
|
@ -33,7 +33,6 @@ function process_tree(fndecl) {
|
|||
|
||||
let cfg = function_decl_cfg(fndecl);
|
||||
|
||||
|
||||
try {
|
||||
let trace = TRACE_ESP;
|
||||
let a = new FlowCheck(cfg, trace);
|
||||
|
@ -63,27 +62,20 @@ function FlowCheck(cfg, trace) {
|
|||
for (let bb in cfg_bb_iterator(cfg)) {
|
||||
for (let isn in bb_isn_iterator(bb)) {
|
||||
switch (isn.tree_code()) {
|
||||
case CALL_EXPR: {
|
||||
let fn = call_function_decl(isn)
|
||||
case GIMPLE_CALL: {
|
||||
let fn = gimple_call_fndecl(isn)
|
||||
if (!fn || decl_name(fn) != FLOW_THROUGH)
|
||||
continue;
|
||||
this.must_flow_fn = fn
|
||||
break
|
||||
}
|
||||
case RETURN_EXPR: {
|
||||
let ret_expr = isn.operands()[0]
|
||||
if (track_return_loc && ret_expr)
|
||||
switch (ret_expr.tree_code()) {
|
||||
case GIMPLE_MODIFY_STMT:
|
||||
this.rval = ret_expr.operands()[1].tree_check(VAR_DECL)
|
||||
break;
|
||||
case RESULT_DECL:
|
||||
this.rval = ret_expr
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unhandled return expression")
|
||||
}
|
||||
}
|
||||
case GIMPLE_RETURN:
|
||||
let ret_expr = return_expr(isn);
|
||||
if (track_return_loc && ret_expr) {
|
||||
TREE_CHECK(ret_expr, VAR_DECL, RESULT_DECL);
|
||||
this.rval = ret_expr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,14 +101,14 @@ function char_star_arg2string(tree) {
|
|||
// another function as either an assignment or a call.
|
||||
FlowCheck.prototype.flowState = function(isn, state) {
|
||||
switch (TREE_CODE(isn)) {
|
||||
case CALL_EXPR: {
|
||||
let fn = call_function_decl(isn)
|
||||
case GIMPLE_CALL: {
|
||||
let fn = gimple_call_fndecl(isn)
|
||||
if (fn == this.must_flow_fn)
|
||||
state.assignValue(fn, char_star_arg2string(call_arg(isn, 0)), isn)
|
||||
state.assignValue(fn, char_star_arg2string(gimple_call_arg(isn, 0)), isn)
|
||||
break
|
||||
}
|
||||
case LABEL_EXPR: {
|
||||
let label = decl_name(isn.operands()[0])
|
||||
case GIMPLE_LABEL: {
|
||||
let label = decl_name(gimple_op(isn, 0))
|
||||
for ([value, blame] in state.yieldPreconditions(this.must_flow_fn)) {
|
||||
if (label != value) continue
|
||||
// reached the goto label we wanted =D
|
||||
|
@ -124,7 +116,7 @@ FlowCheck.prototype.flowState = function(isn, state) {
|
|||
}
|
||||
break
|
||||
}
|
||||
case RETURN_EXPR: {
|
||||
case GIMPLE_RETURN:
|
||||
for ([value, blame] in state.yieldPreconditions(this.must_flow_fn)) {
|
||||
if (typeof value != 'string') continue
|
||||
let loc;
|
||||
|
@ -137,9 +129,8 @@ FlowCheck.prototype.flowState = function(isn, state) {
|
|||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
case GIMPLE_MODIFY_STMT:
|
||||
if (track_return_loc && isn.operands()[0] == this.rval) {
|
||||
case GIMPLE_ASSIGN:
|
||||
if (track_return_loc && gimple_op(isn, 0) == this.rval) {
|
||||
state.assignValue(this.rval, location_of(isn), isn)
|
||||
break
|
||||
}
|
||||
|
|
|
@ -14,27 +14,23 @@ function MayReturnAnalysis() {
|
|||
MayReturnAnalysis.prototype = new BackwardAnalysis;
|
||||
|
||||
MayReturnAnalysis.prototype.flowState = function(isn, state) {
|
||||
if (TREE_CODE(isn) == RETURN_EXPR) {
|
||||
let gms = TREE_OPERAND(isn, 0);
|
||||
if (gms) {
|
||||
// gms is usually a GIMPLE_MODIFY_STMT but can be a RESULT_DECL
|
||||
if (TREE_CODE(gms) == GIMPLE_MODIFY_STMT) {
|
||||
let v = GIMPLE_STMT_OPERAND(gms, 1);
|
||||
this.vbls.add(v);
|
||||
state.add(v);
|
||||
this.retvar = v;
|
||||
} else if (TREE_CODE(gms) == RESULT_DECL) {
|
||||
throw new Error("Weird case hit");
|
||||
}
|
||||
}
|
||||
} else if (TREE_CODE(isn) == GIMPLE_MODIFY_STMT) {
|
||||
let lhs = GIMPLE_STMT_OPERAND(isn, 0);
|
||||
let rhs = GIMPLE_STMT_OPERAND(isn, 1);
|
||||
if (TREE_CODE(isn) == GIMPLE_RETURN) {
|
||||
let v = return_expr(isn);
|
||||
if (!v)
|
||||
return;
|
||||
if (v.tree_code() == RESULT_DECL) // only an issue with 4.3
|
||||
throw new Error("Weird case hit");
|
||||
this.vbls.add(v);
|
||||
state.add(v);
|
||||
this.retvar = v;
|
||||
} else if (TREE_CODE(isn) == GIMPLE_ASSIGN) {
|
||||
let lhs = gimple_op(isn, 0);
|
||||
let rhs = gimple_op(isn, 1);
|
||||
if (DECL_P(rhs) && DECL_P(lhs) && state.has(lhs)) {
|
||||
this.vbls.add(rhs);
|
||||
state.add(rhs);
|
||||
}
|
||||
|
||||
|
||||
for (let e in isn_defs(isn, 'strong')) {
|
||||
if (DECL_P(e)) {
|
||||
state.remove(e);
|
||||
|
|
|
@ -49,7 +49,7 @@ function process_tree(func_decl) {
|
|||
if (!func_filter(func_decl)) return;
|
||||
|
||||
// Determine outparams and return if function not relevant
|
||||
if (is_constructor(func_decl)) return;
|
||||
if (DECL_CONSTRUCTOR_P(func_decl)) return;
|
||||
let psem = OutparamCheck.prototype.func_param_semantics(func_decl);
|
||||
if (!psem.some(function(x) x.check)) return;
|
||||
let decl = rectify_function_decl(func_decl);
|
||||
|
@ -112,11 +112,6 @@ function process_tree(func_decl) {
|
|||
if (TRACE_PERF) timer_stop(fstring);
|
||||
}
|
||||
|
||||
function is_constructor(function_decl)
|
||||
{
|
||||
return function_decl.decl_common.lang_specific.decl_flags.constructor_attr;
|
||||
}
|
||||
|
||||
// Outparam check analysis
|
||||
function OutparamCheck(cfg, psem_list, outparam_list, retvar, retvar_set,
|
||||
trace) {
|
||||
|
@ -253,14 +248,14 @@ OutparamCheck.prototype.updateEdgeState = function(e) {
|
|||
|
||||
OutparamCheck.prototype.flowState = function(isn, state) {
|
||||
switch (TREE_CODE(isn)) {
|
||||
case GIMPLE_MODIFY_STMT:
|
||||
case GIMPLE_ASSIGN:
|
||||
this.processAssign(isn, state);
|
||||
break;
|
||||
case CALL_EXPR:
|
||||
this.processCall(undefined, isn, isn, state);
|
||||
case GIMPLE_CALL:
|
||||
this.processCall(isn, isn, state);
|
||||
break;
|
||||
case SWITCH_EXPR:
|
||||
case COND_EXPR:
|
||||
case GIMPLE_SWITCH:
|
||||
case GIMPLE_COND:
|
||||
// This gets handled by flowStateCond instead, has no exec effect
|
||||
break;
|
||||
default:
|
||||
|
@ -275,8 +270,8 @@ OutparamCheck.prototype.flowStateCond = function(isn, truth, state) {
|
|||
// For any outparams-specific semantics, we handle it here and then
|
||||
// return. Otherwise we delegate to the zero-nonzero analysis.
|
||||
OutparamCheck.prototype.processAssign = function(isn, state) {
|
||||
let lhs = isn.operands()[0];
|
||||
let rhs = isn.operands()[1];
|
||||
let lhs = gimple_op(isn, 0);
|
||||
let rhs = gimple_op(isn, 1);
|
||||
|
||||
if (DECL_P(lhs)) {
|
||||
// Unwrap NOP_EXPR, which is semantically a copy.
|
||||
|
@ -316,17 +311,8 @@ OutparamCheck.prototype.processAssign = function(isn, state) {
|
|||
}
|
||||
break;
|
||||
case CALL_EXPR:
|
||||
let fname = call_function_name(rhs);
|
||||
if (fname == 'NS_FAILED') {
|
||||
this.processTest(lhs, rhs, av.NONZERO, isn, state);
|
||||
} else if (fname == 'NS_SUCCEEDED') {
|
||||
this.processTest(lhs, rhs, av.ZERO, isn, state);
|
||||
} else if (fname == '__builtin_expect') {
|
||||
// Same as an assign from arg 0 to lhs
|
||||
state.assign(lhs, call_args(rhs)[0], isn);
|
||||
} else {
|
||||
this.processCall(lhs, rhs, isn, state);
|
||||
}
|
||||
/* Embedded CALL_EXPRs are a 4.3 issue */
|
||||
this.processCall(rhs, isn, state, lhs);
|
||||
return;
|
||||
|
||||
case INDIRECT_REF:
|
||||
|
@ -386,7 +372,7 @@ OutparamCheck.prototype.processAssign = function(isn, state) {
|
|||
|
||||
// Handle an assignment x := test(foo) where test is a simple predicate
|
||||
OutparamCheck.prototype.processTest = function(lhs, call, val, blame, state) {
|
||||
let arg = call_arg(call, 0);
|
||||
let arg = gimple_call_arg(call, 0);
|
||||
if (DECL_P(arg)) {
|
||||
this.zeroNonzero.predicate(state, lhs, val, arg, blame);
|
||||
} else {
|
||||
|
@ -395,11 +381,27 @@ OutparamCheck.prototype.processTest = function(lhs, call, val, blame, state) {
|
|||
};
|
||||
|
||||
// The big one: outparam semantics of function calls.
|
||||
OutparamCheck.prototype.processCall = function(dest, expr, blame, state) {
|
||||
let args = call_args(expr);
|
||||
let callable = callable_arg_function_decl(CALL_EXPR_FN(expr));
|
||||
OutparamCheck.prototype.processCall = function(call, blame, state, dest) {
|
||||
if (!dest)
|
||||
dest = gimple_call_lhs(call);
|
||||
|
||||
let args = gimple_call_args(call);
|
||||
let callable = callable_arg_function_decl(gimple_call_fn(call));
|
||||
let psem = this.func_param_semantics(callable);
|
||||
|
||||
let name = function_decl_name(callable);
|
||||
if (name == 'NS_FAILED') {
|
||||
this.processTest(dest, call, av.NONZERO, call, state);
|
||||
return;
|
||||
} else if (name == 'NS_SUCCEEDED') {
|
||||
this.processTest(dest, call, av.ZERO, call, state);
|
||||
return;
|
||||
} else if (name == '__builtin_expect') {
|
||||
// Same as an assign from arg 0 to lhs
|
||||
state.assign(dest, args[0], call);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TRACE_CALL_SEM) {
|
||||
print("param semantics:" + psem);
|
||||
}
|
||||
|
@ -408,7 +410,6 @@ OutparamCheck.prototype.processCall = function(dest, expr, blame, state) {
|
|||
let ct = TREE_TYPE(callable);
|
||||
if (TREE_CODE(ct) == POINTER_TYPE) ct = TREE_TYPE(ct);
|
||||
if (args.length < psem.length || !stdarg_p(ct)) {
|
||||
let name = function_decl_name(callable);
|
||||
// TODO Can __builtin_memcpy write to an outparam? Probably not.
|
||||
if (name != 'operator new' && name != 'operator delete' &&
|
||||
name != 'operator new []' && name != 'operator delete []' &&
|
||||
|
@ -568,7 +569,7 @@ OutparamCheck.prototype.findReturnStmt = function(ss) {
|
|||
|
||||
for (let bb in cfg_bb_iterator(this.cfg)) {
|
||||
for (let isn in bb_isn_iterator(bb)) {
|
||||
if (TREE_CODE(isn) == RETURN_EXPR) {
|
||||
if (isn.tree_code() == GIMPLE_RETURN) {
|
||||
return this.cfg._cached_return = isn;
|
||||
}
|
||||
}
|
||||
|
@ -593,9 +594,8 @@ OutparamCheck.prototype.checkSubstateSuccess = function(ss) {
|
|||
let callMsg;
|
||||
let callName = "";
|
||||
try {
|
||||
let callExpr = blameStmt.tree_check(GIMPLE_MODIFY_STMT).
|
||||
operands()[1].tree_check(CALL_EXPR);
|
||||
let callDecl = callable_arg_function_decl(CALL_EXPR_FN(callExpr));
|
||||
let call = TREE_CHECK(blameStmt, GIMPLE_CALL, GIMPLE_MODIFY_STMT);
|
||||
let callDecl = callable_arg_function_decl(gimple_call_fn(call));
|
||||
|
||||
callMsg = [callDecl, "declared here"];
|
||||
callName = " '" + decl_name(callDecl) + "'";
|
||||
|
@ -798,6 +798,7 @@ function pointer_type_is_outparam(pt) {
|
|||
case ENUMERAL_TYPE:
|
||||
case REAL_TYPE:
|
||||
case UNION_TYPE:
|
||||
case BOOLEAN_TYPE:
|
||||
return true;
|
||||
case RECORD_TYPE:
|
||||
// TODO: should we consider field writes?
|
||||
|
|
Загрузка…
Ссылка в новой задаче