This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 4 years ago.
Compiling c code using cmake. What is likely causing this error in one of my objects file despite including the sqlite3.h file:
Undefined symbols for architecture x86_64:
"_sqlite3_close", referenced from:
_prv_temperature_read in object_temperature.c.o
"_sqlite3_column_double", referenced from:
_prv_temperature_read in object_temperature.c.o
"_sqlite3_errmsg", referenced from:
_prv_temperature_read in object_temperature.c.o
"_sqlite3_finalize", referenced from:
_prv_temperature_read in object_temperature.c.o
"_sqlite3_open", referenced from:
_prv_temperature_read in object_temperature.c.o
"_sqlite3_prepare_v2", referenced from:
_prv_temperature_read in object_temperature.c.o
"_sqlite3_step", referenced from:
_prv_temperature_read in object_temperature.c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
EDIT:
Here's the complete object_temperature.c object, invoked by lwm2mclient.c main class.
#include "liblwm2m.h"
#include "lwm2mclient.h"
//..#include <sqlite3.0.tbd>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sqlite3.h>
//...#include <libsqlite3.dylib>
//Resource Id's
#define RES_SENSOR_VALUE 5700
#define RES_SENSOR_UNITS 5701
typedef struct _prv_instance_
{
struct _prv_instance_ * next;
uint16_t shortID;
double temp;
char unit[10];
} prv_instance_t;
static uint8_t prv_temperature_read(uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
int i;
sqlite3 *db;
sqlite3_stmt *res;
int timer = 0;
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
fprintf(stderr, "----------------- Entering in oprv_temperature ----------------\n");
// connect to the backend
timer = time(NULL);
if (time(NULL) - timer > 60)
{
int rc = sqlite3_open("test.sqlite3", &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
} else {
fprintf(stdout, "DB Connection Successful..\n");
}
rc = sqlite3_prepare_v2(db, "SELECT temperature_data FROM environment ORDER BY ID DESC LIMIT 1", -1, &res, 0);
if (rc != SQLITE_OK) {
fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
rc = sqlite3_step(res);
if (rc == SQLITE_ROW) {
double t;
fprintf(stdout, "Yeah, rc == SQLITE_ROW \n");
t = sqlite3_column_double(res, 0);
targetP->temp = t;
}
sqlite3_finalize(res);
sqlite3_close(db);
timer = time(NULL);
}
if(*numDataP == 0)
{
*dataArrayP = lwm2m_data_new(1);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = 1;
(*dataArrayP)[0].id = RES_SENSOR_VALUE;
(*dataArrayP)[1].id = RES_SENSOR_UNITS;
}
for (i = 0; i < *numDataP; i++)
{
switch((*dataArrayP)[i].id)
{
case RES_SENSOR_VALUE:
lwm2m_data_encode_float(targetP->temp, *dataArrayP +1);
break;
case RES_SENSOR_UNITS:
return COAP_405_METHOD_NOT_ALLOWED;;
default:
return COAP_404_NOT_FOUND;
}
}
return COAP_205_CONTENT;
}
lwm2m_object_t * get_object_temperature()
{
/*
* The get_object_temperature function create the object itself and return a pointer to the structure that represent it.
*/
lwm2m_object_t * temperatureObj;
temperatureObj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t));
if (NULL != temperatureObj)
{
memset(temperatureObj, 0, sizeof(lwm2m_object_t));
/*
* Assigns it's unique ID 3303
*/
temperatureObj->objID = LWM2M_TEMPERATURE_OBJECT_ID;
/*
* and its unique instance
*
*/
temperatureObj->instanceList = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t));
if (NULL != temperatureObj->instanceList)
{
memset(temperatureObj->instanceList, 0, sizeof(lwm2m_list_t));
}
else
{
lwm2m_free(temperatureObj);
return NULL;
}
/*
* And the private function that will access the object.
* Those function will be called when a read/write/execute query is made by the server. In fact the library don't need to
* know the resources of the object, only the server does.
*/
temperatureObj->readFunc = prv_temperature_read;
//deviceObj->discoverFunc = prv_device_discover;
//deviceObj->writeFunc = prv_device_write;
//deviceObj->executeFunc = prv_device_execute;
//temperatureObj->userData = lwm2m_malloc(sizeof(prv_instance_t));
}
return temperatureObj;
}
void free_object_temperature(lwm2m_object_t * objectP)
{
if (NULL != objectP->userData)
{
lwm2m_free(objectP->userData);
objectP->instanceList = NULL;
}
if(NULL != objectP->instanceList)
{
lwm2m_free(objectP->instanceList);
objectP->instanceList = NULL;
}
lwm2m_free(objectP);
}
It is not enough to just include the sqlite3.h header file. You need to either
link against the sqlite3 library - using -lsqlite3 in your compiler/linker command, or
include the 'amalgamated' SQLite source file, sqlite3.c, amongst the source files you compile.
Regarding the second option, see https://sqlite.org/amalgamation.html .
Related
I'm trying to write C code to parse a config file using libconfig
The config file contains a simple element and a group. A group is composed of multiple settings, each has a unique name. ref
Config file :
host_name = "HOST";
device_settings:
{
rcu1:
{
product_id = 0x0001;
vendor_id = 0x0217;
},
rcu2:
{
product_id = 0x0001;
vendor_id = 0x0218;
}
}
I want to parse all RCUs data and store it in a data structre (the storing part is not a problem for now).
So I'm using the simple steps of :
Store the group in a config_setting_t * called section.
get length of section in a varaible called len
Iterrate len time to read RCUs data.
The problem is when i want to read RCU data i get a seg fault.
Code :
#include <libconfig.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
config_t cfg;
config_setting_t *root;
config_setting_t *section;
config_setting_t *elem;
int d, len;
config_init(&cfg);
if (config_read_file(&cfg,"./config.cfg") != CONFIG_TRUE) {
printf("[%s:%d] %s \n", config_error_file(&cfg),
config_error_line(&cfg), config_error_text(&cfg));
config_destroy(&cfg);
return -1;
}
if ((root = config_root_setting(&cfg)) == NULL) {
printf ("[%s:%d] %s \n", config_error_file(&cfg),
config_error_line(&cfg), config_error_text(&cfg));
config_destroy(&cfg);
return -1;
}
/* Device settings */
if ((section = config_setting_get_member(root, "device_settings")) != NULL)
{
len = config_setting_length(section);
printf("len = %d \n",len);
}
int i;
const char* device_id;
config_setting_t *device = NULL;
printf("device_settings %s a group \n",config_setting_is_group(section)?"is":"isn't");
for(i=0;i<len;i++) {
printf("iteration i = %d \n",i);
//device
if(device = config_setting_get_elem(section, i) != NULL) {
/*device id*/
if ((d = config_setting_lookup_string(device, "device_id",&device_id) != CONFIG_FALSE)) /*seg fault here*/
{
// Do stuff
}
}
}
return 0;
}
Something strange I noticed is when I compile the code i get this warning :
parse.c: In function ‘main’: parse.c:46:14: warning: assignment to
‘config_setting_t *’ {aka ‘struct config_setting_t *’} from ‘int’
makes pointer from integer without a cast [-Wint-conversion]
if(device = config_setting_get_elem(section, i) != NULL) {
GDB output :
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7da78a0 in config_setting_get_member () from
/lib/x86_64-linux-gnu/libconfig.so.9
ref to config_setting_get_elem(..)
I can not find what wrong Im doing. Everything looks correct to me.
Can someone see why the seg fault is happening?
if (device = config_setting_get_elem(section, i) != NULL)
needs to be
if ((device = config_setting_get_elem(section, i)) != NULL)
Because != has higher precedence than =.
I'm playing around the bfd library (<bfd.h>), and I was able to implement my own version of objdump -h on binary files by printing out sections, their vmas, size, etc. Now, I'm having trouble implementing nm. I'm able to use the bfd library to obtain all the different symbols of a binary executable file, but how can I get each symbol's (main, etc) vma using asection/asymbol struct data? Here's the code I have that prints out every symbol name:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <bfd.h>
int main(int argc, char *argv[])
{
bfd *ibfd = NULL;
if (!argv[1])
{
printf("Please supply a second argument\n");
return -1;
}
else
{
// initialize bfd so we can use it
bfd_init();
// open the supplied argument file
const char *str = argv[1];
ibfd = bfd_openr(str, "elf64-x86-64");
// if issue opening
if (!ibfd)
{
bfd_perror("open failure\n");
return -1;
}
// if file isnt elf binary file
if (!bfd_check_format(ibfd, bfd_object))
{
printf("not an object file\n");
return -1;
}
int spaceNeeded = bfd_get_symtab_upper_bound(ibfd);
if (spaceNeeded < 0)
{
return -1;
}
else if (spaceNeeded == 0)
{
return 1;
}
asymbol **symTable = malloc(spaceNeeded);
long numSyms = bfd_canonicalize_symtab(ibfd, symTable);
if (numSyms < 0)
return -1;
for (int i = 0, count = 0; i < numSyms; i++)
{
printf("%s\n", symTable[i]->name);
}
bfd_close(ibfd);
}
// success code
return 1;
}
nm uses the function bfd_symbol_info to fetch the virtual memory addresses of the symbols. You can read the source code for that function to get an idea as to the implementation.
void
bfd_symbol_info (symbol, ret)
asymbol *symbol;
symbol_info *ret;
{
ret->type = bfd_decode_symclass (symbol);
if (bfd_is_undefined_symclass (ret->type))
ret->value = 0;
else
ret->value = symbol->value + symbol->section->vma;
ret->name = symbol->name;
}
I'm using xmlTextReader to process large xml files. Now i need to validate the instance against an xsd schema. The api from libxml2 is a little bit confusing, how this is done.
With my approach, im getting the validation errors in the schemaParseErrorHandler function, but without any line numbers or column numbers.
How can i get these informations?
#include <stdio.h>
#include <libxml/xmlreader.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
static void schemaParseErrorHandler(void *arg, xmlErrorPtr error)
{
fprintf( stderr, "Error at line %d, column %d\n%s",
error->line, error->int2, error->message);
*((bool*)arg) = true;
}
int main( int argc, char **argv )
{
xmlInitParser();
xmlSchemaPtr schema = NULL;
xmlSchemaParserCtxtPtr schema_parser_ctxt = NULL;
int has_schema_errors = 0;
int ret = -1;
xmlSchemaValidCtxtPtr valid_ctxt = NULL;
if ((schema_parser_ctxt = xmlSchemaNewParserCtxt("example.xsd")))
{
schema = xmlSchemaParse(schema_parser_ctxt);
xmlSchemaFreeParserCtxt(schema_parser_ctxt);
if (schema)
{
valid_ctxt = xmlSchemaNewValidCtxt(schema);
}
}
xmlTextReaderPtr reader = NULL;
reader = xmlReaderForFile(filename, RPCXmlStream::STD_ENCODING, 0);
if (reader != NULL)
{
if (valid_ctxt)
{
xmlTextReaderSchemaValidateCtxt(reader, valid_ctxt, 0);
xmlSchemaSetValidStructuredErrors(valid_ctxt, schemaParseErrorHandler, &has_schema_errors);
}
ret = xmlTextReaderRead(reader);
while (ret == 1 && !has_schema_errors)
{
//... procesing informations
ret = xmlTextReaderRead(reader);
}
}
if (ret != 0)
{
xmlErrorPtr err = xmlGetLastError();
TRACE("%s: failed to parse in line %d, col %d. Error %d: %s\n",
err->file,
err->line,
err->int2,
err->code,
err->message);
}
xmlFreeTextReader(reader);
xmlCleanupParser();
return 0;
}
Another try was to use the function
xmlTextReaderSchemaValidate(reader, "example.xsd");
instead of creating an xmlSchemaNewValidCtxt, but than the programm is crashing on the first call to xmlTextReaderRead.
So how is validation done right, so that the error informations includes line and column numbers?
So, your questions got me thinking and when I looked in the libxml2 documentation,
Structure xmlError
struct _xmlError {
int domain : What part of the library raised this er
int code : The error code, e.g. an xmlParserError
char * message : human-readable informative error messag
xmlErrorLevel level : how consequent is the error
char * file : the filename
int line : the line number if available
char * str1 : extra string information
char * str2 : extra string information
char * str3 : extra string information
int int1 : extra number information
int int2 : error column # or 0 if N/A (todo: renam
void * ctxt : the parser context if available
void * node : the node in the tree
}
where we can clearly see that the xmlErrorPtr which is returned by the function xmlGetLastError() clearly contains information about the filename and the line number and the column number.
char * file : the filename
int line : the line number if available
...
int int2 : error column
So to test if this was possible or not, here is the code that I used (basically your code with minor changes to make it run on my system):
#include <stdio.h>
#include <stdbool.h>
#include <libxml/xmlreader.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
static void schemaParseErrorHandler(void *arg, xmlErrorPtr error)
{
fprintf(stderr, "Error at line %d, column %d\n%s", error->line, error->int2, error->message);
*((bool*)arg) = true;
}
int main( int argc, char **argv )
{
xmlInitParser();
xmlSchemaPtr schema = NULL;
xmlSchemaParserCtxtPtr schema_parser_ctxt = NULL;
int has_schema_errors = 0;
int ret = -1;
xmlSchemaValidCtxtPtr valid_ctxt = NULL;
if ((schema_parser_ctxt = xmlSchemaNewParserCtxt("/home/junglefox/shiporder.xsd")))
{
schema = xmlSchemaParse(schema_parser_ctxt);
xmlSchemaFreeParserCtxt(schema_parser_ctxt);
if (schema)
{
valid_ctxt = xmlSchemaNewValidCtxt(schema);
}
}
xmlTextReaderPtr reader = NULL;
const char* filename = "/home/junglefox/shiporder.xml";
reader = xmlReaderForFile(filename, /*RPCXmlStream::STD_ENCODING,*/ NULL, 0);
if (reader != NULL)
{
if (valid_ctxt)
{
xmlTextReaderSchemaValidateCtxt(reader, valid_ctxt, 0);
xmlSchemaSetValidStructuredErrors(valid_ctxt, schemaParseErrorHandler, &has_schema_errors);
}
ret = xmlTextReaderRead(reader);
while (ret == 1 && !has_schema_errors)
{
//... procesing informations
ret = xmlTextReaderRead(reader);
}
}
if (ret != 0)
{
xmlErrorPtr err = xmlGetLastError();
fprintf(stdout, "%s: failed to parse in line %d, col %d. Error %d: %s\n",
err->file,
err->line,
err->int2,
err->code,
err->message);
}
xmlFreeTextReader(reader);
xmlCleanupParser();
return 0;
}
where, the shiporder.xml and shiporder.xsd used in that program were copied from the url and saved locally.
I compiled and ran the code like this:
junglefox#ubuntu:~$ gcc -o test_xsd main.c -I/usr/include/libxml2/ -lxml2 -L/usr/lib/x86_64-linux-gnu/
junglefox#ubuntu:~$ ./test_xsd
junglefox#ubuntu:~$
The output this time was nothing. As it should be as there were no errors.
If however now I make an intentional error in the shiporder.xml file, as shown below:
Here is the partial-snippet from the buggy shiporder.xml:
<?xml version="1.0" encoding="UTF-8"?>
...
<item>
<title>Hide your heart</title>
<quantity>1</quantity>
price>9.90</price>
</item>
</shiporder>
Notice the missing < before price!
Now I run the program again,
junglefox#ubuntu:~$ ./test_xsd
Error at line 22, column 0
Element 'item': Character content other than whitespace is not allowed because the content type is 'element-only'.
which answers your question(s):
With my approach, im getting the validation errors in the schemaParseErrorHandler function, but without any line numbers or column numbers. How can i get these informations?
and,
So how is validation done right, so that the error informations includes line and column numbers?
as the output clearly shows the line number 22 and column 0, where there was an unexpected empty space due to the missing <.
I have a simple code that uses the PCRE library. I just wanted to know about the c code with pcre thus copied the code from http://www.mitchr.me/SS/exampleCode/AUPG/pcre_example.c.html
#include <pcre.h> /* PCRE lib NONE */
#include <stdio.h> /* I/O lib C89 */
#include <stdlib.h> /* Standard Lib C89 */
#include <string.h> /* Strings C89 */
/**********************************************************************************************************************************/
int main(int argc, char *argv[]) {
pcre *reCompiled;
pcre_extra *pcreExtra;
int pcreExecRet;
int subStrVec[30];
const char *pcreErrorStr;
int pcreErrorOffset;
char *aStrRegex;
char **aLineToMatch;
const char *psubStrMatchStr;
int j;
char *testStrings[] = { "This should match... hello",
"This could match... hello!",
"More than one hello.. hello",
"No chance of a match...",
NULL};
aStrRegex = "(.*)(hello)+";
printf("Regex to use: %s\n", aStrRegex);
// First, the regex string must be compiled.
reCompiled = pcre_compile(aStrRegex, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
/* OPTIONS (second argument) (||'ed together) can be:
PCRE_ANCHORED -- Like adding ^ at start of pattern.
PCRE_CASELESS -- Like m//i
PCRE_DOLLAR_ENDONLY -- Make $ match end of string regardless of \n's
No Perl equivalent.
PCRE_DOTALL -- Makes . match newlins too. Like m//s
PCRE_EXTENDED -- Like m//x
PCRE_EXTRA --
PCRE_MULTILINE -- Like m//m
PCRE_UNGREEDY -- Set quantifiers to be ungreedy. Individual quantifiers
may be set to be greedy if they are followed by "?".
PCRE_UTF8 -- Work with UTF8 strings.
*/
// pcre_compile returns NULL on error, and sets pcreErrorOffset & pcreErrorStr
if(reCompiled == NULL) {
printf("ERROR: Could not compile '%s': %s\n", aStrRegex, pcreErrorStr);
exit(1);
} /* end if */
// Optimize the regex
pcreExtra = pcre_study(reCompiled, 0, &pcreErrorStr);
/* pcre_study() returns NULL for both errors and when it can not optimize the regex. The last argument is how one checks for
errors (it is NULL if everything works, and points to an error string otherwise. */
if(pcreErrorStr != NULL) {
printf("ERROR: Could not study '%s': %s\n", aStrRegex, pcreErrorStr);
exit(1);
} /* end if */
for(aLineToMatch=testStrings; *aLineToMatch != NULL; aLineToMatch++) {
printf("String: %s\n", *aLineToMatch);
printf(" %s\n", "0123456789012345678901234567890123456789");
printf(" %s\n", "0 1 2 3");
/* Try to find the regex in aLineToMatch, and report results. */
pcreExecRet = pcre_exec(reCompiled,
pcreExtra,
*aLineToMatch,
strlen(*aLineToMatch), // length of string
0, // Start looking at this point
0, // OPTIONS
subStrVec,
30); // Length of subStrVec
/* pcre_exec OPTIONS (||'ed together) can be:
PCRE_ANCHORED -- can be turned on at this time.
PCRE_NOTBOL
PCRE_NOTEOL
PCRE_NOTEMPTY */
// Report what happened in the pcre_exec call..
//printf("pcre_exec return: %d\n", pcreExecRet);
if(pcreExecRet < 0) { // Something bad happened..
switch(pcreExecRet) {
case PCRE_ERROR_NOMATCH : printf("String did not match the pattern\n"); break;
case PCRE_ERROR_NULL : printf("Something was null\n"); break;
case PCRE_ERROR_BADOPTION : printf("A bad option was passed\n"); break;
case PCRE_ERROR_BADMAGIC : printf("Magic number bad (compiled re corrupt?)\n"); break;
case PCRE_ERROR_UNKNOWN_NODE : printf("Something kooky in the compiled re\n"); break;
case PCRE_ERROR_NOMEMORY : printf("Ran out of memory\n"); break;
default : printf("Unknown error\n"); break;
} /* end switch */
} else {
printf("Result: We have a match!\n");
// At this point, rc contains the number of substring matches found...
if(pcreExecRet == 0) {
printf("But too many substrings were found to fit in subStrVec!\n");
// Set rc to the max number of substring matches possible.
pcreExecRet = 30 / 3;
} /* end if */
// Do it yourself way to get the first substring match (whole pattern):
// char subStrMatchStr[1024];
// int i, j
// for(j=0,i=subStrVec[0];i<subStrVec[1];i++,j++)
// subStrMatchStr[j] = (*aLineToMatch)[i];
// subStrMatchStr[subStrVec[1]-subStrVec[0]] = 0;
//printf("MATCHED SUBSTRING: '%s'\n", subStrMatchStr);
// PCRE contains a handy function to do the above for you:
for(j=0; j<pcreExecRet; j++) {
pcre_get_substring(*aLineToMatch, subStrVec, pcreExecRet, j, &(psubStrMatchStr));
printf("Match(%2d/%2d): (%2d,%2d): '%s'\n", j, pcreExecRet-1, subStrVec[j*2], subStrVec[j*2+1], psubStrMatchStr);
} /* end for */
// Free up the substring
pcre_free_substring(psubStrMatchStr);
} /* end if/else */
printf("\n");
} /* end for */
// Free up the regular expression.
pcre_free(reCompiled);
// Free up the EXTRA PCRE value (may be NULL at this point)
if(pcreExtra != NULL)
pcre_free(pcreExtra);
// We are all done..
return 0;
} /* end func main */
while running the program as
gcc -o test -I/usr/local/Cellar/pcre/8.35/include -L/usr/local/Cellar/pcre/8.35/lib simple_pcre.c
gives the error as
Undefined symbols for architecture x86_64:
"_pcre_compile", referenced from:
_main in ccn0k76z.o
"_pcre_exec", referenced from:
_main in ccn0k76z.o
"_pcre_free", referenced from:
_main in ccn0k76z.o
"_pcre_free_substring", referenced from:
_main in ccn0k76z.o
"_pcre_get_substring", referenced from:
_main in ccn0k76z.o
"_pcre_study", referenced from:
_main in ccn0k76z.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
how should I compile the C code using Pcre library??
You're compiling with the -L flag which tells the linker where to find the library but I don't see a -l flag with the actual library to link.
I wrote a program "run_coffee.c" to implement fork() and exec() system calls. It fundamentally calls exec to start another process "coffee" built through "coffee.c" multiple times. The problem is I am running this program on cygwin64 in windows environment and it keeps failing with the following error -
**
error while loading shared libraries: ?: cannot open shared object
file: no such file or directory
**
I also ran cygcheck to see wether dependencies are being met or not. This is the output -
C:\cygwin64\home\Admin\run_coffee.exe C:\cygwin64\bin\cygwin1.dll
C:\Windows\system32\KERNEL32.dll
C:\Windows\system32\API-MS-Win-Core-RtlSupport-L1-1-0.dll
C:\Windows\system32\ntdll.dll C:\Windows\system32\KERNELBASE.dll
C:\Windows\system32\API-MS-Win-Core-ProcessThreads-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Heap-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Memory-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Handle-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Synch-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-File-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-IO-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-ThreadPool-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-LibraryLoader-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-NamedPipe-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Misc-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-SysInfo-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Localization-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-ProcessEnvironment-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-String-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Debug-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-ErrorHandling-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Fibers-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Util-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Core-Profile-L1-1-0.dll
C:\Windows\system32\API-MS-Win-Security-Base-L1-1-0.dll
No error or unmet dependency showed up so I guess all dependencies are being met. So what is causing this problem? Please Help.
Here are the two programs -
coffee.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[])
{
char *w = getenv("EXTRA");
if (!w)
w = getenv("FOOD");
if (!w)
w = argv[argc-1];
char *c = getenv("EXTRA");
if (!c)
c = argv[argc-1];
printf("%s with %s\n", c, w);
return 0;
}
run_coffee.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
struct food_options
{
char *food;
char *extra;
};
int main()
{
int i;
char **env;
env[0] = (char*)malloc(sizeof(char) * 20);
env[1] = (char*)malloc(sizeof(char) * 20);
env[2] = (char*)malloc(sizeof(char) * 20);
struct food_options *opts = (struct food_options *)malloc(sizeof(struct food_options) * 3);
opts[0].food = "coffee";
opts[0].extra = "donuts";
opts[1].food = "fish";
opts[1].extra = "chips";
opts[2].food = "kabab";
opts[2].extra = "parantha";
for (i = 0; i < 3; i++)
{
pid_t pid = fork();
if (pid == -1)
{
fprintf(stderr, "Cannot fork process. Fatal Error %s\n", strerror(errno));
return 1;
}
else if (!pid)
{
sprintf(env[0], "FOOD=%s", opts[0].food);
sprintf(env[1], "EXTRA=%s", opts[0].extra);
env[2] = NULL;
if (execle("coffee.exe","coffee.exe",NULL,env) == -1)
{
fprintf(stderr, "Cannot execute coffee.exe. Error %s\n", strerror(errno));
}
}
}
free(opts);
free(env[0]);
free(env[1]);
free(env[2]);
return 0;
}
There is a memory bug in your program which can cause undefined behavior: you declared env to be an array of char*'s, but you did not initialize env. Hence, env[0], env[1], and env[2] point to random locations in memory. When you do sprintf(env[0], ...) and sprintf(env[1], ...), you are writing data to some random location in memory (where ever env[0] and env[1] points to). This can cause almost anything to happen, including modification of the names of libraries, making you unable to load them.