(Please note that in all the following code no standard libaries are linked - this is for a bare-metal kernel project.)
The following code (full header/assembly attached below): Iterator &operator ++ () { m_Node = (m_Node->*FunctionNext)(); return *this; } When instantiated as: template<typename T> struct _ListNode_t { /** Get the next data structure in the list *\return pointer to the next data structure in the list */ _ListNode_t *next() {return m_Next;} /** Get the previous data structure in the list *\return pointer to the previous data structure in the list */ _ListNode_t *previous() {return m_Previous;} /** Pointer to the next node */ _ListNode_t *m_Next; /** Pointer to the previous node */ _ListNode_t *m_Previous; /** The value of the node */ T value; }; ** List template specialisation for void* *\brief List template specialisation for void* */ template<> class List<void*> { /** The data structure of the list's nodes */ typedef _ListNode_t<void*> node_t; public: /** Type of the bidirectional iterator */ typedef ::Iterator<void*, node_t> Iterator; ... Produces the following (dis)assembly: 00000000 <_ZN8IteratorIPv11_ListNode_tIS0_EXadL_ZNS2_8previousEvEEXadL_ZNS2_4nextEvEES0_EppEv>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 08 sub $0x8,%esp 6: b8 00 00 00 00 mov $0x0,%eax 7: R_386_32 _ZN11_ListNode_tIPvE4nextEv b: 83 e0 01 and $0x1,%eax e: 84 c0 test %al,%al 10: 74 16 je 28 <_ZN8IteratorIPv11_ListNode_tIS0_EXadL_ZNS2_8previousEvEEXadL_ZNS2_4nextEvEES0_EppEv+0x28> 12: 8b 45 08 mov 0x8(%ebp),%eax 15: 8b 00 mov (%eax),%eax 17: 8b 10 mov (%eax),%edx 19: b8 ff ff ff ff mov $0xffffffff,%eax 1a: R_386_32 _ZN11_ListNode_tIPvE4nextEv 1e: 8d 04 02 lea (%edx,%eax,1),%eax 21: 8b 00 mov (%eax),%eax 23: 89 45 fc mov %eax,-0x4(%ebp) 26: eb 07 jmp 2f <_ZN8IteratorIPv11_ListNode_tIS0_EXadL_ZNS2_8previousEvEEXadL_ZNS2_4nextEvEES0_EppEv+0x2f> 28: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp) 2b: R_386_32 _ZN11_ListNode_tIPvE4nextEv 2f: 8b 45 08 mov 0x8(%ebp),%eax 32: 8b 00 mov (%eax),%eax 34: 83 ec 0c sub $0xc,%esp 37: 50 push %eax 38: ff 55 fc call *-0x4(%ebp) 3b: 83 c4 10 add $0x10,%esp 3e: 89 c2 mov %eax,%edx 40: 8b 45 08 mov 0x8(%ebp),%eax 43: 89 10 mov %edx,(%eax) 45: 8b 45 08 mov 0x8(%ebp),%eax 48: c9 leave 49: c3 ret Notice that the AND instruction tests the least significant bit of the address of ListNode::next(). The code path changes depending on this - if it is zero, that is the address is 16-bit aligned, the second code path is taken which works fine. If the address is not 16-bit aligned, the first path is taken, and it is on taking that path that a segfault (well, actually page fault for me as I'm on bare metal) occurs, on the dereference in the MOV after the LEA. At the point of the LEA, %eax contains the address of ListNode::next(), and %edx contains what appears to be a valid address on my kernel heap. This is seemingly being used as an offset, but with bad consequences. The code fails here. I can only get the code to fail when ListNode::next() is not 16-bit aligned. This code worked perfectly in GCC 4.3.0, and in that version of the compiler the AND/JE pair was not generated - the only code path is the second one. Is this deliberate? Is it a regression? Thanks, James Molloy ------------------------------------------------------ <Iterator.h> /* * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef KERNEL_UTILITIES_ITERATOR_H #define KERNEL_UTILITIES_ITERATOR_H #include <Log.h> /** @addtogroup kernelutilities * @{ */ /** General iterator for structures that provide functions for the next and previous structure * in the datastructure and a "value" member. This template provides a bidirectional, a constant * bidirectional, a reverse bidirectional and a constant reverse bidirectional iterator. *\brief An iterator applicable for many data structures *\param[in] originalT the original element type of the iterator *\param[in] Struct the datastructure that provides functions for the next/previous datastructure * and a "value" member *\param[in] previous pointer to the member function used to iterate forward *\param[in] next pointer to the member function used to iterate backwards *\param[in] T the real element type of the iterator */ template<typename originalT, class Struct, Struct *(Struct::*FunctionPrev)() = &Struct::previous, Struct *(Struct::*FunctionNext)() = &Struct::next, typename T = originalT> class Iterator { /** All iterators must be friend in order to allow casts between some iterator types */ template<typename _originalT, class _Struct, _Struct *(_Struct::*_FunctionPrev)(), _Struct *(_Struct::*_FunctionNext)(), typename _T> friend class Iterator; /** The assignment operator is extern */ template<typename _originalT, class _Struct, _Struct *(_Struct::*_FunctionPrev)(), _Struct *(_Struct::*_FunctionNext)(), typename _T1, typename _T2> friend bool operator == (const Iterator<_originalT, _Struct, _FunctionPrev, _FunctionNext, _T1> &x1, const Iterator<_originalT, _Struct, _FunctionPrev, _FunctionNext, _T2> &x2); public: /** Type of the constant bidirectional iterator */ typedef Iterator<originalT, Struct, FunctionPrev, FunctionNext, T const> Const; /** Type of the reverse iterator */ typedef Iterator<originalT, Struct, FunctionNext, FunctionPrev, T> Reverse; /** Type of the constant reverse iterator */ typedef Iterator<originalT, Struct, FunctionNext, FunctionPrev, T const> ConstReverse; /** The default constructor constructs an invalid/unusable iterator */ Iterator() : m_Node(){} /** The copy-constructor *\param[in] Iterator the reference object */ Iterator(const Iterator &x) : m_Node(x.m_Node){} /** The constructor *\param[in] Iterator the reference object */ template<typename T2> Iterator(const Iterator<originalT, Struct, FunctionPrev, FunctionNext, T2> &x) : m_Node(x.m_Node){} /** Constructor from a pointer to an instance of the data structure *\param[in] Node pointer to an instance of the data structure */ Iterator(Struct *Node) : m_Node(Node){} /** The destructor does nothing */ ~Iterator(){} /** The assignment operator *\param[in] Iterator the reference object */ Iterator &operator = (const Iterator &x) { m_Node = x.m_Node; return *this; } /** Preincrement operator */ Iterator &operator ++ () { m_Node = (m_Node->*FunctionNext)(); return *this; } /** Predecrement operator */ Iterator &operator -- () { m_Node = (m_Node->*FunctionPrev)(); return *this; } /** Dereference operator yields the element value */ T &operator *() { return m_Node->value; } /** Dereference operator yields the element value */ T &operator ->() { return m_Node->value; } /** Conversion Operator to a constant iterator */ operator Const () { return Const(m_Node); } /** Get the Node */ Struct *__getNode() { return m_Node; } private: /** Pointer to the instance of the data structure or 0 */ Struct *m_Node; }; /** Comparison operator for the Iterator class *\param[in] x1 the first operand *\param[in] x2 the second operand *\return true, if the two iterator point to the same object, false otherwise */ template<typename originalT, class Struct, Struct *(Struct::*FunctionPrev)(), Struct *(Struct::*FunctionNext)(), typename T1, typename T2> bool operator == (const Iterator<originalT, Struct, FunctionPrev, FunctionNext, T1> &x1, const Iterator<originalT, Struct, FunctionPrev, FunctionNext, T2> &x2) { if (x1.m_Node != x2.m_Node)return false; return true; } /** @} */ #endif ------------------------------------ <List.h> /* * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef KERNEL_UTILITIES_LIST_H #define KERNEL_UTILITIES_LIST_H #include <utilities/template.h> #include <processor/types.h> #include <utilities/IteratorAdapter.h> #include <utilities/Iterator.h> #include <Log.h> /** @addtogroup kernelutilities * @{ */ /** One node in the list *\brief One node in the list *\param[in] T the element type */ template<typename T> struct _ListNode_t { /** Get the next data structure in the list *\return pointer to the next data structure in the list */ _ListNode_t *next() {return m_Next;} /** Get the previous data structure in the list *\return pointer to the previous data structure in the list */ _ListNode_t *previous() {return m_Previous;} /** Pointer to the next node */ _ListNode_t *m_Next; /** Pointer to the previous node */ _ListNode_t *m_Previous; /** The value of the node */ T value; }; template<class T> class List; /** List template specialisation for void* *\brief List template specialisation for void* */ template<> class List<void*> { /** The data structure of the list's nodes */ typedef _ListNode_t<void*> node_t; public: /** Type of the bidirectional iterator */ typedef ::Iterator<void*, node_t> Iterator; /** Type of the constant bidirectional iterator */ typedef Iterator::Const ConstIterator; /** Type of the reverse iterator */ typedef Iterator::Reverse ReverseIterator; /** Type of the constant reverse iterator */ typedef Iterator::ConstReverse ConstReverseIterator; /** Default constructor, does nothing */ List(); /** Copy-constructor *\param[in] x reference object */ List(const List &x); /** Destructor, deallocates memory */ ~List(); /** Assignment operator *\param[in] x the object that should be copied */ List &operator = (const List &x); /** Get the number of elements we reserved space for *\return number of elements we reserved space for */ size_t size() const; /** Get the number of elements in the List */ size_t count() const; /** Add a value to the end of the List *\param[in] value the value that should be added */ void pushBack(void *value); /** Remove the last element from the List *\return the previously last element */ void *popBack(); /** Add a value to the front of the List *\param[in] value the value that should be added */ void pushFront(void *value); /** Remove the first element in the List *\return the previously first element */ void *popFront(); /** Erase an element *\param[in] iterator the iterator that points to the element */ Iterator erase(Iterator &Iter); /** Get an iterator pointing to the beginning of the List *\return iterator pointing to the beginning of the List */ inline Iterator begin() { return Iterator(m_First); } /** Get a constant iterator pointing to the beginning of the List *\return constant iterator pointing to the beginning of the List */ inline ConstIterator begin() const { return ConstIterator(m_First); } /** Get an iterator pointing to the end of the List + 1 *\return iterator pointing to the end of the List + 1 */ inline Iterator end() { return Iterator(); } /** Get a constant iterator pointing to the end of the List + 1 *\return constant iterator pointing to the end of the List + 1 */ inline ConstIterator end() const { return ConstIterator(); } /** Get an iterator pointing to the reverse beginning of the List *\return iterator pointing to the reverse beginning of the List */ inline ReverseIterator rbegin() { return ReverseIterator(m_Last); } /** Get a constant iterator pointing to the reverse beginning of the List *\return constant iterator pointing to the reverse beginning of the List */ inline ConstReverseIterator rbegin() const { return ConstReverseIterator(m_Last); } /** Get an iterator pointing to the reverse end of the List + 1 *\return iterator pointing to the reverse end of the List + 1 */ inline ReverseIterator rend() { return ReverseIterator(); } /** Get a constant iterator pointing to the reverse end of the List + 1 *\return constant iterator pointing to the reverse end of the List + 1 */ inline ConstReverseIterator rend() const { return ConstReverseIterator(); } /** Remove all elements from the List */ void clear(); /** Copy the content of a List into this List *\param[in] x the reference List */ void assign(const List &x); private: /** The number of Nodes/Elements in the List */ size_t m_Count; /** Pointer to the first Node in the List */ node_t *m_First; /** Pointer to the last Node in the List */ node_t *m_Last; }; /** List template specialisation for pointers. Just forwards to the * void* template specialisation of List. *\brief List template specialisation for pointers */ template<class T> class List<T*> { public: /** Iterator */ typedef IteratorAdapter<T*, List<void*>::Iterator> Iterator; /** ConstIterator */ typedef IteratorAdapter<T* const, List<void*>::ConstIterator> ConstIterator; /** ReverseIterator */ typedef IteratorAdapter<T*, List<void*>::ReverseIterator> ReverseIterator; /** ConstReverseIterator */ typedef IteratorAdapter<T* const, List<void*>::ConstReverseIterator> ConstReverseIterator; /** Default constructor, does nothing */ inline List() : m_VoidList(){} /** Copy-constructor *\param[in] x reference object */ inline List(const List &x) : m_VoidList(x.m_VoidList){} /** Destructor, deallocates memory */ inline ~List() {} /** Assignment operator *\param[in] x the object that should be copied */ inline List &operator = (const List &x) { m_VoidList = x.m_VoidList; return *this; } /** Get the number of elements we reserved space for *\return number of elements we reserved space for */ inline size_t size() const { return m_VoidList.size(); } /** Get the number of elements in the List */ inline size_t count() const { return m_VoidList.count(); } /** Add a value to the end of the List *\param[in] value the value that should be added */ inline void pushBack(T *value) { m_VoidList.pushBack(reinterpret_cast<void*>(const_cast<typename nonconst_type<T>::type*>(value))); } /** Remove the last element from the List *\return the previously last element */ inline T *popBack() { return reinterpret_cast<T*>(m_VoidList.popBack()); } /** Add a value to the front of the List *\param[in] value the value that should be added */ inline void pushFront(T *value) { m_VoidList.pushFront(reinterpret_cast<void*>(value)); } /** Remove the first element in the List *\return the previously first element */ inline T *popFront() { return reinterpret_cast<T*>(m_VoidList.popFront()); } /** Erase an element *\param[in] iterator the iterator that points to the element */ inline Iterator erase(Iterator &Iter) { return Iterator(m_VoidList.erase(Iter.__getIterator())); } /** Get an iterator pointing to the beginning of the List *\return iterator pointing to the beginning of the List */ inline Iterator begin() { return Iterator(m_VoidList.begin()); } /** Get a constant iterator pointing to the beginning of the List *\return constant iterator pointing to the beginning of the List */ inline ConstIterator begin() const { return ConstIterator(m_VoidList.begin()); } /** Get an iterator pointing to the end of the List + 1 *\return iterator pointing to the end of the List + 1 */ inline Iterator end() { return Iterator(m_VoidList.end()); } /** Get a constant iterator pointing to the end of the List + 1 *\return constant iterator pointing to the end of the List + 1 */ inline ConstIterator end() const { return ConstIterator(m_VoidList.end()); } /** Get an iterator pointing to the reverse beginning of the List *\return iterator pointing to the reverse beginning of the List */ inline ReverseIterator rbegin() { return ReverseIterator(m_VoidList.rbegin()); } /** Get a constant iterator pointing to the reverse beginning of the List *\return constant iterator pointing to the reverse beginning of the List */ inline ConstReverseIterator rbegin() const { return ConstReverseIterator(m_VoidList.rbegin()); } /** Get an iterator pointing to the reverse end of the List + 1 *\return iterator pointing to the reverse end of the List + 1 */ inline ReverseIterator rend() { return ReverseIterator(m_VoidList.rend()); } /** Get a constant iterator pointing to the reverse end of the List + 1 *\return constant iterator pointing to the reverse end of the List + 1 */ inline ConstReverseIterator rend() const { return ConstReverseIterator(m_VoidList.rend()); } /** Remove all elements from the List */ inline void clear() { m_VoidList.clear(); } /** Copy the content of a List into this List *\param[in] x the reference List */ inline void assign(const List &x) { m_VoidList.assign(x.m_VoidList); } private: /** The actual container */ List<void*> m_VoidList; }; /** @} */ #endif -- Summary: Code generated for calling pointer-to-member segfaults when address of p-t-m is not 16-bit aligned Product: gcc Version: 4.3.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: james at jamesmolloy dot co dot uk GCC build triplet: i686-elf GCC host triplet: x86_64-linux-gnu GCC target triplet: i686-elf http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39209