On Mon, Jun 04, 2012 at 10:34:21AM +0200, Florian Weimer wrote: > >>+This protection mechanism is only a last resort. As a programmer, you > >>+must not rely on its presence, but use explicit buffer length checks > >>+to avoid buffer overflows. GCC may not be able to determine buffer > >>+sizes accurately, and the accuracy depends on compiler version and > >>+optimization level (currently, at least @option{-O2} is required). > > > >That isn't true, at -O1 or -Os it should work just fine too, and > >to some extent on the compiler side even at -O0. > > Fold needs to run. Without it, __builtin_object_size constantly
Folding is performed at all optimization levels. The objsz pass is only performed at -O1 and above (as it is among optimization passes). So say on: char buf[64]; int f1 (void) { return __builtin_object_size (buf, 0); } int f2 (void) { return __builtin_object_size (&buf[4], 0); } static inline int __attribute__((always_inline)) f3 (char *p) { return __builtin_object_size (p, 0); } int f4 (void) { return f3 (buf); } int f5 (void) { return f3 (&buf[4]); } int f6 (void) { char *q = buf; return f3 (q); } int f7 (void) { struct S { char *q; } s; s.q = buf; return f3 (s.q); } at -O0 f1 returns 64 and f2 returns 60, but due to not performing objsz f[4567] already return -1. By running the objsz pass even at -O0 (as done in the attached pass) even f[456] could return 64 resp. 60, though of course as it isn't optimizing, many other cases wouldn't be determined accurately, e.g f7 due to SRA not being performed. Still, it is purely glibc decision not to do fortification at -O0. --- gcc/passes.c.jj 2012-06-01 14:41:05.000000000 +0200 +++ gcc/passes.c 2012-06-04 10:49:50.581693645 +0200 @@ -1501,6 +1501,7 @@ init_optimization_passes (void) NEXT_PASS (pass_tm_edges); } NEXT_PASS (pass_lower_complex_O0); + NEXT_PASS (pass_object_sizes_O0); NEXT_PASS (pass_cleanup_eh); NEXT_PASS (pass_lower_resx); NEXT_PASS (pass_nrv); --- gcc/tree-pass.h.jj 2012-05-12 10:21:06.000000000 +0200 +++ gcc/tree-pass.h 2012-05-12 10:21:06.000000000 +0200 @@ -411,6 +411,7 @@ extern struct gimple_opt_pass pass_diagn extern struct gimple_opt_pass pass_expand_omp; extern struct gimple_opt_pass pass_expand_omp_ssa; extern struct gimple_opt_pass pass_object_sizes; +extern struct gimple_opt_pass pass_object_sizes_O0; extern struct gimple_opt_pass pass_strlen; extern struct gimple_opt_pass pass_fold_builtins; extern struct gimple_opt_pass pass_stdarg; --- gcc/tree-object-size.c.jj 2011-12-16 08:37:45.000000000 +0100 +++ gcc/tree-object-size.c 2012-06-04 10:52:35.033699016 +0200 @@ -1285,3 +1285,28 @@ struct gimple_opt_pass pass_object_sizes TODO_verify_ssa /* todo_flags_finish */ } }; + +static bool +gate_object_sizes_O0 (void) +{ + return !optimize; +} + +struct gimple_opt_pass pass_object_sizes_O0 = +{ + { + GIMPLE_PASS, + "objsz0", /* name */ + gate_object_sizes_O0, /* gate */ + compute_object_sizes, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_NONE, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_verify_ssa /* todo_flags_finish */ + } +}; Jakub