boost test case from dll access violation - c++
I want to start Boost test case from dll under Windows RT. I built test case as dll via the Visual Studio command prompt using the following comandline:
cl.exe /EHsc /D_USRDLL /D_WINDLL /LDd ~location\testcase.cpp ~library location\libboost_unit_test_framework-vc110-mt-sgd-1_53.lib /link /DLL /OUT:~output directory\testcase.dll
placed it into my application’s folder and set property "Content" to "true". After launching of my application I have the following error:
Unhadled exception at the 0x00B9AF16 in TestApp.exe: 0xC0000005: Access violation reading location 0x00000000
Top of the call stack is below:
> TestApp.exe!boost::unit_test::framework::get(unsigned long id, boost::unit_test::test_unit_type t) Line 388 C++
TestApp.exe!boost::unit_test::framework::get(unsigned long id) Line 73 C++
TestApp.exe!boost::unit_test::traverse_test_tree(unsigned long id, boost::unit_test::test_tree_visitor & V) Line 232 C++
TestApp.exe!boost::unit_test::traverse_test_tree(const boost::unit_test::test_suite & suite, boost::unit_test::test_tree_visitor & V) Line 207 C++
TestApp.exe!boost::unit_test::traverse_test_tree(unsigned long id, boost::unit_test::test_tree_visitor & V) Line 234 C++
TestApp.exe!boost::unit_test::framework::run(unsigned long id, bool continue_test) Line 403 C++
TestApp.exe!boost::unit_test::unit_test_main(boost::unit_test::test_suite * (int, char * *) * init_func, int argc, char * * argv) Line 185 C++
Here is the dll code (NOTE: If I place the same code directly into my source, it works fine):
void test_stat()
{
//some code there
}
extern "C" {
__declspec (dllexport) test_suite* init_unit_test_suite( int argc, char* argv[] )
{
test_suite *test = BOOST_TEST_SUITE("test name");
test->add(BOOST_TEST_CASE(&test_stat));
return test;
}
}
Code of the application for launching of the test case:
boost::unit_test::test_suite* main_global_test_suite;
test_suite* init_unit_test_suite( int argc, char* argv[] ) {
return NULL; }
test_suite* run_global_test_suite (int, char* []) {
return main_global_test_suite;
}
HINSTANCE hMyDll;
typedef test_suite* (*PFN_MyFunction)(int,const char*);
PFN_MyFunction pfnMyFunction;
test_suite* rPtr;
if((hMyDll=::LoadPackagedLibrary(L"testcase", 0))==NULL)
{
return;
}
pfnMyFunction=(PFN_MyFunction)GetProcAddress(hMyDll,"init_unit_test_suite");
if (pfnMyFunction != NULL)
{
//just create fake arguments for the boost::unit_test::unit_test_main function call
char* argv[1024];
argv[0] = "Text";
rPtr = pfnMyFunction(1, NULL);
main_global_test_suite = rPtr;
const int error =
boost::unit_test::unit_test_main(&run_global_test_suite, 1, argv );
}
else
{
//handling code
}
FreeLibrary(hMyDll);
Is there any ideas how to solve the problem?
Check what console_test_runner is doing. This is command line application (part of Boost.Test), which intended to do just that - load and execute test units implemented in shared library. Also please make sure you tell UTF that you want to build dll: define BOOST_TEST_DYN_LINK.
Related
Problem with calling C++ function that receive command line arguments from Rust
I am trying to call a C++ function from rust. The function suppose to receive the command lines arguments then print it. I used cmake to compile the C++ code to a static archive. I write a build.rs script to referee to the static library location and to make the static linking to it. // library.cpp #include "library.h" #include <iostream> extern "C"{ void print_args(int argc, char *argv[]){ std::cout << "Have " << argc << " arguments:" << std::endl; std::cout<<argv<<std::endl; for (int i = 0; i < argc; ++i) { std::cout << argv[i] << std::endl; } } } //library.h extern "C"{ void print_args(int argc, char *argv[]); } //build.rs pub fn main(){ println!("cargo:rustc-link-search=.../cmake-build-debug"); //library.a directory println!("cargo:rustc-link-lib=static=stdc++"); println!("cargo:rustc-link-lib=static=library"); } //main.rs #[link(name = "library", kind = "static")] extern "C" { pub fn print_args(args: c_int, argsv: *const c_char); } fn main() { let args = std::env::args() .map(|arg| CString::new(arg).unwrap()) .collect::<Vec<CString>>(); let args_len: c_int = args.len() as c_int; let c_args_ptr = args.as_ptr() as *const c_char; unsafe { print_args(args_len, c_args_ptr) }; } When running the rust code by the command cargo run "10" "11" . it is only able to print the first argument which is the name of the program then the error error: process didn't exit successfully: target\debug\static_library_binding_test.exe 10 11 (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION) appears. it is the output rust main.rs Have 3 arguments: target\debug\static_library_binding_test.exe error: process didn't exit successfully: `target\debug\static_library_binding_test.exe 10 11` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION) So, I need to know how can I pass the command line argument from rust to the c++ function.
The problem is in this code: let args = std::env::args() .map(|arg| CString::new(arg).unwrap()) .collect::<Vec<CString>>(); // ... let c_args_ptr = args.as_ptr() as *const c_char; That creates a vector of CString objects, which you then proceed to cast into an array of pointers. But a CString consists of two word-sized values, a pointer and a length, and cannot be reinterpreted as a single pointer. To get an actual array of pointers which print_args() expects, you need to collect them into a separate vector: let args = std::env::args() .map(|arg| CString::new(arg).unwrap()) .collect::<Vec<CString>>(); let arg_ptrs: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect(); let args_len: c_int = args.len() as c_int; unsafe { print_args(args_len, arg_ptrs.as_ptr()) }; Note that you'll need to declare print_args as taking pointer to pointer, as it does in C++ (const char *argv[] is just sugar for const char **argv): #[link(name = "library", kind = "static")] extern "C" { pub fn print_args(args: c_int, argsv: *const *const c_char); }
error while loading shared libraries: jvm.dll
I am trying to run a java program using c++ code. I tried below code #include<jni.h> #include<stdio.h> int main(int argc, char** argv) { JavaVM* vm; JNIEnv* env; JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.nOptions = 0; vm_args.ignoreUnrecognized = 1; // Construct a VM jint results = JNI_CreateJavaVM(&vm, (void**)& env, &vm_args); // Construct a String jstring jstr = env->NewStringUTF("Hello World"); // First get the class that contains the method you need to call jclass clazz = env->FindClass("java/lang/String"); // Get the method that you want to call jmethodID to_lower = env->GetMethodID(clazz, "toLowerCase", "()Ljava/lang/String;"); // Call the method on the object jobject result = env->CallObjectMethod(jstr, to_lower); // Get a C-style string const char* str = env->GetStringUTFChars((jstring)result, NULL); printf("%s\n", str); // Clean up env->ReleaseStringUTFChars(jstr, str); // Shutdown the VM. vm->DestroyJavaVM(); } I used below command to compile the code g++ LoadJVM.c -I/c/apps64/Java/jdk-11.0.1/include -I/c/apps64/Java/jdk-11.0.1/include/win32 -L/c/apps64/Java/jdk-11.0.1/lib/ -ljvm It compiles fine, but when i run the executable like below, i am facing error ./a.exe Error error while loading shared libraries: jvm.dll: cannot open shared object file: No such file or directory Any Idea why this jvm.dll is not getting loaded? PS: I am compiling and running from Git-Bash on windows 10.
It looks like your jvm.dll can not be found. Let's say we have 32bit MinGW installation (this is the version I have). simple.cc #include<jni.h> #include<stdio.h> int main(int argc, char** argv) { JavaVM* vm; JNIEnv* env; JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.nOptions = 0; vm_args.ignoreUnrecognized = 1; // Construct a VM jint results = JNI_CreateJavaVM(&vm, (void**)& env, &vm_args); printf("Hello"); // Shutdown the VM. (*vm).DestroyJavaVM(); } compilation and execution > export JAVA_HOME="/c/Program\ Files\ \(x86\)/Java/jdk1.8.0_211/" > export PATH="/c/Program Files (x86)/Java/jdk1.8.0_211/jre/bin/server/":"$PATH" > g++ -o simple simple.cc -I"$JAVA_HOME/include/" -I"$JAVA_HOME/include/win32/" -L"$JAVA_HOME/lib" -ljvm > ./simple Hello you have to make sure that jvm.dll is visible on %PATH% - $PATH inside git-bash.
C++ Linking and running LuaJit compiled files with loadbuffer and runbuffer
I have compiled test.lua with LuaJit into test.obj and test.h. How do I correctly use the loadBuffer or runBuffer functions that I have? All I need to find out is basically how to place test.lua, test.obj and test.h into the command but I just cant, Ive tried hundreds of ways but nothing seems to work. I have stripped some other functions off from main and so forth that it would just leave the problem visible and not other things that work just fine. C++: This is the main int main(int argc, const char* argv[]) { std::vector<std::string> args(argv, argv + argc); g_lua.loadBuffer("test.lua", "test.obj") // I have tried both, runBuffer and loadBuffer but I just cant get it right, it always fails. } Here is the loadBuffer function: void LuaCodes::loadBuffer(const std::string& buffer, const std::string& source) { int ret = luaL_loadbuffer(L, buffer.c_str(), buffer.length(), source.c_str()); if(ret != 0) throw LuaException(popString(), 0); } Here is the runBuffer function: void LuaCodes::runBuffer(const std::string& buffer, const std::string& source) { loadBuffer(buffer, source); safeCall(0, 0); } Here are the insides of test.h: #define luaJIT_BC_test_SIZE 1186 static const char luaJIT_BC_test[] = { 27,76,74,1,2,154,9,2,0,12,0,47,0,151,1,52,0,0,0,55,0,1,0,52,1,2,0,55,1,3,1,62, 1,1,2,52,2,4,0,55,2,5,2,62,2,1,2,37,3,6,0,36,1,3,1,62,0,2,1,52,0,0,0,55,0,7,0, 52,1,8,0,55,1,9,1,37,2,10,0,62,1,2,0,61,0,0,1,52,0,0,0,55,0,7,0,52,1,4,0,55,1, 11,1,62,1,1,2,37,2,12,0,52,3,4,0,55,3,13,3,62,3,1,2,37,4,14,0,52,5,4,0,55,5, 15,5,62,5,1,2,37,6,16,0,52,7,4,0,55,7,17,7,62,7,1,2,37,8,18,0,52,9,4,0,55,9, 19,9,62,9,1,2,37,10,20,0,52,11,4,0,55,11,21,11,62,11,1,2,36,1,11,1,62,0,2,1, 52,0,2,0,55,0,22,0,52,1,2,0,55,1,3,1,62,1,1,2,37,2,23,0,36,1,2,1,41,2,2,0,62, 0,3,2,14,0,0,0,84,0,4,128,52,0,0,0,55,0,24,0,37,1,25,0,62,0,2,1,52,0,2,0,55,0, 22,0,52,1,2,0,55,1,3,1,62,1,1,2,37,2,26,0,36,1,2,1,41,2,2,0,62,0,3,2,14,0,0,0, 84,0,4,128,52,0,0,0,55,0,24,0,37,1,27,0,62,0,2,1,52,0,2,0,55,0,22,0,52,1,2,0, 55,1,3,1,62,1,1,2,37,2,28,0,36,1,2,1,41,2,2,0,62,0,3,1,52,0,2,0,55,0,29,0,52, 1,4,0,55,1,5,1,62,1,1,0,61,0,0,1,52,0,2,0,55,0,30,0,37,1,31,0,37,2,32,0,41,3, 2,0,62,0,4,1,52,0,33,0,55,0,34,0,37,1,35,0,62,0,2,1,52,0,36,0,55,0,37,0,62,0, 1,1,52,0,36,0,55,0,38,0,39,1,99,0,62,0,2,1,52,0,36,0,55,0,39,0,37,1,40,0,62,0, 2,1,52,0,36,0,55,0,39,0,37,1,41,0,62,0,2,1,52,0,36,0,55,0,38,0,39,1,243,1,62, 0,2,1,52,0,36,0,55,0,39,0,37,1,42,0,62,0,2,1,52,0,36,0,55,0,38,0,39,1,231,3, 62,0,2,1,52,0,36,0,55,0,39,0,37,1,43,0,62,0,2,1,52,0,36,0,55,0,38,0,39,1,15, 39,62,0,2,1,37,0,31,0,52,1,4,0,55,1,5,1,62,1,1,2,37,2,44,0,36,0,2,0,52,1,2,0, 55,1,45,1,16,2,0,0,62,1,2,2,15,0,1,0,84,2,3,128,52,1,46,0,16,2,0,0,62,1,2,1, 71,0,1,0,11,100,111,102,105,108,101,15,102,105,108,101,69,120,105,115,116,115, 7,114,99,19,103,97,109,101,95,105,110,116,101,114,102,97,99,101,11,99,108,105, 101,110,116,12,103,97,109,101,108,105,98,12,99,111,114,101,108,105,98,23,101, 110,115,117,114,101,77,111,100,117,108,101,76,111,97,100,101,100,20,97,117, 116,111,76,111,97,100,77,111,100,117,108,101,115,20,100,105,115,99,111,118, 101,114,77,111,100,117,108,101,115,14,103,95,109,111,100,117,108,101,115,17, 47,99,111,110,102,105,103,46,111,116,109,108,9,108,111,97,100,14,103,95,99, 111,110,102,105,103,115,11,46,111,116,112,107,103,6,47,25,115,101,97,114,99, 104,65,110,100,65,100,100,80,97,99,107,97,103,101,115,22,115,101,116,117,112, 85,115,101,114,87,114,105,116,101,68,105,114,9,109,111,100,115,56,85,110,97, 98,108,101,32,116,111,32,97,100,100,32,109,111,100,117,108,101,115,32,100,105, 114,101,99,116,111,114,121,32,116,111,32,116,104,101,32,115,101,97,114,99,104, 32,112,97,116,104,46,12,109,111,100,117,108,101,115,53,85,110,97,98,108,101, 32,116,111,32,97,100,100,32,100,97,116,97,32,100,105,114,101,99,116,111,114, 121,32,116,111,32,116,104,101,32,115,101,97,114,99,104,32,112,97,116,104,46, 10,102,97,116,97,108,9,100,97,116,97,18,97,100,100,83,101,97,114,99,104,80,97, 116,104,17,103,101,116,66,117,105,108,100,65,114,99,104,15,32,102,111,114,32, 97,114,99,104,32,17,103,101,116,66,117,105,108,100,68,97,116,101,16,41,32,98, 117,105,108,116,32,111,110,32,19,103,101,116,66,117,105,108,100,67,111,109, 109,105,116,7,32,40,21,103,101,116,66,117,105,108,100,82,101,118,105,115,105, 111,110,10,32,114,101,118,32,15,103,101,116,86,101,114,115,105,111,110,6,32, 12,103,101,116,78,97,109,101,42,61,61,32,97,112,112,108,105,99,97,116,105,111, 110,32,115,116,97,114,116,101,100,32,97,116,32,37,98,32,37,100,32,37,89,32,37, 88,9,100,97,116,101,7,111,115,9,105,110,102,111,9,46,108,111,103,19,103,101, 116,67,111,109,112,97,99,116,78,97,109,101,10,103,95,97,112,112,15,103,101, 116,87,111,114,107,68,105,114,16,103,95,114,101,115,111,117,114,99,101,115,15, 115,101,116,76,111,103,70,105,108,101,13,103,95,108,111,103,103,101,114,0 };
For luaL_loadbuffer (and hence LuaCodes::loadBuffer) the 1st argument should be a string containing the bytecode and the 2nd argument should be a human-readable name (e.g. the filename that the bytecode was compiled from.) Try: #include "test.h" // ... int main(int argc, const char* argv[]) { // ... std::string bytecode(luaJIT_BC_test, luaJIT_BC_test_SIZE); g_lua.loadBuffer(bytecode, "#test.lua") }
Error: X86CodeEmitter LLVM
I'm having the following problem when I run my program: pseudo instructions should be removed before code emission UNREACHABLE executed at /home/leonor/llvm/llvm/lib/Target/X86/X86CodeEmitter.cpp:1164! Stack dump: 0. Running pass 'X86 Machine Code Emitter' on function '#main' ./build/Release+Asserts/bin/llvm-dis: Bitcode stream must be at least 16 bytes in length My program takes as input a .bc file and then loads the file and shows it. My doubt is: Why is this error happens only when the C program contains conditional statements (if, for ..). How to solve?? My code: int main(int argc, char **argv) { InitializeNativeTarget(); LLVMContext &Context = getGlobalContext(); std::string Err; const std::string InputFile = "teste_f1.bc"; OwningPtr<MemoryBuffer> result; error_code ec = MemoryBuffer::getFile(InputFile, result); MemoryBuffer *buffer = result.take(); Module * Mod = ParseBitcodeFile(buffer, Context); ExecutionEngine* EE = 0; EngineBuilder builder(Mod); builder.setErrorStr(&Err); builder.setEngineKind(EngineKind::JIT); EE = builder.create(); Function * func = Mod->getFunction("main"); std::vector <std::string> params; params.push_back(Mod->getModuleIdentifier()); EE->runStaticConstructorsDestructors(false); int Result = EE->runFunctionAsMain(func, params, NULL); EE->runStaticConstructorsDestructors(true); WriteBitcodeToFile(Mod, outs()); delete Mod; return 0; }
It is because the code containing conditional statements (if,for etc), results in an IR which contains phi nodes. You can remove the phi nodes by using reg2mem pass. The command would be: opt -reg2mem -o output.bc input.bc
Breaking down WinMain's cmdLine in old style main()'s arguments
I want to convert WinMain's cmdLine argument to argc and argv so I can use the argument parsing function I wrote for console applications. This would be trivial except that I want to support "quotes" too. For example: test.exe test1 test2 "testing testing" should be argv[0] = "test.exe"; argv[1] = "test1"; argv[2] = "test2"; argv[3] = "testing testing"; I realize that cmdLine doesn't have the program name (the argv[0]); this doesn't matter I can use a dummy value. I was thinking of doing it with a regex, (("[^"]+")\s+)|(([^\s]+)\s*) I'm not sure how well it would work though.. Probably not very well? Is there any function to do that in the windows api? Thanks
If you are using Microsoft compiler, there are public symbols __argc, __argv and __wargv defined in stdlib.h. This also applies to MinGW that uses Microsoft runtime libraries.
Based on Denis K response See: https://msdn.microsoft.com/library/dn727674.aspx This adds Windows specific entrypoint to clasic startpoint of your app: int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char*, int nShowCmd) { return main(__argc, __argv); }
CommandLineToArgvW looks like it would be helpful here.
If you want plain int argc, char** argv arguments you have to do it on your own. void fetchCmdArgs(int* argc, char*** argv) { // init results *argc = 0; // prepare extraction char* winCmd = GetCommandLine(); int index = 0; bool newOption = true; // use static so converted command line can be // accessed from outside this function static vector<char*> argVector; // walk over the command line and convert it to argv while(winCmd[index] != 0){ if (winCmd[index] == ' ') { // terminate option string winCmd[index] = 0; newOption = true; } else { if(newOption){ argVector.push_back(&winCmd[index]); (*argc)++; } newOption = false; } index++; } // elements inside the vector are guaranteed to be continous *argv = &argVector[0]; } // usage int APIENTRY WinMain(...) { int argc = 0; char** argv; fetchCmdArgs(&argc, &argv); }