I'm trying to start a tutorial about libclang library, but I get an access violation when calling the function clang_getSpellingLocation()
. Other information about the error is correctly reported with error count, line and column.
My environment: C++Builder XE pro, Windows 7 32bit, LLVM 3.4, libCLang.lib converted using coff2omf, libCLang.dll.
I tested the same code on visual C++ 2010 and it works correctly.
Please could anyone you help me about this issue?
My simple code
//---------------------------------------------------------------------------
void __fastcall TForm8::Button1Click(TObject *Sender)
{
unsigned line, column;
CXIndex index = clang_createIndex(0, 0);
const char * args [] = {
"-I/usr/include" ,
"-I."
};
int numArgs = sizeof ( args ) / sizeof ( * args );
CXTranslationUnit tu = clang_parseTranslationUnit(index, "G:\\projects\\LibCLang \\File2.cpp", args, numArgs, NULL, 0, CXTranslationUnit_None);
unsigned diagnosticCount = clang_getNumDiagnostics ( tu );
for ( unsigned i = 0 ; i < diagnosticCount ; i++ )
{
CXDiagnostic diagnostic = clang_getDiagnostic ( tu , i );
CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
clang_getSpellingLocation(location, NULL, &line, &column, NULL);
CXString text = clang_getDiagnosticSpelling(diagnostic);
UnicodeString s = clang_getCString(text);
}
}
Are you sure the AV is on clang_getSpellingLocation()
and not clang_getDiagnosticSpelling()
?
When using the __cdecl
calling convention, compilers from different vendors are allowed to do whatever they want when it comes to returning a structure by value when the size of the structure is <= 8 bytes. In the case of clang_getDiagnosticSpelling()
, CXString
is 8 bytes in a 32bit environment. Some compilers, like Visual C++, return the contents of an 8-byte structure directly in the EAX:EDX
CPU registers, whereas other compilers, like C++Builder, use a hidden output parameter that passes a reference to a temp structure.
clang_getDiagnosticSpelling()
(and other similar functions) return a CXString
using EAX:EDX
, but C++Builder uses a hidden parameter instead. There is a simple workaround for that. C++Builder expects a __cdecl
function to return an __int64
using EAX:EDX
, and since CXString
and __int64
are the same size in 32bit, you can do the following:
typedef __int64 __cdecl (*clang_getDiagnosticSpellingHack)(CXDiagnostic);
//CXString text = clang_getDiagnosticSpelling(diagnostic);
clang_getDiagnosticSpellingHack func = reinterpret_cast<clang_getDiagnosticSpellingHack>(&clang_getDiagnosticSpelling);
__int64 tmp = func(diagnostic);
CXString text = reinterpret_cast<CXString&>(tmp);
Alternatively, you can utilize C++Builder's _EAX
and _EDX
intrinsics:
typedef void __cdecl (*clang_getDiagnosticSpellingHack)(CXDiagnostic);
//CXString text = clang_getDiagnosticSpelling(diagnostic);
clang_getDiagnosticSpellingHack func = reinterpret_cast<clang_getDiagnosticSpellingHack>(&clang_getDiagnosticSpelling);
CXString text;
func(diagnostic);
text.ptr_data = (void*) _EAX;
text.int_data = _EDX;
As for clang_getSpellingLocation()
, I would not expect there to be such a mismatch in conventions since it has no return value, unless clang_getSpellingLocation()
were compiled to accept its CXSourceLocation
parameter differently than how C++Builder is passing it. C++Builder pushes all three data values from CXSourceLocation
directly on the call stack. You would have to look at the disassembly of clang_getSpellingLocation()
to see how it is actually accessing the values of its CXSourceLocation
parameter, and then adjust your C++Builder code accordingly if needed.
You should also double-check how clang_getDiagnosticLocation()
is returning its CXSourceLocation
to make sure that it matches how C++Builder expects it to be returned (via a hidden output parameter by reference) to ensure that memory is not being corrupted before clang_getSpellingLocation()
is being called. So it is possible that clang_getSpellingLocation()
itself might not be the culprit. Hard to say without seeing the disassembly for both clang_getDiagnosticLocation()
and clang_getSpellingLocation()
(I have seen the disassembly for functions that return CXString
, that is how I know for sure that clang uses EAX:EDX
for that).