By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,320 Members | 2,224 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,320 IT Pros & Developers. It's quick & easy.

Returning local variables from DLL

P: n/a
Hi together,

I am a bit clueless about the following problem:

In the following code excerpt

std::string getStr()
{

std::string bla="asdfsa";
return bla;
}

void func1()
{

{
std::string str1=getStr();
}
return;
}

str1 is destroyed when the scope inside func1() is left.
Works fine.
But, if getStr() is inside a DLL and is called from func1() in a main
program, this does not work.
At least, I experience that in my code.
Actually, the getStr() is a member function of a class in the DLL which
is exported.
Are they not sharing the same memspace?
Am I missing something?

See callstack below

NTDLL! 7c911230()
NTDLL! 7c97cd80()
NTDLL! 7c970af8()
KERNEL32! 7c85e9cf()
_CrtIsValidHeapPointer(const void * 0x009d33d8) line 1697
_free_dbg_lk(void * 0x009d33d8, int 0x00000001) line 1044 + 9 bytes
_free_dbg(void * 0x009d33d8, int 0x00000001) line 1001 + 13 bytes
free(void * 0x009d33d8) line 956 + 11 bytes
operator delete(void * 0x009d33d8) line 7 + 10 bytes
std::allocator<char>::deallocate(void * 0x009d33d8, unsigned int
0x00000021) line 64 + 16 bytes
std::basic_string<char,std::char_traits<char>,std: :allocator<char>
>::_Tidy(unsigned char 0x01) line 592
std::basic_string<char,std::char_traits<char>,std: :allocator<char>
>::~basic_string<char,std::char_traits<char>,std:: allocator<char() line 59 + 17 bytes

Thanks in advance,

--
Regards,

Rainer

Dec 14 '06 #1
Share this Question
Share on Google+
6 Replies


P: n/a
* RT*****@web.de:
<off-topic>
See the FAQ for information about relevant newsgroups.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Dec 14 '06 #2

P: n/a
<RT*****@web.dewrote in message
news:11**********************@l12g2000cwl.googlegr oups.com...
Hi together,

I am a bit clueless about the following problem:

In the following code excerpt

std::string getStr()
{

std::string bla="asdfsa";
return bla;
}

void func1()
{

{
std::string str1=getStr();
}
return;
}

str1 is destroyed when the scope inside func1() is left.
Works fine.
But, if getStr() is inside a DLL and is called from func1() in a main
program, this does not work.
At least, I experience that in my code.
Actually, the getStr() is a member function of a class in the DLL which
is exported.
Are they not sharing the same memspace?
Am I missing something?

See callstack below

NTDLL! 7c911230()
NTDLL! 7c97cd80()
NTDLL! 7c970af8()
KERNEL32! 7c85e9cf()
_CrtIsValidHeapPointer(const void * 0x009d33d8) line 1697
_free_dbg_lk(void * 0x009d33d8, int 0x00000001) line 1044 + 9 bytes
_free_dbg(void * 0x009d33d8, int 0x00000001) line 1001 + 13 bytes
free(void * 0x009d33d8) line 956 + 11 bytes
operator delete(void * 0x009d33d8) line 7 + 10 bytes
std::allocator<char>::deallocate(void * 0x009d33d8, unsigned int
0x00000021) line 64 + 16 bytes
std::basic_string<char,std::char_traits<char>,std: :allocator<char>
>>::_Tidy(unsigned char 0x01) line 592
std::basic_string<char,std::char_traits<char>,std: :allocator<char>
>>::~basic_string<char,std::char_traits<char>,std: :allocator<char() line
59 + 17 bytes


Thanks in advance,
DLLs have nothing to do with C++, that's part of the OS and specific
compiler. Try a microsoft newsgroup such as
comp.os.ms-windows-programmer.win32
or others.
Dec 14 '06 #3

P: n/a
On Dec 14, 11:56 am, "RTha...@web.de" <RTha...@web.dewrote:
Hi together,

I am a bit clueless about the following problem:

In the following code excerpt

std::string getStr()
{

std::string bla="asdfsa";
return bla;

}void func1()
{

{
std::string str1=getStr();
}
return;

}str1 is destroyed when the scope inside func1() is left.
Works fine.
But, if getStr() is inside a DLL and is called from func1() in a main
program, this does not work.
At least, I experience that in my code.
Actually, the getStr() is a member function of a class in the DLL which
is exported.
Are they not sharing the same memspace?
Am I missing something?
Contrary to the previous replies to your post, there is something in
this for the comp.lang.c++ community. We encountered a problem
previously which looks very similar to the above problem, and as it
turned out it had a substantial influence on our software design.

In our case, we got a similar message when we unknowingly built our
application (multiple shared libraries/DLL's and some main stubs which
used them) in such a way that each DLL had its own memory heap. We
thought we were using default compiler flags, but as it turned out, we
were not for a DLL arrangement. Under Windows using VC++ (I forget the
version), we got the above behavior, but under linux we had no problems
at all. We temporarily resolved the problem by using appropriate
compiler flags until we found a more robust design solution.

Where this is relevant to the comp.lang.c++ community is that the C++
standard says nothing at all about shared libraries. It talks about
"translation units", but that's a different (but related) thing and
doesn't address situations like the above. Indeed, since it does not
prohibit separate memory heaps in DLL's, there's a fair argument which
says it is okay for the compiler implementor to do that. Unfortunately,
this is often not what the programmer expects and can lead to problems
like the one you posted.

There are a few good items in "C++ Coding Standards" by Herb Sutter and
Andrei Alexandrescu which talk about these things (see the "Namespaces
and Modules" section). Item 63 "Use sufficiently portable types in a
module's interface" is particularly relevant, where they discuss
std::string as a function parameter in the module's interface. That
example talks about compiler flags, but the hidden part of std::string
which makes it particularly nasty is that it involves dynamic memory
allocation under the covers. When you force the internal data buffer to
be resized (eg you add characters to the string), memory is allocated
in the module in which that usage of std::string occurred. If you then
pass that string to a different module and it tries to modify it, then
the other module will first try to deallocate the internal buffer and
BAM! there goes your program if your modules are using their own
private memory heaps. If you are returning a std::string by value, then
you essentially have the same problem merely as a result of the
function call mechanics. Which module allocates and deallocates the
memory on each side of the final assignment when the function returns?
Note that all the containers in the STL are vulnerable to this same
gotcha.

If you have to keep the memory heaps separate for some reason (unlikely
from what I can tell from your original post), then there is possibly
still a workaround. You could wrap std::string and make the memory
(re)allocation happen inside your wrapped implementation. Using the
pImpl idiom will suffice to hide this from your compiler so that it
doesn't inline the memory (re)allocation. There is, of course, a
performance penalty for doing this though, so consider carefully if
this matters to you. You should note that this still relies on you
using the same compiler settings and compiler version for all modules
that are going to use your wrapper if you want to have maximum chance
of avoiding inter-module problems (see the book - it contains good
advice on this area).

Hope that helps.

--
Computational Fluid Dynamics, CSIRO (CMIS)
Melbourne, Australia

Dec 14 '06 #4

P: n/a

"RT*****@web.de д
"
Hi together,

I am a bit clueless about the following problem:

In the following code excerpt

std::string getStr()
{

std::string bla="asdfsa";
return bla;
}

void func1()
{

{
std::string str1=getStr();
}
return;
}
The code is fine.You can prove it by put getStr into yourself's CPP.

Dec 14 '06 #5

P: n/a
On Dec 14, 11:56 am, "RTha...@web.de" <RTha...@web.dewrote:
Hi together,

I am a bit clueless about the following problem:

In the following code excerpt

std::string getStr()
{

std::string bla="asdfsa";
return bla;

}void func1()
{

{
std::string str1=getStr();
}
return;

}str1 is destroyed when the scope inside func1() is left.
Works fine.
But, if getStr() is inside a DLL and is called from func1() in a main
program, this does not work.
At least, I experience that in my code.
Actually, the getStr() is a member function of a class in the DLL which
is exported.
Are they not sharing the same memspace?
Am I missing something?

Contrary to the previous replies to your post, there is something in
this for the comp.lang.c++ community. We encountered a problem
previously which looks very similar to the above problem, and as it
turned out it had a substantial influence on our software design.

In our case, we got a similar message when we unknowingly built our
application (multiple shared libraries/DLL's and some main stubs which
used them) in such a way that each DLL had its own memory heap. We
thought we were using default compiler flags, but as it turned out, we
were not for a DLL arrangement. Under Windows using VC++ (I forget the
version), we got the above behavior, but under linux we had no problems
at all. We temporarily resolved the problem by using appropriate
compiler flags until we found a more robust design solution.

Where this is relevant to the comp.lang.c++ community is that the C++
standard says nothing at all about shared libraries. It talks about
"translation units", but that's a different (but related) thing and
doesn't address situations like the above. Indeed, since it does not
prohibit separate memory heaps in DLL's, there's a fair argument which
says it is okay for the compiler implementor to do that. Unfortunately,
this is often not what the programmer expects and can lead to problems
like the one you posted.

There are a few good items in "C++ Coding Standards" by Herb Sutter and
Andrei Alexandrescu which talk about these things (see the "Namespaces
and Modules" section). Item 63 "Use sufficiently portable types in a
module's interface" is particularly relevant, where they discuss
std::string as a function parameter in the module's interface. That
example talks about compiler flags, but the hidden part of std::string
which makes it particularly nasty is that it involves dynamic memory
allocation under the covers. When you force the internal data buffer to
be resized (eg you add characters to the string), memory is allocated
in the module in which that usage of std::string occurred. If you then
pass that string to a different module and it tries to modify it, then
the other module will first try to deallocate the internal buffer and
BAM! there goes your program if your modules are using their own
private memory heaps. If you are returning a std::string by value, then
you essentially have the same problem merely as a result of the
function call mechanics. Which module allocates and deallocates the
memory on each side of the final assignment when the function returns?
Note that all the containers in the STL are vulnerable to this same
gotcha.

If you have to keep the memory heaps separate for some reason (unlikely
from what I can tell from your original post), then there is possibly
still a workaround. You could wrap std::string and make the memory
(re)allocation happen inside your wrapped implementation. Using the
pImpl idiom will suffice to hide this from your compiler so that it
doesn't inline the memory (re)allocation. There is, of course, a
performance penalty for doing this though, so consider carefully if
this matters to you. You should note that this still relies on you
using the same compiler settings and compiler version for all modules
that are going to use your wrapper if you want to have maximum chance
of avoiding inter-module problems (see the book - it contains good
advice on this area).

Hi Craig,

thanks for your kind response. I thought that this had something to do
with C++. Thanks for having a deeper look inside this than the other
replyers.

I hereby forward this thread to comp.os.ms-windows-programmer.win32 to
see if those guys find it appropriate and to know what they think about
it.
I hope I am not making a fault in doing this, but if I do, I'm sure
there's somebody who will teach me good behaviour.

As far as I understand you, even allocating the string in the main
module and passing the pointer to the DLL does not help since a
reallocation (grow, shrink) would cause a crash, right?
Is the underlying memory allocation the same as allocation by new?
new uses the global heap, but as I understand even the global heap is
separated into different memspaces for each module.
Or, to be more concrete, if I allocate an object of a user defined type
with new in the DLL and pass the pointer back to the main module which,
then, deletes the object, would this cause the same behaviour?

--
Regards,

Rainer

Dec 14 '06 #6

P: n/a
As far as I understand you, even allocating the string in the main
module and passing the pointer to the DLL does not help since a
reallocation (grow, shrink) would cause a crash, right?
It *might*, depending on what memory heap management the compiler is
using. You need to check your compiler flags for that.
Is the underlying memory allocation the same as allocation by new?
If that is what the author of your particular STL implementation uses.
The std::string class uses the default allocator<char>, which may or
may not be using the global new operator (I'm not sure if the standard
says anything specific about this particular point). In short, maybe,
so don't depend on it.
new uses the global heap, but as I understand even the global heap is
separated into different memspaces for each module.
Maybe, see earlier comment at the top of this reply.
Or, to be more concrete, if I allocate an object of a user defined type
with new in the DLL and pass the pointer back to the main module which,
then, deletes the object, would this cause the same behaviour?
Yes, this can lead to the same behavior as your first posting. It can
even happen if you are allocating/deallocating built in types, since it
is the actual operator new/delete that is the issue, not the underlying
data type. A data type might implement its own operator new/delete, but
that is a red herring to this issue.

--
Computational Fluid Dynamics, CSIRO (CMIS)
Melbourne, Australia

Dec 15 '06 #7

This discussion thread is closed

Replies have been disabled for this discussion.