char* p = new char[100];
...
delete p;
or
std::auto_ptr<char> p(new char[100]);
I know that it is undefined behavior according to the Standard. What I
would like to know, however, is how strict is this rule in practice.
Several widely used C++ implementations, in particular, do not seem to
have any troubles with the code above if the pointer is to a POD type
(in general, whenever destructors do not have to be called). However,
it seems likely that there do exist implementations where even for POD
types this will not work correctl. Therefore, I ask you to share your
experience on this subject: what code failed to work (if it is
sufficiently different from the pattern described above), whether the
type in question was a POD type or not, and what compiler and library
version were you using?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> I would like to ask everyone who had previously had issues with non-
> array operator delete used to delete the result of array new, i.e.:
>
> char* p = new char[100];
> ...
> delete p;
>
> or
>
> std::auto_ptr<char> p(new char[100]);
>
> I know that it is undefined behavior according to the Standard. What I
> would like to know, however, is how strict is this rule in practice.
> Several widely used C++ implementations, in particular, do not seem to
> have any troubles with the code above if the pointer is to a POD type
> (in general, whenever destructors do not have to be called). However,
> it seems likely that there do exist implementations where even for POD
> types this will not work correctl. Therefore, I ask you to share your
> experience on this subject: what code failed to work (if it is
> sufficiently different from the pattern described above), whether the
> type in question was a POD type or not, and what compiler and library
> version were you using?
Why? What can you possibly hope to gain?
In the case of standard ambiguities, or perhaps borderline cases, it
might be a valid topic for a language group. What makes you think
that exploring the result of 100% absolutely, guaranteed, undefined
behavior is meaningful at all.
I will tell you the result on every implementation where I have ever
(accidentally, I hasten to add) used such code: undefined behavior.
None of them "worked correctly", because there is no correct behavior.
Whether or not such undefined behavior produced "wanted" or "expected"
results depends entirely on your idea of what you "wanted" or
"expected".
>From my point of view, all of them "failed to work" because none of
them doubled the balance in my bank account, one possible result that
the C++ standard allows for undefined behavior.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
I hope to assemble a sufficient number of scary stories to use as a
convincing argument wherever such discussion arises.
> In the case of standard ambiguities, or perhaps borderline cases, it
> might be a valid topic for a language group. What makes you think
> that exploring the result of 100% absolutely, guaranteed, undefined
> behavior is meaningful at all.
Because there is a lot of real-world code is written using constructs
which amount to undefined behavior, and when the issue of rewriting
that code to comply or leave it alone arises, theoretical arguments
alone are not enough. There is a need to convince that not only the
existing behavior is wrong by the book, but it can lead to very
practical troubles. The best way to do so is to demonstrate,
practically, that such code can and does misbehave (for a very wide
definition of "misbehave" - memory leaks, data corruption, crashes
etc... basically anything where the behavior would be not what the
programmer who wrote the code in question intended). I therefore asked
the community of people who are well-versed in the Standard, and
understand the practical implications of breaking the Standard, to
help me find such examples.
> I will tell you the result on every implementation where I have ever
> (accidentally, I hasten to add) used such code: undefined behavior.
"Undefined behavior" only covers the potential future behavior of the
system in some well-defined circumstances. A single specific outcome
is not, by definition, "undefined behaviour". It can be a program
crash, data loss, hardware damage, or the beginning of Apocalypse, but
it is always a specific event that can be described.
> None of them "worked correctly", because there is no correct behavior.
> Whether or not such undefined behavior produced "wanted" or "expected"
> results depends entirely on your idea of what you "wanted" or
> "expected".
I apologize for being imprecise with my words, but I believe I've
managed to convey my point nonetheless. Still, in case it is not
clear, the "correct" - or rather, should I rather say, "expected" (by
a specific programmer, not the Standard, or the people in this
newsgroup) behavior is that "delete" works exactly like "delete[]" for
new-allocated arrays of POD types.
--
> I hope to assemble a sufficient number of scary stories to use as a
> convincing argument wherever such discussion arises.
> Because there is a lot of real-world code is written using constructs
> which amount to undefined behavior, and when the issue of rewriting
> that code to comply or leave it alone arises, theoretical arguments
> alone are not enough. There is a need to convince that not only the
> existing behavior is wrong by the book, but it can lead to very
> practical troubles. The best way to do so is to demonstrate,
> practically, that such code can and does misbehave (for a very wide
> definition of "misbehave" - memory leaks, data corruption, crashes
> etc... basically anything where the behavior would be not what the
> programmer who wrote the code in question intended).
Forget it. People who don't get scared from undefined behaviour won't get
scared from your "real world examples" either. It's like everyone knows
that
smoking is likely to harm one's health, but some people still do it. They
just assume it won't happen to them.
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
In that case, you can use some memory checking tool. For example,
valgrind (http://valgrind.org/). The memcheck tool reports positives
on mis-match of the forms of new/delete used in the code.
Tracing memory leaks as the primary problem should be easy. But I have
heard people defending leaks even. There is nothing you can do about
them, than just throwing them out and if that's not possible, just
don't bother.
Managers don't think that way. If the software seems to be satisfactory to
the customer they will not endorce a programmer to spend $$$ on it unless he
can convince the manager that his end-of-year bonus is at stake.
Antoon
{ quoted signature removed - please do it yourself. -mod }
--
"Antoon" <the-dot-Wizard-at...@news1.news.xs4all.nl> schrieb
im Newsbeitrag news:4704ad9d$0$234$e4fe...@news.xs4all.nl...
Well, but why should a programmer care if managers don't listen to them?
Let
them lose their end-of-year bonus if they think they know so much better.
They will take your advice more seriously when you warn them of undefined
behaviour again next year... ;-)
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
With MS VC++ it depends on whether the type has a destructor. If it has,
the array new expression stores a count of the number of objects in the
array, and the array delete expression uses that count to destroy them.
The non-array new expression does not store the count, so if you use the
wrong delete expression you are very likely to get a crash.
Types without destructors, like char or int, seem to work. For these the
compiler is quite forgiving. Neither version of the new expression stores
the number of objects. You could probably allocate with new or new[] and
delete with free(). (I've not actually tested that.)
I don't know about other compilers.
-- Dave Harris, Nottingham, UK.
> <int...@gmail.com> schrieb im Newsbeitrag
> news:1191402141.7...@o80g2000hse.googlegroups.com...
>> On Oct 3, 10:58 am, Jack Klein <jackkl...@spamcop.net> wrote:
>
>> I hope to assemble a sufficient number of scary stories to use as a
>> convincing argument wherever such discussion arises.
>
>> Because there is a lot of real-world code is written using constructs
>> which amount to undefined behavior, and when the issue of rewriting
>> that code to comply or leave it alone arises, theoretical arguments
>> alone are not enough. There is a need to convince that not only the
>> existing behavior is wrong by the book, but it can lead to very
>> practical troubles. The best way to do so is to demonstrate,
>> practically, that such code can and does misbehave (for a very wide
>> definition of "misbehave" - memory leaks, data corruption, crashes
>> etc... basically anything where the behavior would be not what the
>> programmer who wrote the code in question intended).
>
> Forget it. People who don't get scared from undefined behaviour won't get
> scared from your "real world examples" either. It's like everyone knows
> that
> smoking is likely to harm one's health, but some people still do it. They
> just assume it won't happen to them.
I don't think that is the right analogy. Undefined behaviors are not all
equal (despite the fact that the standard does not impose any requirements
on any of them). Dereferencing a null pointer is undefined behavior and so
is relying on std::string being contiguous. While I will avoid the first at
all costs, I take the liberty of doing the later in my code (in fact,
sometimes I go as far as assuming that it is safe to write \0 behind the
string, which I think will remain undefined even with the next revision of
the standard).
Whether rational people get scared by undefined behavior depends on the
consequences of which they are aware. If you show them that a certain piece
of code not only _can_ do something unexpected but is likely to _do_
something unexpected, they will be more likely to change the code.
Best
Kai-Uwe Bux
--
Now one can ask: for what kinds of T will this work for in my
application? For a POD, it works fine. So you could say that if
union {T x} _dummy;
compiles, the the above code has no worries.
Of course the syntax is a little more verbose, but you get much
clearer code, at least in intent. And you are not relying on
implementation defined behavior.
I cant recall any horror stories regaring asymmetric new[]/delete,
because the vast majority of people
1) use std::vector.
std::vector<T> p(100); //almost identical to new T[100]
(where the "almost" part refers to the extra size member inside
vector.)
2) wrap the C-style array in a struct
struct Twrap{
T buf[100];
T&operator[](unsigned idx){return buf[idx];}
operator T*(){return &buf[0];}
};
std::auto_ptr<Twrap> p(new Twrap); //does the right thing
3) use tr1::array
std::auto_ptr<tr1::array<T,100> > p(new tr1::array<T,100> );
//like std::vector without the extra size member
4) use use one of the boost "array deleters"
5) make their own "auto_array_ptr"
Who knows how all the different compilers (and options) react to
asymmetrical new[]/delete? As you can see, there are many ways to get
rid of the "undefined" and "implementation specific" behavior
cluttering your code.
Lance
*I got this to compile using gcc, but MSVC didnt like it
> Dereferencing a null pointer is undefined behavior and so
> is relying on std::string being contiguous. While I will avoid the first
> at
> all costs, I take the liberty of doing the later in my code (in fact,
> sometimes I go as far as assuming that it is safe to write \0 behind the
> string, which I think will remain undefined even with the next revision of
> the standard).
What do you mean by relying on std::string being contigous? 21.3/2 says
that
"the iterators supported by basic_string are random access iterators", and
as std::string is nothing but a typedef to std::basic_string<char>, the
same
must be true for the former. And as far as I understand things, random
access interators imply that the elements of the sequence are contigous in
memory.
And what's the deal with writing '\0' behind the string? Where is "behind
the string", do you mean the element whose index is basic_string::size()?
According to 21.3.6/1, there already is "a null character specified by
charT()" at that position. And the type of the value returned from
basic_char::c_str() is const charT*, so as a matter of course, you cannot
use it to modify any of the elements of the string.
> Whether rational people get scared by undefined behavior depends on the
> consequences of which they are aware.
So for rational people the term "undefined" is too... well, "undefined" to
be scary? They need a more "defined" concept of "undefined"?
> If you show them that a certain piece
> of code not only _can_ do something unexpected but is likely to _do_
> something unexpected, they will be more likely to change the code.
The mere thought of having to explain to someone what may happen if
anything
can happen makes me a little upset! Isn't it enough to say the the program
may crash, with all the consequences a crash may have?
If the question is only about calling scalar delete on a pointer obtained
from array new, then write an email to your compiler vendor and ask him
what
the behaviour will be. If he says it will be fine, then you can consider it
to be a language extension. Note, for example, that polymorphic array
deletion is also undefined behaviour, but it does seem to work on
Microsoft's compilers:
"Although, strictly speaking, polymorphic array delete is undefined
behavior, we had several customer requests to implement it anyway.
Therefore, in MSC++, this is implemented by yet another synthesized virtual
destructor helper function, the so-called "vector delete destructor," which
(since it is customized for a particular class, such as WW) has no
difficulty iterating through the array elements (in reverse order), calling
the appropriate destructor for each."
(From the MSDN Library article "C++: Under the Hood" by Jan Gray from March
1994, which can be found here:
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnarvc/html/jangrayhood.asp
)
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> <jkher...@gmx.net> schrieb im Newsbeitrag news:fe6b6m$mn0$1...@aioe.org...
>> Matthias Hofmann wrote:
>
>> Dereferencing a null pointer is undefined behavior and so
>> is relying on std::string being contiguous. While I will avoid the first
>> at
>> all costs, I take the liberty of doing the later in my code (in fact,
>> sometimes I go as far as assuming that it is safe to write \0 behind the
>> string, which I think will remain undefined even with the next revision
>> of the standard).
>
> What do you mean by relying on std::string being contigous? 21.3/2 says
> that
> "the iterators supported by basic_string are random access iterators", and
> as std::string is nothing but a typedef to std::basic_string<char>, the
> same
> must be true for the former. And as far as I understand things, random
> access interators imply that the elements of the sequence are contigous in
> memory.
No, it does not. All it guarantees is that expressions of the form
*( cont.begin() + n ) or cont[n]
give you a reference to the n-th element. It does not imply that this
element resides at a certain position in memory, i.e., you usually have
not:
&cont[n] == &cont[0] + n
See std::deque for an example of a container with random access iterators
for which it is not guaranteed that
&cont[0] + i == &cont[i]
Similarly, as of now, std::string does not make that guarantee, either. Only
std::vector makes the guarantee of contiguity. I think, in the next
revision of the standard, std::string will be declared contiguous.
> And what's the deal with writing '\0' behind the string? Where is "behind
> the string", do you mean the element whose index is basic_string::size()?
Yes.
> According to 21.3.6/1, there already is "a null character specified by
> charT()" at that position.
std::string::c_str() returns a pointer to _an_ array of length size()+1 that
happens to contain a 0-terminated copy of the string. There is no
guarantee, that
str.c_str() == &str[0]
The implementation is free to actually make a copy of the string and append
the terminating 0-character to the copy while holding the string data in a
buffer where there is no terminating 0-character.
> And the type of the value returned from
> basic_char::c_str() is const charT*, so as a matter of course, you cannot
> use it to modify any of the elements of the string.
Right. My point was that
str[ str.size() ] = char();
is undefined behavior and so is
*( &str[0] + str.size() ) = char();
>> Whether rational people get scared by undefined behavior depends on the
>> consequences of which they are aware.
>
> So for rational people the term "undefined" is too... well, "undefined" to
> be scary? They need a more "defined" concept of "undefined"?
Not quite. Rational people feel free to program outside the guarantees of
the standard every once in a while when they see a definite need (e.g., in
performance critical regions as demonstrated by profiling) _and_ only if
they have assurances that their code will meet their expectations. That
usually entails (at least):
a) Clearly documenting the expected behavior and documenting that the
standard does not make the guarantees needed.
b) Documenting the need to go outside the standard in a way that makes it
feasible to revisit this decision periodically and re-asses the rationale.
E.g., changes in the standard may render a conforming implementation
competitive.
c) Writing thorough tests to verify that, On The Implementation Used, the
anti-idiom in question produces the expected behavior. Of course, those
tests go into the suite of automated tests.
d) If possible, verifying that the implementation makes additional
guarantees (e.g., by reading the STL headers or by contacting the vendor).
For instance, you can check with reasonable certainty that std::vector is
contiguous in a given implementation by using a custom made allocator that
allows you to peek into the allocated buffer or by using memory tracing
tools. You can also write test code to check whether std::list<T> works
with incomplete types (that's an iffy one!). And, with an STL
implementation that comes with the source, you can read the STL code to get
a non-empirical verification for those guarantees, too.
Using a proper regimen for managing code that has undefined behavior is not
easy, but it is not impossible either. Of course, there are forms of
undefined behavior that should always be avoided since the costs of dealing
with it properly (if at all feasible) far exceed the costs of eliminating
the offending code. Dereferencing an invalid pointer is one of those and
changing a variable twice between sequence points is too, in my opinion.
>> If you show them that a certain piece
>> of code not only _can_ do something unexpected but is likely to _do_
>> something unexpected, they will be more likely to change the code.
>
> The mere thought of having to explain to someone what may happen if
> anything
> can happen makes me a little upset! Isn't it enough to say the the program
> may crash, with all the consequences a crash may have?
Actually, a crash is often of _little_ concern. When the program crashes,
all your co-workers _will_ notice that there is a bug that needs to be
fixed. Moreover, your customers will have the advantage(!) of the program
crashing to getting incorrect results.
Much more of a concern is undefined behavior (or implementation defined
behavior for that matter) that just affects the results of a computations.
For instance those stupid things like
std::cout << a++ << a++ << a++ << '\n';
or more generally
f( a++, a++ );
where people may rely on a certain order of evaluation. Even a line
sum = a + b;
is dangerous if you do not carefully check for arithmetic overflows. In
those cases, a program may just produce incorrect results and buy stocks
for $100,000,000 for no reason. _That_ is a problem; and your customers
would most certainly have preferred the program to crash instead.
[snipped: interesting microsoft specific advice for the OP]
Best
Kai-Uwe Bux
--
> And as far as I understand things, random
> access interators imply that the elements of the sequence are contigous in
> memory.
>
They don't. The requirements for random access iterators are that
various operations on those iterators must execute in constant time,
regardless of the length of the sequence. A deque provides random
access iterators, but its storage is segmented. Incrementing an
iterator requires checking whether the iterator is at the end of a
segment, and if it is, moving to the next segment. That's a constant
time operation, but the memory need not be congiguous.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
std::deque is a counterexample, with noncontiguous storage
but having random access iterators.
C++0x will likely guarantee that std::string is contiguous.
-- James
--
No, it does not. std::deque iterators are random-access, for example,
but the deque itself is not guaranteed to be, and is typically not,
continuous.
> And what's the deal with writing '\0' behind the string? Where is "behind
> the string", do you mean the element whose index is basic_string::size()?
> According to 21.3.6/1, there already is "a null character specified by
> charT()" at that position. And the type of the value returned from
> basic_char::c_str() is const charT*, so as a matter of course, you cannot
> use it to modify any of the elements of the string.
c_str() is not guaranteed to return a pointer to internal string
buffer, either. So, s.c_str()[s.size()] is legal and equals '\0', but
this does not mean that s[s.size()] is legal - it is UB.
> So for rational people the term "undefined" is too... well, "undefined" to
> be scary? They need a more "defined" concept of "undefined"?
Sometimes there's no efficient way to do something but resort to code
that would be UB by the letter of the Standard (but can be well-
defined in a specific implementation).
> The mere thought of having to explain to someone what may happen if
> anything
> can happen makes me a little upset! Isn't it enough to say the the program
> may crash, with all the consequences a crash may have?
No, because it may be the case that for all existing implementations
it will not crash, and furthermore, it will do exactly what the person
who wrote it intended. Continuous std::string is a good example,
actually. Consider:
std::string s;
std::size_t n = SomeAPI_GetNameLength();
s.resize(n);
SomeAPI_GetName(&s[0]);
Technically, this is UB (because string data is not guaranteed to be
continuous). Practically, I am not aware of any implementation where
this would not do what you'd expect it to do. To make it standard-
compliant, I'd have to do:
std::vector<char> v;
std::size_t n = SomeAPI_GetNameLength();
v.resize(n);
SomeAPI_GetName(&v[0]);
std::string s(v.begin(), v.end());
But this is an extra copy, and it can be pretty expensive for long
strings. Personally, I would go for UB-in-theory which works
everywhere in practice in this case (and is recognized as "established
practice" by all vendors, as well).
> If the question is only about calling scalar delete on a pointer obtained
> from array new, then write an email to your compiler vendor and ask him
> what the behaviour will be. If he says it will be fine, then you can consider it
> to be a language extension.
This is a good idea, thank you. We're using both Visual C++ and g++
here, so I'll find out about both, and post the results of my
inquiries.
--
Only with the non-const version of string::operator[];
the const version returns char().
string s = /* ... */;
const string& cs = s;
cs[s.size()]; // okay; evaluates to char()
s[s.size()]; // undefined behaviour
I guess the requirement that the const version should return char()
practically makes many (if not all) implementations keep the null
terminating character at the end of the internal buffer.
--
Seungbeom Kim
I have a similar view on this issue and therefore I
humbly asked in the comp.std.c++ thread
"Do multiple calls to std::string::data() return the same pointer?"
the question
"Although that seems like muckraking(?) in a beehive: Does
there exists any serious (in the sense: Not my personal,
hand-made, etc.) std::basic_string implementation, which
does *not* use a null-termined representation? (Obviously
I'm starting to hi-jack even the freedom of potentially
computed c_str() returns ;-))"
Would be interesting to hear the more recent views on
this issue, since std::basic_string will now be re-
quired to use a continous representation. I would like
to mention that I don't want try to exclude ref-counted
implementations. E.g. Delphi's (huge) string type is in
fact ref-counted, length-aware, and zero-terminated.
Greetings from Bremen,
Daniel Krügler
--
> You can also write test code to check whether std::list<T> works
> with incomplete types (that's an iffy one!).
What's the deal with std::list<T> and incomplete types?
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
>
> <jkher...@gmx.net> schrieb im Newsbeitrag news:fe8u6d$dtf$1...@aioe.org...
>
>> You can also write test code to check whether std::list<T> works
>> with incomplete types (that's an iffy one!).
>
> What's the deal with std::list<T> and incomplete types?
Nothing much: it's not guaranteed to compile, and if it compiles, it is
undefined behavior. That is because of clause [17.4.3.6/2 (last item)].
Consider:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <list>
class recursive_list {
std::list< recursive_list > the_list;
public:
friend
std::ostream & operator<< ( std::ostream & o_str,
recursive_list const & rl ) {
if ( rl.the_list.empty() ) {
o_str << "[]";
} else {
o_str << "[ ";
std::copy ( rl.the_list.begin(),
rl.the_list.end(),
std::ostream_iterator<recursive_list>
( std::cout, " " ) );
o_str << "]";
}
return ( o_str );
}
void push_back ( recursive_list const & rl ) {
the_list.push_back( rl );
}
};
int main ( void ) {
recursive_list const empty_list;
recursive_list r1;
r1.push_back( empty_list );
r1.push_back( empty_list );
r1.push_back( empty_list );
r1.push_back( r1 );
r1.push_back( empty_list );
r1.push_back( empty_list );
r1.push_back( empty_list );
std::cout << r1 << '\n';
}
// Intended output: [ [] [] [] [ [] [] [] ] [] [] [] ]
Some compilers accept this, some don't. Essentially, it depends on whether
your STL implementation uses concept checks (e.g., with g++, this depends
on how you built the compiler).
Note: unlike the other sequence containers, std::list can be implemented
without detours and overhead to allow for incomplete types (and often, it
is implemented that way).
Best
Kai-Uwe Bux
--
> ...Therefore, I ask you to share your
> experience on this subject: what code failed to work... whether the
> type in question was a POD type or not, and what compiler and library
> version were you using?
GCC 3.4.2: Fine, AFAICT, for POD type. For non-POD: glibc actually
detects the error, gives you debug info, and apparently calls abort.
Only the first object is destructed.
# #include <cstdio>
#
# struct S {
# S() { std::puts("S();"); }
# ~S() { std::puts("~S();"); }
# };
#
# int main() {
# delete new S[2]; /* Similar behavior for S[1]. */
# return 0;
# }
$ ./main
S();
S();
~S();
*** glibc detected *** ./main: munmap_chunk(): invalid pointer:
0x0000000000501018 ***
======= Backtrace: =========
/lib64/libc.so.6[0x2abeaf83639e]
./main(__gxx_personality_v0+0x1c6)[0x400816]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x2abeaf7e8154]
./main(__gxx_personality_v0+0x49)[0x400699]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:05
3529371 /export/home/jeff/files/code/cc/
nonarray_delete/main
00500000-00501000 rw-p 00000000 08:05
3529371 /export/home/jeff/files/code/cc/
nonarray_delete/main
00501000-00522000 rw-p 00501000 00:00
0 [heap]
2abeaf24a000-2abeaf265000 r-xp 00000000 08:05
30525 /lib64/ld-2.4.so
2abeaf265000-2abeaf267000 rw-p 2abeaf265000 00:00 0
2abeaf294000-2abeaf295000 rw-p 2abeaf294000 00:00 0
2abeaf365000-2abeaf367000 rw-p 0001b000 08:05
30525 /lib64/ld-2.4.so
2abeaf367000-2abeaf44e000 r-xp 00000000 08:05
47891 /usr/lib64/libstdc++.so.6.0.8
2abeaf44e000-2abeaf54d000 ---p 000e7000 08:05
47891 /usr/lib64/libstdc++.so.6.0.8
2abeaf54d000-2abeaf553000 r--p 000e6000 08:05
47891 /usr/lib64/libstdc++.so.6.0.8
2abeaf553000-2abeaf556000 rw-p 000ec000 08:05
47891 /usr/lib64/libstdc++.so.6.0.8
2abeaf556000-2abeaf568000 rw-p 2abeaf556000 00:00 0
2abeaf568000-2abeaf5bc000 r-xp 00000000 08:05
30540 /lib64/libm-2.4.so
2abeaf5bc000-2abeaf6bb000 ---p 00054000 08:05
30540 /lib64/libm-2.4.so
2abeaf6bb000-2abeaf6bd000 rw-p 00053000 08:05
30540 /lib64/libm-2.4.so
2abeaf6bd000-2abeaf6ca000 r-xp 00000000 08:05
46549 /lib64/libgcc_s.so.1
2abeaf6ca000-2abeaf7c9000 ---p 0000d000 08:05
46549 /lib64/libgcc_s.so.1
2abeaf7c9000-2abeaf7ca000 rw-p 0000c000 08:05
46549 /lib64/libgcc_s.so.1
2abeaf7ca000-2abeaf7cb000 rw-p 2abeaf7ca000 00:00 0
2abeaf7cb000-2abeaf8f1000 r-xp 00000000 08:05
30532 /lib64/libc-2.4.so
2abeaf8f1000-2abeaf9f1000 ---p 00126000 08:05
30532 /lib64/libc-2.4.so
2abeaf9f1000-2abeaf9f4000 r--p 00126000 08:05
30532 /lib64/libc-2.4.so
2abeaf9f4000-2abeaf9f6000 rw-p 00129000 08:05
30532 /lib64/libc-2.4.so
2abeaf9f6000-2abeaf9fc000 rw-p 2abeaf9f6000 00:00 0
7ffffb84a000-7ffffb860000 rw-p 7ffffb84a000 00:00
0 [stack]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00
0 [vdso]
Aborted