Closed
Bug 1175485
Opened 9 years ago
Closed 9 years ago
ReverseIterator contains undefined behavior when used with IntegerRange, EnumeratedRange and nsFrameList
Categories
(Core :: MFBT, defect)
Core
MFBT
Tracking
()
RESOLVED
FIXED
mozilla42
People
(Reporter: xidorn, Assigned: xidorn)
References
Details
Attachments
(4 files, 5 obsolete files)
(deleted),
patch
|
Waldo
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
Waldo
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
Waldo
:
review+
|
Details | Diff | Splinter Review |
(deleted),
patch
|
Waldo
:
review+
|
Details | Diff | Splinter Review |
It seems to me that there are compiler bug in Clang and GCC which mis-optimize code combines Reversed() with MakeRange().
If we have code
> for (auto i : Reversed(MakeRange(n))) {
> std::cout << i << std::endl;
> }
we expect that it outputs [0, n) reversely.
However, on GCC with -O1 or higher, it outputs n times of 0, and on Clang with -O2 or higher, it outputs a 0 and then (n-1) times of several weird numbers.
Interestingly, if I compile that on Clang with -fsanitize=undefined, the output would be n times of weird numbers. If compile with -fsanitize=integer, the program outputs [1,n] reversely.
What may help is compiling on Clang with -fsanitize=memory. It reports use-of-uninitialized-value error for MakeRange().
If I expand everything explicitly to:
> auto range = MakeRange(n);
> auto iter = range.begin();
> auto end = range.end();
> while (true) {
> bool done = (iter == end);
> std::cout << done << std::endl;
> if (done) {
> break;
> }
> auto i = *iter;
> std::cout << i << std::endl;
> ++iter;
> }
The memory sanitizer reports that error on the line "if (done) {", which doesn't make sense at all.
Assignee | ||
Comment 1•9 years ago
|
||
This problem is because that the current impl of ReverseIterator contains an undefined behavior that we returns a reference of a variable in the current stack frame.
Summary: Clang and GCC mis-optimize code combines Reversed() with MakeRange() → ReverseIterator contains undefined behavior when used with IntegerRange and nsFrameList
Assignee | ||
Updated•9 years ago
|
Assignee: nobody → quanxunzhen
Assignee | ||
Comment 2•9 years ago
|
||
Attachment #8624057 -
Flags: review?(roc)
Attachment #8624057 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 3•9 years ago
|
||
Attachment #8624058 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 4•9 years ago
|
||
Attachment #8624059 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 5•9 years ago
|
||
Attachment #8624060 -
Flags: review?(jwalden+bmo)
Attachment #8624057 -
Flags: review?(roc) → review+
Assignee | ||
Comment 6•9 years ago
|
||
Attachment #8624060 -
Attachment is obsolete: true
Attachment #8624060 -
Flags: review?(jwalden+bmo)
Attachment #8624112 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 7•9 years ago
|
||
Assignee | ||
Updated•9 years ago
|
Assignee | ||
Updated•9 years ago
|
status-firefox38:
--- → affected
status-firefox38.0.5:
--- → affected
status-firefox39:
--- → affected
status-firefox40:
--- → affected
Assignee | ||
Comment 8•9 years ago
|
||
Errr, EnumeratedRange has the same issue...
Summary: ReverseIterator contains undefined behavior when used with IntegerRange and nsFrameList → ReverseIterator contains undefined behavior when used with IntegerRange, EnumeratedRange and nsFrameList
Assignee | ||
Comment 9•9 years ago
|
||
Attachment #8624057 -
Attachment is obsolete: true
Attachment #8624057 -
Flags: review?(jwalden+bmo)
Attachment #8624601 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 10•9 years ago
|
||
Attachment #8624059 -
Attachment is obsolete: true
Attachment #8624059 -
Flags: review?(jwalden+bmo)
Attachment #8624603 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 11•9 years ago
|
||
Attachment #8624112 -
Attachment is obsolete: true
Attachment #8624112 -
Flags: review?(jwalden+bmo)
Attachment #8624604 -
Flags: review?(jwalden+bmo)
Assignee | ||
Comment 12•9 years ago
|
||
Attachment #8624604 -
Attachment is obsolete: true
Attachment #8624604 -
Flags: review?(jwalden+bmo)
Attachment #8624640 -
Flags: review?(jwalden+bmo)
Comment 13•9 years ago
|
||
Comment on attachment 8624601 [details] [diff] [review]
patch 1 - change return type of operator*() of several iterators, r=roc
Review of attachment 8624601 [details] [diff] [review]:
-----------------------------------------------------------------
::: mfbt/EnumeratedRange.h
@@ +24,1 @@
> #include "mozilla/IntegerTypeTraits.h"
Flip these to preserve alphabetical ordering.
::: mfbt/ReverseIterator.h
@@ +15,2 @@
> #include "mozilla/Attributes.h"
> #include "mozilla/IteratorTraits.h"
Alphabetize, again.
@@ +31,5 @@
> template<typename Iterator>
> MOZ_IMPLICIT ReverseIterator(const ReverseIterator<Iterator>& aOther)
> : mCurrent(aOther.mCurrent) { }
>
> + auto operator*() const -> decltype(*DeclVal<IteratorT>())
I think you want to uUse this decltype as the type in the ValueType typedef above, right?
Attachment #8624601 -
Flags: review?(jwalden+bmo) → review+
Comment 14•9 years ago
|
||
Comment on attachment 8624058 [details] [diff] [review]
patch 2 - add static_assert to ensure MakeRange used with integer
Review of attachment 8624058 [details] [diff] [review]:
-----------------------------------------------------------------
::: mfbt/IntegerRange.h
@@ +190,5 @@
> detail::IntegerRange<IntType2>
> MakeRange(IntType1 aBegin, IntType2 aEnd)
> {
> + static_assert(IsIntegral<IntType1>::value && IsIntegral<IntType2>::value,
> + "Values must both be integral");
Lowercase "value" and "values" in these, as I believe compilers generally treat the assertion message as a sentence fragment.
Attachment #8624058 -
Flags: review?(jwalden+bmo) → review+
Assignee | ||
Comment 15•9 years ago
|
||
(In reply to Jeff Walden [:Waldo] (remove +bmo to email) from comment #13)
> Comment on attachment 8624601 [details] [diff] [review]
> patch 1 - change return type of operator*() of several iterators, r=roc
>
> Review of attachment 8624601 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: mfbt/EnumeratedRange.h
> @@ +24,1 @@
> > #include "mozilla/IntegerTypeTraits.h"
>
> Flip these to preserve alphabetical ordering.
>
> ::: mfbt/ReverseIterator.h
> @@ +15,2 @@
> > #include "mozilla/Attributes.h"
> > #include "mozilla/IteratorTraits.h"
>
> Alphabetize, again.
>
> @@ +31,5 @@
> > template<typename Iterator>
> > MOZ_IMPLICIT ReverseIterator(const ReverseIterator<Iterator>& aOther)
> > : mCurrent(aOther.mCurrent) { }
> >
> > + auto operator*() const -> decltype(*DeclVal<IteratorT>())
>
> I think you want to uUse this decltype as the type in the ValueType typedef
> above, right?
No. If we want a typedef for the return value of operator*(), it should be ReferenceType. But I don't think it helps a lot to introduce a new typedef here. Actually, I remove the useless ValueType and DifferenceType in patch 3.
Comment 16•9 years ago
|
||
Comment on attachment 8624603 [details] [diff] [review]
patch 3 - remove unused operators and traits
Review of attachment 8624603 [details] [diff] [review]:
-----------------------------------------------------------------
::: mfbt/ReverseIterator.h
@@ -22,5 @@
> {
> public:
> - typedef typename IteratorTraits<IteratorT>::ValueType ValueType;
> - typedef typename IteratorTraits<IteratorT>::DifferenceType DifferenceType;
> -
Ah, yes, I see you removed these later.
That said, thinking slightly more, is there a reason you have to use auto -> syntax? Couldn't you just use |decltype(*DeclVal<IteratorT>()) operator*() const| to avoid the extra indirection of auto+trailing return type?
Attachment #8624603 -
Flags: review?(jwalden+bmo) → review+
Comment 17•9 years ago
|
||
Comment on attachment 8624640 [details] [diff] [review]
patch 4 - unittest for integer range
Review of attachment 8624640 [details] [diff] [review]:
-----------------------------------------------------------------
::: mfbt/tests/TestIntegerRange.cpp
@@ +5,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +#include "mozilla/Assertions.h"
> +#include "mozilla/IntegerRange.h"
> +#include <cstdlib>
What are you using from <cstdlib>? I don't see anything here except size_t and ptrdiff_t, maybe. But those are in <stddef.h>, and you should use that header to access them.
Also, blank line before the standard-library include.
@@ +7,5 @@
> +#include "mozilla/Assertions.h"
> +#include "mozilla/IntegerRange.h"
> +#include <cstdlib>
> +
> +using namespace mozilla;
Policy is to only |using| specific symbols, not open up the entire namespace. Break this up:
using mozilla::IsSame;
using mozilla::MakeRange;
using mozilla::Reversed;
I think that's the full list, add others as needed.
@@ +10,5 @@
> +
> +using namespace mozilla;
> +
> +#define MAX_NUMBER 50
> +#define ARRAY_SIZE 256
const size_t for both of htese.
Attachment #8624640 -
Flags: review?(jwalden+bmo) → review+
Assignee | ||
Comment 18•9 years ago
|
||
(In reply to Jeff Walden [:Waldo] (remove +bmo to email) from comment #16)
> That said, thinking slightly more, is there a reason you have to use auto ->
> syntax? Couldn't you just use |decltype(*DeclVal<IteratorT>()) operator*()
> const| to avoid the extra indirection of auto+trailing return type?
Yes, if you prefer that style. I thought using auto -> syntax looks more clear, though.
Comment 19•9 years ago
|
||
Comment 20•9 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/13b68b2357f9
https://hg.mozilla.org/mozilla-central/rev/addb5b055383
https://hg.mozilla.org/mozilla-central/rev/685a87f8677c
https://hg.mozilla.org/mozilla-central/rev/61cae4c32db5
Status: NEW → RESOLVED
Closed: 9 years ago
status-firefox42:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla42
Updated•5 years ago
|
You need to log in
before you can comment on or make changes to this bug.
Description
•