I have some long source code that involves a struct definition:
struct exec_env {
cl_program* cpPrograms;
cl_context cxGPUContext;
int cpProgramCount;
int cpKernelCount;
int nvidia_platform_index;
int num_cl_mem_buffs_used;
int total;
cl_platform_id cpPlatform;
cl_uint ciDeviceCount;
cl_int ciErrNum;
cl_command_queue commandQueue;
cl_kernel* cpKernels;
cl_device_id *cdDevices;
cl_mem* cmMem;
};
The strange thing, is that the output of my program is dependent on the order in which I declare the components of this struct. Why might this be?
EDIT:
Some more code:
int HandleClient(int sock) {
struct exec_env my_env;
int err, cl_err;
int rec_buff [sizeof(int)];
log("[LOG]: In HandleClient. \n");
my_env.total = 0;
//in anticipation of some cl_mem buffers, we pre-emtively init some. Later, we should have these
//grow/shrink dynamically.
my_env.num_cl_mem_buffs_used = 0;
if ((my_env.cmMem = (cl_mem*)malloc(MAX_CL_BUFFS * sizeof(cl_mem))) == NULL)
{
log("[ERROR]:Failed to allocate memory for cl_mem structures\n");
//let the client know
replyHeader(sock, MALLOC_FAIL, UNKNOWN, 0, 0);
return EXIT_FAILURE;
}
my_env.cpPlatform = NULL;
my_env.ciDeviceCount = 0;
my_env.cdDevices = NULL;
my_env.commandQueue = NULL;
my_env.cxGPUContext = NULL;
while(1){
log("[LOG]: Awaiting next packet header... \n");
//read the first 4 bytes of the header 1st, which signify the function id. We later switch on this value
//so we can read the rest of the header which is function dependent.
if((err = receiveAll(sock,(char*) &rec_buff, sizeof(int))) != EXIT_SUCCESS){
return err;
}
log("[LOG]: Got function id %d \n", rec_buff[0]);
log("[LOG]: Total Function count: %d \n", my_env.total);
my_env.total++;
//now we switch based on the function_id
switch (rec_buff[0]) {
case CREATE_BUFFER:;
{
//first define a client packet to hold the header
struct clCreateBuffer_client_packet my_client_packet_hdr;
int client_hdr_size_bytes = CLI_PKT_HDR_SIZE + CRE_BUFF_CLI_PKT_HDR_EXTRA_SIZE;
//buffer for the rest of the header (except the size_t)
int header_rec_buff [(client_hdr_size_bytes - sizeof(my_client_packet_hdr.buff_size))];
//size_t header_rec_buff_size_t [sizeof(my_client_packet_hdr.buff_size)];
size_t header_rec_buff_size_t [1];
//set the first field
my_client_packet_hdr.std_header.function_id = rec_buff[0];
//read the rest of the header
if((err = receiveAll(sock,(char*) &header_rec_buff, (client_hdr_size_bytes - sizeof(my_client_packet_hdr.std_header.function_id) - sizeof(my_client_packet_hdr.buff_size)))) != EXIT_SUCCESS){
//signal the client that something went wrong. Note we let the client know it was a socket read error at the server end.
err = replyHeader(sock, err, CREATE_BUFFER, 0, 0);
cleanUpAllOpenCL(&my_env);
return err;
}
//read the rest of the header (size_t)
if((err = receiveAll(sock, (char*)&header_rec_buff_size_t, sizeof(my_client_packet_hdr.buff_size))) != EXIT_SUCCESS){
//signal the client that something went wrong. Note we let the client know it was a socket read error at the server end.
err = replyHeader(sock, err, CREATE_BUFFER, 0, 0);
cleanUpAllOpenCL(&my_env);
return err;
}
log("[LOG]: Got the rest of the header, packet size is %d \n", header_rec_buff[0]);
log("[LOG]: Got the rest of the header, flags are %d \n", header_rec_buff[1]);
log("[LOG]: Buff size is %d \n", header_rec_buff_size_t[0]);
//set the remaining fields
my_client_packet_hdr.std_header.packet_size = header_rec_buff[0];
my_client_packet_hdr.flags = header_rec_buff[1];
my_client_packet_hdr.buff_size = header_rec_buff_size_t[0];
//get the payload (if one exists)
int payload_size = (my_client_packet_hdr.std_header.packet_size - client_hdr_size_bytes);
log("[LOG]: payload_size is %d \n", payload_size);
char* payload = NULL;
if(payload_size != 0){
if ((payload = malloc(my_client_packet_hdr.buff_size)) == NULL){
log("[ERROR]:Failed to allocate memory for payload!\n");
replyHeader(sock, MALLOC_FAIL, UNKNOWN, 0, 0);
cleanUpAllOpenCL(&my_env);
return EXIT_FAILURE;
}
if((err = receiveAllSizet(sock, payload, my_client_packet_hdr.buff_size)) != EXIT_SUCCESS){
//signal the client that something went wrong. Note we let the client know it was a socket read error at the server end.
err = replyHeader(sock, err, CREATE_BUFFER, 0, 0);
free(payload);
cleanUpAllOpenCL(&my_env);
return err;
}
}
//make the opencl call
log("[LOG]: ***num_cl_mem_buffs_used before***: %d \n", my_env.num_cl_mem_buffs_used);
cl_err = h_clCreateBuffer(&my_env, my_client_packet_hdr.flags, my_client_packet_hdr.buff_size, payload, &my_env.cmMem);
my_env.num_cl_mem_buffs_used = (my_env.num_cl_mem_buffs_used+1);
log("[LOG]: ***num_cl_mem_buffs_used after***: %d \n", my_env.num_cl_mem_buffs_used);
//send back the reply with the error code to the client
log("[LOG]: Sending back reply header \n");
if((err = replyHeader(sock, cl_err, CREATE_BUFFER, 0, (my_env.num_cl_mem_buffs_used -1))) != EXIT_SUCCESS){
//send the header failed, so we exit
log("[ERROR]: Failed to send reply header to client, %d \n", err);
log("[LOG]: OpenCL function result was %d \n", cl_err);
if(payload != NULL) free(payload);
cleanUpAllOpenCL(&my_env);
return err;
}
//now exit if failed
if(cl_err != CL_SUCCESS){
log("[ERROR]: Error executing OpenCL function clCreateBuffer %d \n", cl_err);
if(payload != NULL) free(payload);
cleanUpAllOpenCL(&my_env);
return EXIT_FAILURE;
}
}
break;
Now what's really interesting is the call to h_clCreateBuffer. This function is as follows
int h_clCreateBuffer(struct exec_env* my_env, int flags, size_t size, void* buff, cl_mem* all_mems){
/*
* TODO:
* Sort out the flags.
* How do we store cl_mem objects persistantly? In the my_env struct? Can we have a pointer int the my_env
* struct that points to a mallocd area of mem. Each malloc entry is a pointer to a cl_mem object. Then we
* can update the malloced area, growing it as we have more and more cl_mem objects.
*/
//check that we have enough pointers to cl_mem. TODO, dynamically expand if not
if(my_env->num_cl_mem_buffs_used == MAX_CL_BUFFS){
return CL_MEM_OUT_OF_RANGE;
}
int ciErrNum;
cl_mem_flags flag;
if(flags == CL_MEM_READ_WRITE_ONLY){
flag = CL_MEM_READ_WRITE;
}
if(flags == CL_MEM_READ_WRITE_OR_CL_MEM_COPY_HOST_PTR){
flag = CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR;
}
log("[LOG]: Got flags. Calling clCreateBuffer\n");
log("[LOG]: ***num_cl_mem_buffs_used before in function***: %d \n", my_env->num_cl_mem_buffs_used);
all_mems[my_env->num_cl_mem_buffs_used] = clCreateBuffer(my_env->cxGPUContext, flag , size, buff, &ciErrNum);
log("[LOG]: ***num_cl_mem_buffs_used after in function***: %d \n", my_env->num_cl_mem_buffs_used);
log("[LOG]: Finished clCreateBuffer with id: %d \n", my_env->num_cl_mem_buffs_used);
//log("[LOG]: Finished clCreateBuffer with id: %d \n", buff_counter);
return ciErrNum;
}
The first time round the while loop, my_env->num_cl_mem_buffs_used is increased by 1. However, the next time round the loop, after the call to clCreateBuffer, the value of my_env->num_cl_mem_buffs_used gets reset to 0. This does not happen when I change the order in which I declare the members of the struct! Thoughts? Note that I've omitted the other case statements, all of which so similar things, i.e. updating the structs members.
Well, if your program dumps the raw memory content of the object of your struct type, then the output will obviously depend on the ordering of the fields inside your struct. So, here's one obvious scenario that will create such a dependency. There are many others.
Why are you surprised that the output of your program depends on that order? In general, there's nothing strange in that dependency. If you base your verdict of on the knowledge of the rest of the code, then I understand. But people here have no such knowledge and we are not telepathic.
It's hard to tell. Maybe you can post some code. If I had to guess, I'd say you were casting some input file (made of bytes) into this struct. In that case, you must have the proper order declared (usually standardized by some protocol) for your struct in order to properly cast or else risk invalidating your data.
For example, if you have file that is made of two bytes and you are casting the file to a struct, you need to be sure that your struct has properly defined the order to ensure correct data.
struct example1
{
byte foo;
byte bar;
};
struct example2
{
byte bar;
byte foo;
};
//...
char buffer[];
//fill buffer with some bits
(example1)buffer;
(example2)buffer;
//those two casted structs will have different data because of the way they are defined.
In this case, "buffer" will always be filled in the same manner, as per some standard.
Of course the output depends on the order. Order of fields in a struct matters.
An additional explanation to the other answers posted here: the compiler may be adding padding between fields in the struct, especially if you are on a 64 bit platform.
If you are not using binary serialization, then your best bet is an invalid pointer issue. Like +1 error, or some invalid pointer arithmetics can cause this. But it is hard to know without code. And it is still hard to know, even with the code. You may try to use some kind of pointer validation/tracking system to be sure.
other guesses
by changing the order you are having different uninitialized values in the struct. A pointer being zero or not zero for example
you somehow manage to overrun an item (by casting ) and blast later items. Different items get blasted depending on order
This may happen if your code uses on "old style" initializer as from C89. For a simple example
struct toto {
unsigned a;
double b;
};
.
.
toto A = { 0, 1 };
If you interchange the fields in the definition this remains a valid initializer, but your fields are initialized completely different. Modern C, AKA C99, has designated initializers for that:
toto A = { .a = 0, .b = 1 };
Now, even when reordering your fields or inserting a new one, your initialization remains valid.
This is a common error which is perhaps at the origin of the initializerphobia that I observe in many C89 programs.
You have 14 fields in your struct, so there is 14! possible ways the compiler and/or standard C library can order them during the output.
If you think from the compiler designer's point of view, what should the order be? Random is certainly not useful. The only useful order is the order in which the struct fields were declared by you.
Related
I got a struct Chat
struct Chat
{
int m_FD;
int m_BindPort;
char m_NameLength;
char* m_Name;
char m_PeerCount;
char** m_PeerList;
} typedef Chat_t;
i'm initializing it with this function:
int chat_init(Chat_t* this, unsigned int nameLen, char* name, unsigned short int bindPort, unsigned int peerCount, char** peerList)
{
this->m_NameLength = nameLen;
this->m_Name = malloc(sizeof(char) * (nameLen+1));
strcpy(this->m_Name, name);
this->m_BindPort = bindPort;
this->m_PeerCount = peerCount;
this->m_PeerList = malloc(sizeof(char*) * peerCount);
for(int i=0; i<peerCount; i++)
{
this->m_PeerList[i] = malloc(sizeof(char) * 16); // enough for xxx.xxx.xxx.xxx\0
strcpy(this->m_PeerList[i], peerList[i]);
}
//Socket initialization for TCP connection...
//Commenting this out doesn't change anything so i'm hiding it for simplification
return 0;
}
After that i'm calling a second function
int chat_communicate(Chat_t* this)
{
printf("2\n");
fflush(stdout);
//Some stuff that doesn't matter because it isn't even called
return retVar;
}
in main like this
void main(void)
{
char* peerList[1];
char username[USERNAME_MAX_LEN];
int initRet;
int loopRet;
Chat_t chat;
peerList[0] = "192.168.2.2";
memset(username, 0, USERNAME_MAX_LEN);
printf("Please enter your user name: ");
scanf("%s", username);
username[USERNAME_MAX_LEN-1] = 0;
initRet = chat_init(&chat, strlen(username), username, 1234, 1, peerList);
printf("File Descriptor: %d\n", chat.m_FD);
printf("Binding Port: %d\n", chat.m_BindPort);
printf("Name Length: %d\n", chat.m_NameLength);
printf("Name: %s\n", chat.m_Name);
printf("Peer Count: %d\n", chat.m_PeerCount);
for(int i=0; i< chat.m_PeerCount; i++)
{
printf("Peer[%d]: %s\n", i, chat.m_PeerList[i]);
}
printf("1");
ret = chat_communicate(&chat);
//Even more Stuff that isn't even called
}
My program outputs the following
File Descriptor: 3
Binding Port: 1234
Name Length: 4
Name: User
Peer Count: 1
Peer[0]: 192.168.2.2
1
Segmentation Fault
It compiles without errors or even warnings.
You can also assume that every string is null-Terminated The stuff i replaced with comments itn't that complicated but just too much to show.
Every value inside the struct is printed with printf right before but when passing this very struct per reference the application crashes.
What i want to know is why i'm getting this Segmentation Fault. Since it appeared while calling a function i thought it is some kind of layout problem but i havn't find anything like that.
Addition:
Because some people weren't able to believe me that the code i hid behind "some stuff" comments doesn't change anything i want to state this here once again. This code just contains a tcp socket communication and only performs read-operations. I also am able to reproduce the error mentioned above without this code so please don't get stuck with it. Parts does not influence the object under observation at all.
Among other potential problems,
this->m_PeerList = malloc(sizeof(char)*peerCount);
is clearly wrong.
m_PeerList is a char **, yet you're only allocating peerCount bytes, which only works if a char * pointer is one byte on your system - not likely.
Replace it with something like
this->m_PeerList = malloc(peerCount * sizeof( *( this->m_peerList ) ) );
Note that sizeof( char ) is always one - by definition.
You're not allocating enough memory for the this->m_Name. It should be on more than this if you want it to store the null-terminated string of the name.
That, or we need more information about the peerList.
Now that you have posted an almost complete code, I was able to spot two problems next to each other:
int chat_init(Chat_t* this, unsigned int nameLen, char* name, unsigned short int bindPort, unsigned int peerCount, char** peerList)
{
this->m_NameLength = nameLen;
this->m_Name = malloc(sizeof(char) * (nameLen + 1)); // correct
//< this->m_Name = malloc(sizeof(char) * nameLen); // wrong
strcpy(this->m_Name, name); // correct
//< memcpy(this->m_Name, name, nameLen); // wrong
...
The lines starting with //< is your original code:
Here you don't allocate enough space, you need to account for the NUL terminator:
this->m_Name = malloc(sizeof(char) * nameLen);
And here you don't copy the NUL terminator:
memcpy(this->m_Name, name, nameLen);
You really need to be aware how strings work in C.
Why don't you debug it yourself. If using GCC, compile your code with options -g -O0. Then run it with gdb:
gdb ./a.out
...
(gdb) r
If it crashes do:
(gdb) bt
This will give exactly where it crashes.
Update: There may be potential problems with your code as found by other users. However, memory allocation related issues will not crash your application just on calling function chat_communicate. There could be different reasons for this behaviour ranging from stack overflow to improper compilation. Without seeing the whole code it is very difficult to tell. Best advice is to consider review comments by other users and debug it yourself.
I have a problem with a simple malloc/free functions I use in a more complex program and I can't find how to get rid of this problem.
My project looks like :
main.c
while(1){programm();}
I tried a lot of tests to know where it come from but I just can't find a solution...
here is the code part where it seems to bug :
programm.c
void programm(){
... Creating variables and getting infos from socket ...
char a[512];
char b[512];
sprintf(a,"blablabla",strlen(a));
sprintf(b,"blablabla",strlen(b));
char* MessageOut = NULL;
MessageOut = (char*)malloc(strlen(a)+strlen(b));
if(MessageOut==NULL)
printf("MessageOut Is Null\n");
else
printf("%x\n",(uint)MessageOut);
printf("Size of Malloc:%d\n",strlen(a)+strlen(b));
sprintf( (char*)MessageOut, "%s%s",a, b );
MessageOut[0] = 0x02;
MessageOut[1] = Data[1];
MessageOut[2] = Data[2];
MessageOut[3] = 0x03;
byte_nb = sendto(client_socket, (void *)MessageOut, strlen(a)+strlen(b), 0, (struct sockaddr *)&dist_addr, addr_len);
if (byte_nb == -1) {
printf("send error:%s\n", strerror(errno));
} else {
printf("%i bytes sent\n", byte_nb);
}
printf("%s\n",MessageOut);
if(MessageOut==NULL)
printf("MessageOut Is Null\n");
else
printf("%x\n",(uint)MessageOut);
free(MessageOut);
printf("Test\n");
}
As I said it is just a part of my code, I tried to summarize it to the part where it goes wrong.
All of this is in a while(1)-loop.
The error I got is double free or corruption (!prev)
The printf give me :
1c7eeb0
Size Of Malloc : 196
196 Bytes sent
1c7eeb0
The first loop works correctly but after a few one I got
Error: double free or corruption (!prev): 0x01c7eeb0
It does not seems to be a problem with the socket because I have the same address before and after the sendto.
Here
sprintf(a,"blablabla",strlen(a));
strlen() is passed an uninitialised a which invokes undefined behaviour.
To initially set a initialise it on definition:
char a[512] = "blablabla";
or set it right after:
char a[512];
strcpy(a, "blablabla");
(The same applies to b)
Assuming a and b were set correctly this call
sprintf( (char*)MessageOut, "%s%s",a, b );
would write 1 char beyond MessageOut bounds, as after setting the data as per a and b and additional '\0' will be put, the so called 0-terminator, that every C-"string" carries to maker is end.
To fix this adjust the related call to malloc() accordingly:
MessageOut = malloc(strlen(a) + strlen(b) + 1); /* There is no need to cast
the result fo malloc in C. */
I am having a lot of trouble with this piece of code (I am not good at pointers :P). So here is the code.
printf("\n Enter the file name along with its extensions that you want to delete:-");
scanf("%s",fileName);
deletefile_1_arg=fileName;
printf("test\n");
result_5 = deletefile_1(&deletefile_1_arg, clnt);
if (result_5 == (int *) NULL) {
clnt_perror (clnt, "call failed");
}
else
{
printf("\n File is deleted sucessfully");
goto Menu2;
}
break;
Function that is getting called is as following.
int *
deletefile_1_svc(char **argp, struct svc_req *rqstp)
{
static int result;
printf("test2\n");
printf("%s",**argp);
if(remove(**argp));
{
printf("\nFile Has Been Deleted");
result=1;
}
return &result;
}
I am getting test2 on console but. It does not print value of argp / removes that perticular file. I am not sure what I am doing wrong. Please help me.
The argp is a pointer to a pointer char, and you are trying to use it as a pointer to char, try change your code to:
printf("%s", *argp);
You would also need to change your remove call to:
remove(*argp);
I always found drawing pictures helped understand pointers. Use boxes for memory addresses and a label for the box is the variable name. If the variable is a pointer, then the contents of the box is the address of another box (draw line to the other box).
You are using pointers when you don't need to. Your "deletefile1_svc" function doesn't manipulate the value of "argp" at all so it doesn't need a pointer-to-pointer. Plus your "result" doesn't need to be returned as a pointer since it is simply a numeric value. You also don't initialize result (it might be zero) or re-initialize it (it is static so it will remember the last value assigned to it).
int
deletefile_1_svc(const char *argp, struct svc_req *rqstp)
{
int result = 0; /* Initial value => failure */
if (remove (argp) == 0)
{
result = 1; /* 1 => success */
}
return result;
}
To call the function use:
result_5 = deletefile1_svc(filename, clnt);
if (result_5 == 0)
// Failed
else
// Success
That will make the code simpler and less prone to bugs.
Short version: Is there an official/correct way to query for the size of strings like CL_PLATFORM_VENDOR?
Long version:
Looking at OpenCL functions like clGetPlatformInfo I want to find out how much space to allocate for the result. The function has this signature:
cl_int clGetPlatformInfo(cl_platform_id platform,
cl_platform_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret)
The docs say:
param_value_size
Specifies the size in bytes of memory pointed to by
param_value. This size in bytes must be greater
than or equal to size of return type specified in the
table below.
All of the return types are listed as char[]. I wanted to know how much space to reserve so I called it like this, where I pass 0 for param_value_size and NULL for param_value, hoping to get the correct size return in param_value_size_ret:
size_t size = 0;
l_success = clGetPlatformInfo(platform_id,
CL_PLATFORM_VENDOR, 0, NULL, &size);
if( l_success != CL_SUCCESS)
{
printf("Failed getting vendor name size.\n");
return -1;
}
printf("l_success = %d, size = %d\n", l_success, size);
char* vendor = NULL;
vendor = malloc(size);
if( vendor )
{
l_success = clGetPlatformInfo(platform_id,
CL_PLATFORM_VENDOR, size, vendor, &size);
if( l_success != CL_SUCCESS )
{
printf("Failed getting vendor name.\n");
return -1;
}
printf("Vendor name is '%s', length is %d\n", vendor, strlen(vendor));
} else {
printf("malloc failed.\n");
return -1;
}
It behaved as I had hoped, it return a size of 19 for the string, "NVIDIA Corporation" (size included null terminator) and strlen return 18. Is this the "right" way to query for parameter size or am I just getting lucky with my vendor's implementation? Has anyone seen this idiom fail on some vendor?
Edit: The bit that is tripping me up is this, "This size in bytes must be greater than or equal to size of return type", it seems like when I pass 0 and NULL the call should fail because that's not greater than or equal to the size of the returned value. I'm not sure why they say "return type".
Yes, it is the right way.
In the same doc you've mentioned:
If param_value is NULL, it is ignored.
And below:
Returns CL_SUCCESS if the function is executed successfully. Otherwise, it returns the following:
...
CL_INVALID_VALUE if param_name is not one of the supported values or if size in bytes specified by param_value_size is less than size of return type and param_value is not a NULL value.
So even if it is not stated explicitly, if param_value is NULL no error should be produced, so the code is supposed to work properly.
Here is a piece of code from Khronos OpenCL C++ bindings (specs). They too do it this way, and I think it counts as "official":
// Specialized GetInfoHelper for STRING_CLASS params
template <typename Func>
struct GetInfoHelper<Func, STRING_CLASS>
{
static cl_int get(Func f, cl_uint name, STRING_CLASS* param)
{
::size_t required;
cl_int err = f(name, 0, NULL, &required);
if (err != CL_SUCCESS) {
return err;
}
char* value = (char*) alloca(required);
err = f(name, required, value, NULL);
if (err != CL_SUCCESS) {
return err;
}
*param = value;
return CL_SUCCESS;
}
};
Note in the example that while asking for the value, the forth parameter has to be NULL. Otherwise some platforms answer a CL_INVALID_VALUE as return.
As the upfront query and malloc is somehow over the top, I use one large char buffer as workaround.
char vendor[10240];
l_success = clGetPlatformInfo( platform_id,
CL_PLATFORM_VENDOR, sizeof(vendor), vendor, NULL);
I am getting an error when I try to run a c file which does some basic writes to a serial port. I am trying to run it asynchronously because the writes sometimes take a long time to transfer. My original version had it running synchronously with WriteFile() commands which worked fine. I am new to using OVERLAPPED and would appreciate and input concerning it.
The error I am getting is:
Debug Assertion Failed!
<path to dbgheap.c>
Line: 1317
Expression: _CrtIsValidHeapPointer(pUserData)
when the second write function is called.
In main:
{
//initialized port (with overlapped), DBC, and timeouts
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
}
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) {
//write completed. check for errors? if so throw an exception maybe?
printf("write completed--and made it to callback function\n");
}
int write_port(HANDLE hComm,BYTE* lpBuf) {
OVERLAPPED osWrite = {0};
// Create this write operation's OVERLAPPED structure's hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// error creating overlapped event handle
return 0;
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, 1, &osWrite, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
// Write is pending.
WaitForSingleObjectEx(osWrite.hEvent, 50, TRUE); //50 ms timeout
return -1; //pending
}
}
else {
return 1; //finished
}
}
That was not the full code, sorry. I was using an array of BYTEs as well, not constants. But system("pause")'s were causing my debug assertion failed errors, and after carefully looking through my code, when the WriteFileEx() was successful, it was never setting an alert/timeout on the event in the overlapped structure, so the callback function would never get called. I fixed these problems though.
I just need help with the handling/accessing a single BYTE in a structure which is allocated when a ReadFileEx() function is called (for storing the BYTE that is read so it can be handled). I need to know how to access that BYTE storage using an offset and make the overlapped structure null. Would making the overlapped structure null be as simple as setting the handle in it to INVALID_HANDLE_VALUE?
I think you have a couple of issues:
You are passing an integer as a pointer (your compiler should warn against this or preferably refuse to compile the code):
result = write_port(outPortHandle, 128);
Compare this to the definition of write_port:
int write_port(HANDLE hComm,BYTE* lpBuf) {
The above statements doesn't match. Later on you then pass a pointer to the lpBuf pointer to the WriteFileEx function by taking the address of the BYTE* -> "&lpBuf". This will not result in what you think it will do.
Even if you fix this, you will still have potential lifetime issues whenever the write is successfully queued but won't complete within the 50 ms timeout.
When using overlapped I/O, you need to make sure that the read/write buffer and the overlapped structure remain valid until the I/O is completed, cancelled or the associated device is closed. In your code above you use a pointer to an OVERLAPPED struct that lives on the stack in your call to WriteFileEx. If WriteFileEx does not complete within 50 ms, the pending I/O will have a reference to a non-existing OVERLAPPED struct and you will (hopefully) have an access violation (or worse, silently corrupted stack data somewhere in your app).
The canonical way of handling these lifetime issues (if performance is not a big issue), is to use a custom struct that includes an OVERLAPPED struct and some storage for the data to be read/written. Allocate the struct when posting the write and deallocate the struct from the I/O completion routine. Pass the address of the included OVERLAPPED struct to WriteFileEx, and use e.g. offsetof to get the address to the custom struct from the OVERLAPPED address in the completion routine.
Also note that WriteFileEx does not actually use the hEvent member, IIRC.
EDIT: Added code sample, please note:
I haven't actually tried to compile the code, there might be typos or other problems with the code.
It's not the most efficient way of sending data (allocating/deallocating a memory block for each byte that is sent). It should be easy to improve, though.
#include <stddef.h>
#include <assert.h>
#include <windows.h>
// ...
typedef struct _MYOVERLAPPED
{
OVERLAPPED ol;
BYTE buffer;
} MYOVERLAPPED, *LPMYOVERLAPPED;
// ...
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
if (NULL == lpOverlapped)
{
assert(!"Should never happen");
return;
}
LPBYTE pOlAsBytes = (LPBYTE)lpOverlapped;
LPBYTE pMyOlAsBytes = pOlAsBytes - offsetof(MYOVERLAPPED, ol);
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)pOlAsBytes;
if ((ERROR_SUCCESS == dwErrorCode) &&
(sizeof(BYTE) == dwNumberOfBytesTransfered))
{
printf("written %uc\n", pMyOl->buffer);
}
else
{
// handle error
}
free(pMyOl);
}
int write_port(HANDLE hComm, BYTE byte) {
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)malloc(sizeof(MYOVERLAPPED));
ZeroMemory(pMyOl, sizeof(MYOVERLAPPED));
pMyOl->buffer = byte;
// Issue write.
if (!WriteFileEx(hComm, &pMyOl->buffer, sizeof(BYTE), pMyOl, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
free(pMyOl);
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
return -1; //pending
}
}
else {
free(pMyOl);
return 1; //finished
}
}
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
The lpBuf argument have to be pointers to buffers, not constants.
e.g.
char buffer;
buffer = 128;
result = write_port(outPortHandle, &buffer);
buffer = 131;
result = write_port(outPortHandle, &buffer);
What you really want to do is also pass a buffer length.
e.g.
char buffer[] = { 128, 131 };
result = write_port(outPortHandle, &buffer, sizeof(buffer));
int write_port(HANDLE hComm,BYTE* lpBuf, size_t length) {
...
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, length, &osWrite, &write_compl )) {
...