Xinliang David Li via llvm-dev
2016-Feb-29 18:38 UTC
[llvm-dev] Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
ok thanks. A more reduced test case can show different behavior between O2 and O0. Say we have unsigned maybe_divide (unsigned *ptr) { int flag = false; unsigned val = 500/ptr[0]; if (flag) return val; return (unsigned)(intptr_t)ptr); } int main() { unsigned g = 0; return maybe_divide(&g); } At O2, it runs fine, but at O0 it core dumps. what is the right behavior? David On Sat, Feb 27, 2016 at 5:21 PM, Sanjoy Das <sanjoy at playingwithpointers.com> wrote:> On Sat, Feb 27, 2016 at 4:21 PM, Xinliang David Li <xinliangli at gmail.com> > wrote: > > So in this case, ptr[0] = 10 is propagated into one copy of maybe_devide > (in > > source a), and ptr[0]=10 in caller_a is DSEed ? > > `ptr[0] = 10` is not really propagated anywhere. What happens is that > `source-a` 's copy of `maybe_divide` gets optimized to a `ret > (unsigned) ptr` (after inlining in the body of `always_false`)[1], so > it is able to DSE the store `ptr[0] = 10`. But `source-b` s copy of > `maybe_divide` still has the load and the division (since it does not > have access to `always_false` 's body), so if `caller_a` ends up > calling that implementation of `maybe_divide`, we get a `SIGFPE`. > > [1]: For reference, after inlining `always_false`, the `maybe_divide` > becomes > > unsigned maybe_divide(unsigned *ptr) { > unsigned val = 500 / ptr[0]; // dead value > if (false) > return val; > return (unsigned)((intptr_t)ptr); > } > > -- Sanjoy >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160229/5fcc38c5/attachment.html>
Mehdi Amini via llvm-dev
2016-Feb-29 18:42 UTC
[llvm-dev] Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
> On Feb 29, 2016, at 10:38 AM, Xinliang David Li via llvm-dev <llvm-dev at lists.llvm.org> wrote: > > ok thanks. A more reduced test case can show different behavior between O2 and O0. > > Say we have > > unsigned maybe_divide (unsigned *ptr) { > int flag = false; > unsigned val = 500/ptr[0]; > if (flag) > return val; > return (unsigned)(intptr_t)ptr); > } > > int main() { > unsigned g = 0; > return maybe_divide(&g); > } > > > At O2, it runs fine, but at O0 it core dumps.I believe this program has a divide by zero and is not correct. By luck the optimization removes the faulty instruction, which does not mean the program is well formed. IMO this is different from Sanjoy's example, where a wrong optimization introduces the error. -- Mehdi> > what is the right behavior? > > David > > > On Sat, Feb 27, 2016 at 5:21 PM, Sanjoy Das <sanjoy at playingwithpointers.com <mailto:sanjoy at playingwithpointers.com>> wrote: > On Sat, Feb 27, 2016 at 4:21 PM, Xinliang David Li <xinliangli at gmail.com <mailto:xinliangli at gmail.com>> wrote: > > So in this case, ptr[0] = 10 is propagated into one copy of maybe_devide (in > > source a), and ptr[0]=10 in caller_a is DSEed ? > > `ptr[0] = 10` is not really propagated anywhere. What happens is that > `source-a` 's copy of `maybe_divide` gets optimized to a `ret > (unsigned) ptr` (after inlining in the body of `always_false`)[1], so > it is able to DSE the store `ptr[0] = 10`. But `source-b` s copy of > `maybe_divide` still has the load and the division (since it does not > have access to `always_false` 's body), so if `caller_a` ends up > calling that implementation of `maybe_divide`, we get a `SIGFPE`. > > [1]: For reference, after inlining `always_false`, the `maybe_divide` > becomes > > unsigned maybe_divide(unsigned *ptr) { > unsigned val = 500 / ptr[0]; // dead value > if (false) > return val; > return (unsigned)((intptr_t)ptr); > } > > -- Sanjoy > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160229/3fe38ca9/attachment.html>
Sanjoy Das via llvm-dev
2016-Feb-29 18:50 UTC
[llvm-dev] Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
On Mon, Feb 29, 2016 at 10:42 AM, Mehdi Amini <mehdi.amini at apple.com> wrote:> > On Feb 29, 2016, at 10:38 AM, Xinliang David Li via llvm-dev > <llvm-dev at lists.llvm.org> wrote: > > ok thanks. A more reduced test case can show different behavior between O2 > and O0. > > Say we have > > unsigned maybe_divide (unsigned *ptr) { > int flag = false; > unsigned val = 500/ptr[0]; > if (flag) > return val; > return (unsigned)(intptr_t)ptr); > } > > int main() { > unsigned g = 0; > return maybe_divide(&g); > } > > > At O2, it runs fine, but at O0 it core dumps. > > > I believe this program has a divide by zero and is not correct. > By luck the optimization removes the faulty instruction, which does not mean > the program is well formed. > > IMO this is different from Sanjoy's example, where a wrong optimization > introduces the error.Yup; in my example there actually is no place where the program divides by zero. Both the call sites that call maybe_divide store a non-zero value to ptr[0] before calling maybe_divide. -- Sanjoy
Apparently Analagous Threads
- Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
- Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
- Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
- Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")
- Possible soundness issue with available_externally (split from "RFC: Add guard intrinsics")