I am having a dynamic cast fail on a g++ compiler (Redhat 5.5 gcc version 3.4.6) that works fine on a Windows Visual studio 2003, 2005, and 2010 compiler. To understand what I am seeing I will try to quickly break the problem down. We have a process that loads in numerous "plugins" from a directory and dynamically loads these plugins (which are dynamically linked libraries). The process is supposed to compare different rules and data types to return an answer. To make the process modulure we made the process understand about a "BaseDataType" but not about the actual specific types (so we could keep the process generic). The flow of the program goes something like this:
All our "SpecifcObject" types inherit from "BaseDataType" like this
class SpecificObject : public virtual BaseDataType {
... Class Items ...
}
This is the code from the process looks like:
// Receive raw data
void receive_data(void *buff, int size,DataTypeEnum type)
{
// Get the plugin associated with this data
ProcessPlugin *plugin = m_plugins[type];
// Since we need to cast the data properly into its actual type and not its
// base data type we need the plugin to cast it for us (so we can keep the
// process generic)
BaseDataType *data = plugin->getDataObject(buff);
if(data)
{
// Cast worked just fine
.... Other things happen (but object isn't modified) ....
// Now compare our rule
RuleObject obj = getRule();
ResultObject *result = plugin->CompareData(obj,data);
if(result)
... Success Case ...
else
... Error Case ...
}
}
Now this is (generically) what a plugin would look like
BaseDataType* ProcessPluginOne::getDataObject(unsigned char *buff)
{
// SpecificObject inherits from BaseDataType using a "virtual" inheritance
SpecificObject *obj = reinterpret_cast<SpecificObject*>(buff);
if(obj)
return (BaseDataType*)obj;
else
return NULL;
}
ResultObject* ProcessPluginOne::CompareData(RuleObject rule, BaseDataType *data)
{
ResultObject *obj = NULL;
// This method checks out fine
if(data->GetSomeBaseMethod())
{
// This cast below FAILS every time in gcc but passes in Visual Studio
SpecificObject *obj = dynamic_cast<SpecificObject*>(data);
if(obj)
{
... Do Something ...
}
}
return result;
}
Again all of this works under Visual Studio but not under GCC. To debug the program I started adding some code to different sections. I finally got it to work once I did the following in the main process (see added code below):
// In process with Modification
void receive_data(void *buff, int size,DataTypeEnum type)
{
// Get the plugin associated with this data
ProcessPlugin *plugin = m_plugins[type];
// Since we need to cast the data properly into its actual type and not its
// base data type we need the plugin to cast it for us (so we can keep the
// process generic)
BaseDataType *data = plugin->getDataObject(buff);
if(data)
{
// Cast worked just fine
.... Other things happen (but object isn't modified) ....
// Now compare our rule
RuleObject obj = getRule();
/** I included the specific data types in as headers for debugging and linked in
* all the specific classes and added the following code
*/
SpecificObject *test_obj = dynamic_cast<SpecificObject*>(data);
if(test_obj)
cout << "Our was Data was casted correctly!" << endl;
/// THE CODE ABOVE FIXES THE BAD CAST IN MY PLUGIN EVEN THOUGH
/// THE CODE ABOVE IS ALL I DO
ResultObject *result = plugin->CompareData(obj,data);
if(result)
... Success Case ...
else
... Error Case ...
}
}
Significant Process Compile Options:
Compile: -m64 -fPIC -wno-non-template-friend -DNDEGBUG -I <Includes>
Link: -Wl -z muldefs -m64
Significant Plugin Compile Options
Compile: -Wall -wno-non-template-friend -O -O2
Link: -Wl -Bstatic -Bdynamic -z muldefs -shared -m64
Since I am not modifying the object "data" I have no idea why the rest of the program would suddenly start working. The only thing I can think of is that the virtual table is getting stripped off somewhere in the process and the "extra" dynamic cast forces the main process to keep the table (which still doesn't make a lot of sense).
I have tried taking out all optimization settings in gcc and its still the same. Any thoughts as to what is going on here?
Thanks.
The two most likely scenarios are that BaseDataType is not a polymorphic type, or that the compiler doesn't see the relationship between BaseDataType and SpecificObject at some point in the code (for example, in getDataObject the compiler might generate different code depending on knowledge of the parent-child relationship, since you use C-cast from child to parent. This is super easy to check: Change the C-cast to static_cast. If it fails to compile you're missing a critical include.
Related
Google wrote in Android ndk guides site:
Memory allocated in one library, and freed in the other, causing memory leakage or heap corruption.
Why?
It's always correct?
EDIT
As #Galik wrote the context of this quote is:
In C++, it is not safe to define more than one copy of the same function or object in a single program. This is one aspect of the One Definition Rule present in the C++ standard.
When using a static runtime (and static libraries in general), it is easy to accidentally break this rule. For example, the following application breaks this rule:
...
In this situation, the STL, including and global data and static constructors, will be present in both libraries. The runtime behavior of this application is undefined, and in practice crashes are very common. Other possible issues include:
Memory allocated in one library, and freed in the other, causing memory leakage or heap corruption.
Exceptions raised in libfoo.so going uncaught in libbar.so, causing your app to crash.
Buffering of std::cout not working properly.
One possible reason why it's considered a mistake is because usually allocation comes with a certain initialization, and deallocation with some destruction logic.
Theory:
The main danger is mismatching initialization / destruction logic.
Lets look at two different STL versions as two different and separate libraries.
Consider this: Each library lets you allocate / deallocate something. Upon resource acquisition, each library does some house-keeping on that thing in its own way, which is encapsulated (read: you don't know about it, and don't need to).
What happens if the housekeeping each does is significantly different?
Example:
class Foo
{
private:
int x;
public:
Foo() : x(42) {}
};
namespace ModuleA
{
Foo* createAFoo()
{
return new Foo();
}
void deleteAFoo(Foo* foo)
{
if(foo != nullptr)
delete foo;
}
}
namespace ModuleB
{
std::vector<Foo*> all_foos;
Foo* createAFoo()
{
Foo* foo = new Foo();
all_foos.push_back(foo);
return foo;
}
void deleteAFoo(Foo* foo)
{
if(foo != nullptr)
{
std::vector<int>::iterator position = std::find(all_foos.begin(), all_foos.end(), foo);
if (position != myVector.end())
{
myVector.erase(position);
}
delete foo;
}
}
}
Question: What happens if we do the following?
Foo* foo = ModuleB::createAFoo();
ModuleA::deleteAFoo(foo);
Answer: ModuleB now has a dangling pointer.
This can cause all sorts scary and hard to debug of issues down the line.
We're also not making all_foos smaller, which may be considered a memory leak (the size of a pointer each time).
Question: What happens if we do the following?
Foo* foo = ModuleA::createAFoo();
ModuleB::deleteAFoo(foo);
Answer: Looks like... nothing bad happens!
But what if I removed the if (position != myVector.end()) check? Then we'd have a problem.
And an STL might do that in the name of optimization, so...
I wrote that section of the doc. I've had to debug an issue where one of the standard stream objects (cout or similar) was doubly linked into to libraries resulting in two distinct instances of the object. The constructor for the object was run twice, but twice on the same instance of the object. One object was double initialized, the other was uninitialized. When the unconstructed object was used, it would attempt to access some uninitialized memory and crash.
There's really no limit to the strangeness of undefined behavior. It's entirely possible that the bug I'm remembering was unique to the version of the compiler, linker, or loader that we were using at the time.
EDIT: Here's a repro case:
// foo.cpp
#include <stdio.h>
class Foo {
public:
Foo() { printf("this: %p\n", this); }
};
Foo foo;
// main.cpp
int main() {
}
Build with:
$ clang++ --version
clang version 7.0.0 (trunk 330210)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/bin
$ clang++ foo.cpp -shared -o libfoo.so
$ clang++ foo.cpp -shared -o libbar.so
$ clang++ main.cpp -L. -lfoo -lbar -rpath '$ORIGIN'
Both libfoo and libbar will be loaded, and each have their own copy of the object. The constructor will be run twice, but as you can see only one instance of the object has its constructor run; it just runs twice.
$ ./a.out
this: 0x7f9475d48031
this: 0x7f9475d48031
In Setting a variable in a child class, I was trying to figure out how to correctly derive variables in polymorphic classes. After some help, I found out that I needed to use a dynamic_cast on a pointer to correctly access the information I need. I am having some trouble with this.
This is the function I am currently working on.
void translateLines(Parser parser, Code code)
{
while(parser.hasMoreCommands())
{
vector<Command>::const_iterator it = parser.currentCommand();
if(it->commandType() == "A")
{
//SubType* item = dynamic_cast<SubType*>(*the_iterator);
A_COMMAND* a_command = dynamic_cast<A_COMMAND*>(*it); //line that is throwing the error
//string symbol = a_command->get_symbol();
//cout << "symbol: " << symbol << endl;
//perform binary conversion
}
/*else if(command.commandType() == "C")
{
string dest = command.get_dest();
}*/
//shouldn't be any L commands in symbol-less version
else
{
std::cout << "unexpected command value \n";
}
parser.advance();
}
}
This is my Parser.h, which has the relevant information regarding the iterator for the vector.
#include "Command.h"
#include <vector>
class Parser {
private:
std::vector<Command> commands;
std::vector<Command>::const_iterator command_it = commands.begin();
public:
Parser(std::vector<std::string>);
bool hasMoreCommands() //are there more commands in the input?
{
if(command_it != commands.end())
return true;
else
return false;
}
void advance(){std::next(command_it);} //move to next command, should only work if hasMoreCommands returns false}
std::vector<Command>::const_iterator currentCommand(){return command_it;}
std::vector<std::string> translateCommands(); //convert commands into binary strings
};
Here is the error I am receiving:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -o Assembler.o "..\\Assembler.cpp"
..\Assembler.cpp: In function 'void translateLines(Parser, Code)':
..\Assembler.cpp:32:55: error: cannot dynamic_cast 'it.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator*<Command*, std::vector<Command> >()' (of type 'class Command') to type 'class A_COMMAND*' (source is not a pointer)
A_COMMAND* a_command = dynamic_cast<A_COMMAND*>(*it);
^
Any clue what's wrong here?
EDIT: So I see now that I can't use a vector of Commands, rather I need pointers to the commands. I already have changed Parser.h to handle vector<Command*> rather than vector<Command>. For the input I tried something like this:
A_COMMAND command();
commands.push_back(&command);
But this isn't quite working for me, as the vector is expecting pointers and not references. What would be the easiest way to create a pointer to the memory and push it into the vector?
You have a vector of Commands. You cannot cast a Command to an A_COMMAND*. It's important to note that a vector<Command> cannot possibly contain a A_COMMAND. If you want to do runtime polymorphism in C++, you have to use pointers or references. In this case your Parser::commands would need to be a std::vector<Command*> (or some type of smart pointer like std::vector<std::shared_ptr<Command>>).
Take for example this code:
std::vector<Command> commands;
A_COMMAND a_command;
commands.push_back(a_command);
commands does not contain an A_COMMAND object. It contains a Command object that is a copy of a_command. It more-or-less equivilant of this:
std::vector<Command> commands;
A_COMMAND a_command;
Command temp(a_command);
commands.push_back(temp);
Remember, in C++ a variable is an object, not a reference to an object like in some other languages (Java or C# for instance). Objects will never change type, but you can have a reference or pointer of one type that points to an object of a derived type:
std::vector<Command*> commands;
A_COMMAND a_command;
commands.push_back(&a_command);
In this case commands[0] is a Command*, but it points to an A_COMMAND object.
RE your edit:
You are adding a pointer. &some_variable returns a pointer to some_variable, BUT you should absolutely never, ever do something like that. As soon as command goes out of scope, it will be destroyed and any access to it will result in undefined behavior. You will need to use dynamic memory allocation with new. It would probably be best to use a smart pointer class like std::shared_ptr<Command> to hold your dynamically allocated objects so you don't have to worry about deleteing them later.
If you use raw pointers then something like this will work:
A_COMMAND* command = new A_COMMAND;
commands.push_back(command);
If you go with that approach, you'll need to delete all of your commands when you're done with them (probably Parser's destructor):
for(Command* command : commands) {
delete command;
}
It would be better to use std::shared_ptrs though. Declare commands as std::vector<std::shared_ptr<Command>> commands;, then:
std::shared_ptr<A_COMMAND> command = std::make_shared<A_COMMAND>();
commands.push_back(command);
Then your objects will all get automatically deleteed when the last shared_ptr to them goes out of scope. If you use smart pointers you'll need to cast them slightly differently though. Look into std::dynamic_pointer_cast.
The real question is why use dynamic_cast at all.
This is a job for virtual methods.
If another class is derived, then your dynamic_cast will also need updating, with a virtual method you do not need to be concerned what the derived class is, only that it overrides the virtual method, which can be forced by using an interface class for the base (pure virtual methods, no state). This sounds like an application for the strategy pattern. https://en.wikipedia.org/wiki/Strategy_pattern.
try (it) instead of (*it)
the iterator should be a pointer to the object allready so you need to omit the * as this would result in the actual data not the reference
The situation I have is that I am trying to initialize a file scoped variable, std::string, in a shared object constructor. It will probably be more clear in code:
#include <string>
#include <dlfcn.h>
#include <cstring>
static std::string pathToDaemon; // daemon should always be in the same dir as my *.so
__attribute__((constructor))
static void SetPath()
{
int lastSlash(0):
Dl_info dl_info;
memset(&dl_info, 0, sizeof(dl_info));
if((dladdr((void*)SetPath, &dl_info)) == 0)
throw up;
pathToDaemon = dl_info.dli_fname; // **whoops, segfault here**
lastSlash = pathToDaemon.find_last_of('/');
if(std::string::npos == lastSlash)
{
// no slash, but in this dir
pathToDaemon = "progd";
}
else
{
pathToDaemon.erase(pathToDaemon.begin() + (lastSlash+1), pathToDaemon.end());
pathToDaemon.append("progd");
}
std::cout << "DEBUG: path to daemon is: " << pathToDaemon << std::endl;
}
I have a very simple program that does this same thing: a test driver program for concept if you will. The code in that looks just like this: a "shared object ctor" which uses dladdr() to store off the path of the *.so file when the file is loaded.
Modifications I've tried:
namespace {
std::string pathToDaemon;
__attribute__((constructor))
void SetPath() {
// function def
}
}
or
static std::string pathToDaemon;
__attribute__((constructor))
void SetPath() { // this function not static
// function def
}
and
std::string pathToDaemon; // variable not static
__attribute__((constructor))
void SetPath() { // this function not static
// function def
}
The example you see above sits in a file that is compiled into both a static object library and a DLL. The compilation process:
options for static.a: --std=C++0x -c -Os.
options for shared.so: -Wl,--whole-archive /path/to/static.a -Wl,--no-whole-archive -lz -lrt -ldl -Wl,-Bstatic -lboost_python -lboost_thread -lboost_regex -lboost_system -Wl,-Bdynamic -fPIC -shared -o mymodule.so [a plethora of more objects which wrap into python the static stuff]
The hoops I have to jump through in the bigger project make a much more complicated build process than my little test driver program requires. This makes me think that the problem lies there. Can anyone please shed some light on what I'm missing?
Thanks,
Andy
I think it's worth giving the answer that I've found. The problem was due to the complex nature of the shared library loading. I discovered after some digging that I could reproduce the problem in my test bed program when compiling the code with optimizations enabled. That confirmed the hypothesis that the variable truly didn't exist when it was being accessed by the constructor function.
GCC includes some extra tools for C++ which allow for developers to force certain things to happen at particular times during code initialization. More precisely, it allows for certain things to take place in particular order rather than particular times.
For example:
int someVar(55) __attribute__((init_priority(101)));
// This function is a lower priority than the initialization above
// so, this will happen *after*
__attribute__((constructor(102)))
void SomeFunc() {
// do important stuff
if(someVar == 55) {
// do something here that important too
someVar = 44;
}
}
I was able to use these tools to success in the test bed program even with optimizations enabled. The happiness which ensued was short lived when applied to my much larger library. Ultimately, the problem was due to the nature of such a large amount of code and the problematic way in which the variables are brought into existence. It just wasn't reliable to use these mechanisms.
Since I wanted to avoid repeated calls for evaluating the path, i.e.
std::string GetPath() {
Dl_info dl_info;
dladdr((void*)GetPath, &dl_info);
// do wonderful stuff to find the path
return dl_info.dli_fname;
}
The solution turned out to be much simpler than I was trying to make it:
namespace {
std::string PathToProgram() {
Dl_info dl_info;
dladdr((void*)PathToProgram, &dl_info);
std::string pathVar(dl_info.dli_fname);
// do amazing things to find the last slash and remove the shared object
// from that path and append the name of the external daemon
return pathVar;
}
std::string DaemonPath() {
// I'd forgotten that static variables, like this, are initialized
// only once due to compiler magic.
static const std::string pathToDaemon(PathToProgram());
return pathToDaemon;
}
}
As you can see, exactly what I wanted with less confusion. Everything happens only once, except calls to DaemonPath(), and everything remains within the translation unit.
I hope this helps someone who runs into this in the future.
Andy
Maybe you could try running valgrind on your program
In you self posted solution above, you have changed your »interface« (for the code that reads your pathToDaemon / DaemonPath()) from »Accessing a file scoped variable« to »calling a function in anonymous namespace« - so far ok.
But the implementation of DaemonPath() is not done in a thread-safe way. I though that thread-safeness matters, because your are wrote »-lboost_thread« in your question. So you may think about to change the implementation thread-safe. There are many discussions and solutions about singleton pattern and thread-safeness available, e.g.:
Article from Scott Meyers
Stack Overflow
The fact is, that your DaemonPath() will invoked (maybe far) after loading of the library is done. Note, that only the 1st call to the singleton pattern is critical in a multithreaded environment.
As an alternative, you may add a simple »early« call to your DaemonPath() function like this:
namespace {
std::string PathToProgram() {
... your code from above ...
}
std::string DaemonPath() {
... your code from above ...
}
__attribute__((constructor)) void MyPathInit() {
DaemonPath();
}
}
or in a more portable way like this:
namespace {
std::string PathToProgram() {
... your code from above ...
}
std::string DaemonPath() {
... your code from above ...
}
class MyPathInit {
public:
MyPathInit() {
DaemonPath();
}
} myPathInit;
}
Of course, this approach don't makes your singleton pattern thread-safe. But sometimes, there are situations, we can be sure that there are no concurrent thread accesses (e.g. at initialization time when the shared lib is loading). If this conditions matches for you, this approach could be a way to bypass thread-safeness problem without the use of thread locking (mutex...).
Question is in bold below :
This works fine:
void process_batch(
string_vector & v
)
{
training_entry te;
entry_vector sv;
assert(sv.size() == 0);
...
}
However, this causes the assert to fail :
void process_batch(
string_vector & v
)
{
entry_vector sv;
training_entry te;
assert(sv.size() == 0);
...
}
Now I know this issue isn't shrink wrapped, so I'll restrict my question to this: what conditions could cause such a problem ? Specifically: variable initialization getting damaged dependant on appearance order in the stack frame. There are no malloc's or free's in my code, and no unsafe functions like strcpy, memcpy etc... it's modern c++. Compilers used: gcc and clang.
For brevity here are the type's
struct line_string
{
boost::uint32_t line_no;
std::string line;
};
typedef std::vector<boost::uint32_t> line_vector;
typedef std::vector<line_vector> entry_vector;
typedef std::vector<line_string> string_vector;
struct training_body
{
boost::uint32_t url_id;
bool relevant;
};
struct training_entry
{
boost::uint32_t session_id;
boost::uint32_t region_id;
std::vector< training_body> urls;
};
p.s., I am in no way saying that there is a issue in the compiler, it's probably my code. But since I am templatizing some code I wrote a long time ago, the issue has me completely stumped, I don't know where to look to find the problem.
edit
followed nim's suggestion and went through the following loop
shrink wrap the code to what I have shown here, compile and test, no problem.
#if 0 #endif to shrink wrap the main program.
remove headers till it compiles in shrink wrapped form.
remove library links till compiles in shrink wrapped form.
Solution: removing link to protocol buffers gets rid of the problem
The C++ standard guarantees that the following assertion will succeed:
std::vector<anything> Default;
//in your case anything is line_vector and Default is sv
assert(Default.size() == 0);
So, either you're not telling the whole story or you have a broken STL implementation.
OR: You have undefined behavior in your code. The C++ standard gives no guarantees about the behavior of a program which has a construct leading to UB, even prior to reaching that construct.
The usual case for this when one of the created objects writes beyond
its end in the constructor. And the most frequent reason this happens
in code I've seen is that object files have been compiled with different
versions of the header; e.g. at some point in time, you added (or
removed) a data member of one of the classes, and didn't recompile all
of the files which use it.
What might cause the sort of problem you see is a user-defined type with a misbehaving constructor;
class BrokenType {
public:
int i;
BrokenType() { this[1].i = 9999; } // Bug!
};
void process_batch(
string_vector & v
)
{
training_entry te;
BrokenType b; // bug in BrokenType shows up as assert fail in std::vector
entry_vector sv;
assert(sv.size() < 100);
...
}
Do you have the right version of the Boost libaries suited for your platform? (64 bit/32 bit)? I'm asking since the entry_vector object seems to be have a couple of member variables of type boost::uint32_t. I'm not sure what could be the behaviour if your executable is built for one platform and the boost library loaded is of another platform.
I'm having some weird issues with static initalization. I'm using a code generator to generate structs and serialization code for a message passing system I wrote. In order to have a way of easily allocating a message based on it's message id I have my code generator ouput something similar to the following for each message type:
MessageAllocator s_InputPushUserControllerMessageAlloc(INPUT_PUSH_USER_CONTROLLER_MESSAGE_ID, (AllocateMessageFunc)Create_InputPushUserControllerMessage);
The MessageAllocator class basically looks like this:
MessageAllocator::MessageAllocator( uint32_t messageTypeID, AllocateMessageFunc func )
{
if (!s_map) s_map = new std::map<uint32_t, AllocateMessageFunc>();
if (s_map->insert(std::make_pair(messageTypeID, func)).second == false)
{
//duplicate key!
ASSERT(false, L"Nooooo!");
}
s_count++;
}
MessageAllocator::~MessageAllocator()
{
s_count--;
if (s_count == 0) delete s_map;
}
where s_map and s_count are static members of MessageAllocator. This works most of the time but sometimes messages are not added to the map. For example, this particular message is not added unless i call Create_InputPushUserControllerMessage() somewhere in my startup code, however other messages work fine. I thought this might be something to do with the linker incorrectly thinking the type is unreferenced and removing it so I disabled that using the /OPT:NOREF switch (I'm using Visual Studio 2008 SP1) but that had no effect.
I'm aware of the problem of the "static initialization order fiasco" but as far as I know the order in which these objects are created shouldn't alter the result so this seems ok to me.
Any insight here would be appreciated.
Put the static into a class so it is a static member of a class
struct InputPushUserControllerMessageAlloc { static MessageAllocator s_obj; };
MessageAllocator InputPushUserControllerMessageAlloc::s_obj(
INPUT_PUSH_USER_CONTROLLER_MESSAGE_ID,
(AllocateMessageFunc)Create_InputPushUserControllerMessage);
The Standard allows it to delay initialization of objects having namespace scope until any function/object from its translation unit is used. If the initialization has side-effect, it can't be optimized out. But that doesn't forbid delaying it.
Not so of objects having class-scope. So that might forbid it optimizing something there.
I would change s_map from a static class member into a static method member:
std::map<uint32_t,AllocateMessageFunc>& MessageAllocator::getMap()
{
// Initialized on first use and destroyed correctly on program termination.
static std::map<uint32_t,AllocateMessageFunc> s_map;
return s_map;
}
MessageAllocator::MessageAllocator( uint32_t messageTypeID, AllocateMessageFunc func )
{
if (getMap().insert(std::make_pair(messageTypeID, func)).second == false)
{
//duplicate key!
ASSERT(false, L"Nooooo!");
}
}
No need for destructor or a count.
If your global objects are in separate DLL's(or shared libs) that are lazy loaded.
This may cause a problem similar to your description.
You are not setting the pointer back to null.
MessageAllocator::~MessageAllocator()
{
s_count--;
if (s_count == 0)
{
delete s_map;
s_map = 0;
}
}
Turns out that the object files containing the static initializers were not included by the linker because nothing referenced any functions in them. To work around this I extern "C"-ed one of the generated functions so that it would have a predictable non-mangled name and then forced a reference to it using a pragma like this for each message
#pragma comment(linker, "/include:Create_GraphicsDynamicMeshCreationMessage")
which I put in the generated header file that is later included in all the other non-generated files. It's MSVC only and kind of hack but I assume I can do something similar on GCC once I eventually port it.