1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
|
// This file is a part of Julia. License is MIT: https://julialang.org/license
// RUN: clang --analyze -Xanalyzer -analyzer-output=text -Xclang -load -Xclang libGCCheckerPlugin%shlibext -I%julia_home/src -I%julia_home/src/support -I%julia_home/usr/include ${CLANGSA_FLAGS} ${CPPFLAGS} ${CFLAGS} -Xclang -analyzer-checker=core,julia.GCChecker --analyzer-no-default-checks -Xclang -verify -x c %s
#include "julia.h"
#include "julia_internal.h"
extern void look_at_value(jl_value_t *v);
extern void process_unrooted(jl_value_t *maybe_unrooted JL_MAYBE_UNROOTED);
extern void jl_gc_safepoint();
void unrooted_argument() {
look_at_value((jl_value_t*)jl_svec1(NULL)); // expected-warning{{Passing non-rooted value as argument to function that may GC}}
// expected-note@-1{{Passing non-rooted value as argument to function}}
// expected-note@-2{{Started tracking value here}}
};
void simple_svec() {
// This is ok, because jl_svecref is non-allocating
jl_svec_t *val = jl_svec1(NULL);
assert(jl_svecref(val, 0) == NULL);
}
jl_value_t *simple_missing_root() {
jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
return jl_svecref(val, 0); // expected-warning{{Argument value may have been GCed}}
// expected-note@-1{{Argument value may have been GCed}}
};
jl_value_t *root_value() {
jl_svec_t *val = jl_svec2(NULL, NULL);
JL_GC_PUSH1(&val);
jl_gc_safepoint();
jl_value_t *ret = jl_svecref(val, 0);
JL_GC_POP();
return ret;
};
void root_value_data() {
jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
jl_value_t **data = jl_svec_data(val);
JL_GC_PUSH1(&val); // expected-note{{GC frame changed here}}
// expected-note@-1{{Value was rooted here}}
jl_gc_safepoint();
look_at_value(*data);
JL_GC_POP(); // expected-note{{GC frame changed here}}
// expected-note@-1{{Root was released here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
*data; // expected-warning{{Creating derivative of value that may have been GCed}}
// expected-note@-1{{Creating derivative of value that may have been GCed}}
};
void root_value_data2() {
jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
jl_value_t **data = jl_svec_data(val);
JL_GC_PUSH1(&val); // expected-note{{GC frame changed here}}
// expected-note@-1{{Value was rooted here}}
jl_gc_safepoint();
look_at_value(data[0]);
JL_GC_POP(); // expected-note{{GC frame changed here}}
// expected-note@-1{{Root was released here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
data[0]; // expected-warning{{Creating derivative of value that may have been GCed}}
// expected-note@-1{{Creating derivative of value that may have been GCed}}
};
void root_value_data3() {
jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
jl_value_t **data = jl_svec_data(val);
JL_GC_PUSH1(&val); // expected-note{{GC frame changed here}}
// expected-note@-1{{Value was rooted here}}
jl_gc_safepoint();
look_at_value(*&data[0]);
JL_GC_POP(); // expected-note{{GC frame changed here}}
// expected-note@-1{{Root was released here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
*&data[0]; // expected-warning{{Creating derivative of value that may have been GCed}}
// expected-note@-1{{Creating derivative of value that may have been GCed}}
};
jl_value_t *existing_root() {
jl_svec_t *val = NULL;
JL_GC_PUSH1(&val);
val = jl_svec1(NULL);
jl_gc_safepoint();
jl_value_t *ret = jl_svecref(val, 0);
JL_GC_POP();
return ret;
};
jl_value_t *late_root() {
jl_svec_t *val = NULL;
val = jl_svec1(NULL); // expected-note {{Started tracking value here}}
jl_gc_safepoint(); // expected-note {{Value may have been GCed here}}
JL_GC_PUSH1(&val); // expected-warning{{Trying to root value which may have been GCed}}
// expected-note@-1{{Trying to root value which may have been GCed}}
jl_value_t *ret = jl_svecref(val, 0);
JL_GC_POP();
return ret;
};
jl_value_t *late_root2() {
jl_svec_t *val = NULL;
jl_svec_t *val2 = NULL;
JL_GC_PUSH1(&val); // expected-note {{GC frame changed here}}
val2 = jl_svec1(NULL); // expected-note {{Started tracking value here}}
jl_gc_safepoint(); // expected-note {{Value may have been GCed here}}
val = val2; // expected-warning{{Trying to root value which may have been GCed}}
// expected-note@-1{{Trying to root value which may have been GCed}}
jl_value_t *ret = jl_svecref(val, 0);
JL_GC_POP();
return ret;
};
jl_value_t *already_freed() {
jl_svec_t *val = NULL;
JL_GC_PUSH1(&val); // expected-note{{GC frame changed here}}
val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
// expected-note@-1{{Value was rooted here}}
JL_GC_POP(); // expected-note{{GC frame changed here}}
// expected-note@-1{{Root was released here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
jl_value_t *ret = jl_svecref(val, 0); // expected-warning{{Argument value may have been GCed}}
// expected-note@-1{{Argument value may have been GCed}}
return ret;
};
int field_access() {
jl_svec_t *val = jl_svec1(NULL); // expected-note {{Started tracking value here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
return val->length == 1; // expected-warning{{Trying to access value which may have been GCed}}
// expected-note@-1{{Trying to access value which may have been GCed}}
}
int pushargs_roots() {
jl_value_t **margs;
jl_svec_t *val = jl_svec1(NULL);;
JL_GC_PUSHARGS(margs, 2);
margs[1] = (jl_value_t*)val;
jl_gc_safepoint();
JL_GC_POP();
return val->length == 1;
}
int pushargs_roots_freed() {
jl_value_t **margs;
jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
JL_GC_PUSHARGS(margs, 1); // expected-note{{GC frame changed here}}
margs[0] = (jl_value_t*)val; // expected-note{{Value was rooted here}}
JL_GC_POP(); // expected-note{{GC frame changed here}}
// expected-note@-1{{Root was released here}}
jl_gc_safepoint(); // expected-note{{Value may have been GCed here}}
return val->length == 1; // expected-warning{{Trying to access value which may have been GCed}}
// expected-note@-1{{Trying to access value which may have been GCed}}
}
int unrooted() {
jl_svec_t *val = jl_svec1(NULL); // expected-note{{Started tracking value here}}
// This is ok
process_unrooted((jl_value_t*)val); // expected-note{{Value may have been GCed here}}
// This is not
return val->length == 1; // expected-warning{{Trying to access value which may have been GCed}}
// expected-note@-1{{Trying to access value which may have been GCed}}
}
extern jl_value_t *global_value JL_GLOBALLY_ROOTED;
void globally_rooted() {
jl_value_t *val = global_value;
jl_gc_safepoint();
look_at_value(val);
JL_GC_PUSH1(&val);
jl_gc_safepoint();
look_at_value(val);
JL_GC_POP();
jl_gc_safepoint();
look_at_value(val);
}
extern jl_value_t *first_array_elem(jl_array_t *a JL_PROPAGATES_ROOT);
void root_propagation(jl_expr_t *expr) {
jl_value_t *val = first_array_elem(expr->args);
jl_gc_safepoint();
look_at_value(val);
}
void argument_propagation(jl_value_t *a) {
jl_svec_t *types = jl_svec2(NULL, NULL);
JL_GC_PUSH1(&types);
jl_value_t *val = jl_svecset(types, 0, jl_typeof(a));
jl_gc_safepoint();
look_at_value(val);
jl_svecset(types, 1, jl_typeof(a));
JL_GC_POP();
}
// New value creation via []
void arg_array(jl_value_t **args) {
jl_gc_safepoint();
jl_value_t *val = args[1];
look_at_value(val);
jl_value_t *val2 = NULL;
JL_GC_PUSH1(&val2);
val2 = val;
JL_GC_POP();
}
// New value creation via ->
void member_expr(jl_expr_t *e) {
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
val = (jl_value_t*)e->args;
JL_GC_POP();
}
void member_expr2(jl_typemap_entry_t *tm) {
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
val = (jl_value_t*)tm->func.linfo;
JL_GC_POP();
}
static inline void look_at_args(jl_value_t **args) {
look_at_value(args[1]);
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
val = args[2];
JL_GC_POP();
}
void pushargs_as_args()
{
jl_value_t **args;
JL_GC_PUSHARGS(args, 5);
look_at_args(args);
JL_GC_POP();
}
static jl_typemap_entry_t *call_cache[10] JL_GLOBALLY_ROOTED;
void global_array2() {
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
val = (jl_value_t*)call_cache[1]->func.linfo;
JL_GC_POP();
}
void global_array3() {
jl_value_t *val = NULL;
jl_typemap_entry_t *tm = NULL;
tm = call_cache[1];
val = (jl_value_t*)tm->func.linfo;
look_at_value(val);
}
void nonconst_loads(jl_svec_t *v)
{
size_t i = jl_svec_len(v);
jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(v);
jl_method_instance_t *mi = data[i];
look_at_value(mi->specTypes);
}
void nonconst_loads2()
{
jl_svec_t *v = jl_svec1(NULL); // expected-note{{Started tracking value here}}
size_t i = jl_svec_len(v);
jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(v);
jl_method_instance_t *mi = data[i]; // expected-note{{No Root to propagate. Tracking}}
look_at_value(mi->specTypes); //expected-warning{{Passing non-rooted value as argument to function that may GC}}
//expected-note@-1{{Passing non-rooted value as argument to function that may GC}}
//expected-note@-2{{No Root to propagate. Tracking}}
}
static inline void look_at_value2(jl_value_t *v) {
look_at_value(v);
}
void mtable(jl_value_t *f) {
look_at_value2((jl_value_t*)jl_gf_mtable(f));
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
val = (jl_value_t*)jl_gf_mtable(f);
JL_GC_POP();
}
void mtable2(jl_value_t **v) {
jl_value_t *val = NULL;
JL_GC_PUSH1(&val);
val = (jl_value_t*)jl_gf_mtable(v[2]);
JL_GC_POP();
}
void tparam0(jl_value_t *atype) {
look_at_value(jl_tparam0(atype));
}
extern jl_value_t *global_atype JL_GLOBALLY_ROOTED;
void tparam0_global() {
look_at_value(jl_tparam0(global_atype));
}
static jl_value_t *some_global JL_GLOBALLY_ROOTED;
void global_copy() {
jl_value_t *local = NULL;
jl_gc_safepoint();
JL_GC_PUSH1(&local);
local = some_global;
some_global = NULL;
jl_gc_safepoint();
look_at_value(some_global);
JL_GC_POP();
}
// Check that rooting the same value twice uses to oldest scope
void scopes() {
jl_value_t *val = (jl_value_t*)jl_svec1(NULL);
JL_GC_PUSH1(&val);
jl_value_t *val2 = val;
JL_GC_PUSH1(&val2);
JL_GC_POP();
jl_gc_safepoint();
look_at_value(val);
JL_GC_POP();
}
jl_module_t *propagation(jl_module_t *m JL_PROPAGATES_ROOT);
void module_member(jl_module_t *m)
{
for(int i=(int)m->usings.len-1; i >= 0; --i) {
jl_module_t *imp = (jl_module_t*)m->usings.items[i];
jl_gc_safepoint();
look_at_value((jl_value_t*)imp);
jl_module_t *prop = propagation(imp);
look_at_value((jl_value_t*)prop);
JL_GC_PUSH1(&imp);
jl_gc_safepoint();
look_at_value((jl_value_t*)imp);
JL_GC_POP();
}
}
int type_type(jl_value_t *v) {
return jl_is_type_type(jl_typeof(v));
}
/* TODO: BROKEN
void assoc_exact_broken(jl_value_t **args, size_t n, int8_t offs, size_t world) {
jl_typemap_level_t *cache = jl_new_typemap_level();
jl_typemap_assoc_exact(cache->any, args, n, offs, world); /expected-warning{{Passing non-rooted value as argument to function that may GC}}
}
*/
void assoc_exact_ok(jl_value_t *args1, jl_value_t **args, size_t n, int8_t offs, size_t world) {
jl_typemap_level_t *cache = jl_new_typemap_level();
JL_GC_PUSH1(&cache);
jl_typemap_assoc_exact(cache->any, args1, args, n, offs, world);
JL_GC_POP();
}
// jl_box_* special cases
void box_special_cases1(int i) {
look_at_value(jl_box_long(i)); // expected-warning{{Passing non-rooted value as argument to function}}
// expected-note@-1{{Passing non-rooted value as argument to function}}
// expected-note@-2{{Started tracking value here}}
}
void box_special_cases2() {
look_at_value(jl_box_long(0));
}
jl_value_t *alloc_something();
jl_value_t *boxed_something() {
jl_value_t *val = alloc_something();
return jl_box_long(jl_datatype_size(val));
}
jl_value_t *alloc_something();
void out_arg(jl_value_t **out JL_REQUIRE_ROOTED_SLOT)
{
jl_value_t *val = alloc_something();
JL_GC_PUSH1(&val);
*out = val;
JL_GC_POP();
}
void foo_out_arg()
{
jl_value_t *val_slot = NULL;
JL_GC_PUSH1(&val_slot);
out_arg(&val_slot);
look_at_value(val_slot);
JL_GC_POP();
}
typedef struct _varbinding {
jl_tvar_t *var;
jl_value_t *lb;
jl_value_t *ub;
} jl_varbinding_t;
extern void escape_vb(jl_varbinding_t **vb);
void stack_rooted(jl_value_t *lb JL_MAYBE_UNROOTED, jl_value_t *ub JL_MAYBE_UNROOTED) {
jl_varbinding_t vb = { NULL, lb, ub };
JL_GC_PUSH2(&vb.lb, &vb.ub);
escape_vb(&vb);
look_at_value(vb.lb);
JL_GC_POP();
}
void JL_NORETURN throw_internal(jl_value_t *e JL_MAYBE_UNROOTED)
{
jl_ptls_t ptls = jl_get_ptls_states();
ptls->sig_exception = e;
jl_gc_unsafe_enter(ptls);
look_at_value(e);
}
|