Segmentation fault when writing to comport - c

I am writing a small program to communicate with a USB to UART bridge (CP210x).
The program is fairly simple, but when ever I decrease the size of the outbound message array below (wm_size < 25) I get a segmentation fault.
The code yielding the segmentation fault looks as follows:
HANDLE prog_com_port;
prog_com_port = CreateFileA("\\\\.\\COM4",
GENERIC_READ | GENERIC_WRITE, //Request Read and Write Acess
0, //Block others from sharing Acess
NULL, //Disable Security features
OPEN_EXISTING, //Only open existing device
FILE_ATTRIBUTE_NORMAL, //Used to set atributes and flags
NULL);
//Handle to
if(prog_com_port == INVALID_HANDLE_VALUE)
{
printf("Opening COM port failed - INVALID_HANDLE_VALUE\n");
CloseHandle(prog_com_port);
return 1;
}
else
printf("COM port was opened successfully \n");
SetupCommState(prog_com_port);
Sleep(2);
#define wm_size 25
int messageLength = 2;
char W_message[wm_size] = {0x01,0x01};
long unsigned int * bytes_sent;
BOOL Status;
Status = WriteFile(prog_com_port, // Handle to the Serial port
&W_message, // Pointer to message buffer
messageLength, // No of bytes to write
bytes_sent, // Pointer to number of bytes written
NULL);
if(!Status)
{
printf("Failed to write to COM port - 0x00 \n");
CloseHandle(prog_com_port);
return 2;
}
CloseHandle(prog_com_port);
My logic tells me that setting wm_size = 2 is enough but apparently that is wrong. Can someone tell me why?
I played around with the size of wm_size and found experiemtally that 25 fixed the problem.

wm_size = 2 is enough, the problem is elsewhere: bytes_sent is a pointer that points nowhere.
Your "fix" didn't fix anything. You are experiencing undefined behaviour (which includes apparently working fine).
You want this (all comments are mine):
DWORD messageLength = 2; // use DWORD
DWORD bytes_sent; // use DWORD
char W_message[] = {0x01,0x01}; // you don't need wm_size
Status = WriteFile(prog_com_port,
W_message, // remove &, W_message decays into a pointer
messageLength,
&bytes_sent, // put &, you need a pointer here
NULL);
or even better: you don't need messageLength:
Status = WriteFile(prog_com_port,
W_message, // remove &
sizeof(W_message), // assuming W_message contains chars
&bytes_sent, // put &
NULL);
// now bytes_sent contains the number of bytes sent (hopefully 2),
// providing WriteFile succeeded (Status is TRUE)
The usage of DWORD is highly recommended, so the types of the arguments passed to to WriteFile actually match the declaration (and the documentation). Also be aware that LPDWORD in all Microsoft documentation and header files is is the
same thing as DWORD*.

Related

Why is my serial read on Windows COM port limited to 8192 bytes?

I'm trying to read 20100 bytes from my COM port in windows. The data is truncated to 8192 bytes. What gives? When I use TeraTerm, there is no truncation. My synchronous calls are:
CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
And (code snippet for non-overlapped read only)
DWORD dwEventMask, dwIncommingReadSize;
int dwSize=0;
char szBuf[10];
if(!SetCommMask((void *) fd, EV_RXCHAR)) {THIS_RTN_ERROR}
do {
if(ReadFile((void *) fd, szBuf, 1, &dwIncommingReadSize, NULL) != 0) {
if(dwIncommingReadSize > 0) {
for (k=0; k<dwIncommingReadSize; k++) {
*(line_buf+dwSize+k) = szBuf[k];
}
dwSize += dwIncommingReadSize;
}
}
else {THIS_RTN_ERROR;}
} while(dwIncommingReadSize > 0);
k = dwSize;
return(k);
This occurs immediately after a WriteFile. I iteratively call this code until I get all the data - except I only get 8192 bytes.
Have you explicitly specified 8192 as the dwInQueue parameter in the SetupComm function, or the device driver default value is 8192?
How about specifying the buffer size required by SetupComm?
SetupComm function
Initializes the communications parameters for a specified communications device.
Syntax C++
BOOL SetupComm(
HANDLE hFile,
DWORD dwInQueue,
DWORD dwOutQueue
);
Parameters
hFile
A handle to the communications device. The CreateFile function returns this handle.
dwInQueue
The recommended size of the device's internal input buffer, in bytes.
dwOutQueue
The recommended size of the device's internal output buffer, in bytes.
For .NET SerialPort, the default value is 4096, up to 2147483647 can be specified.
SerialPort.ReadBufferSize Property
Gets or sets the size of the SerialPort input buffer.
C#
[System.ComponentModel.Browsable(true)]
public int ReadBufferSize { get; set; }
Property Value
Int32
The buffer size, in bytes. The default value is 4096; the maximum value is that of a positive int, or 2147483647.
This is more of a comment than an answer. As per the accepted answer, increasing the buffer size will fix your problem 99.9% of the time.
But the the serial interface (like the socket) is just a stream of bytes. So one always has to deal with two opposing problems:
partial messages
multiple messages
Worse, you can get a complete message followed by a truncated message.
The standard way of handling this, in both Unix and Windows, is to use select. See, for example, https://beej.us/guide/bgnet/.
The resulting code is not long, but you need to know what you want to it do.
Edit: On Windows, select only works with sockets. Maybe Batch-File: Receive Data from the Serial-Port and write it into txt-File would help?

FTDI. Would need to know more details about the FT_Write() function

A question about the FT_Write() function.
FT_STATUS FT_Write (FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpdwBytesWritten)
I wonder about the lpdwBytesWritten.
When will it ever return *lpdwBytesWritten < dwBytesToWrite? Would FT_Write return other than FT_OK in that case?
And how much data can I send in one call to FT_Write? What limit has the dwBytesToWrite parameter?
I have not been able to find the answers to these questions. Have read in the FTDI Knowledgebase and also in the D2XX Programmer's Guide.
FT_Write returns status other than FT_OK on "critical" errors.
This function (as well as FT_Read) might return FT_OK and put in *lpdwBytesWritten any number from 0 (timeout) to dwBytesToWrite (transmission finished).
Intermediate values means that not all data transferred yet but transmission process can be continued.
Transmission loop might be like this:
BYTE *buf = pointer_to_data;
DWORD len = length_of_data;
FT_STATUS status;
DWORD written;
for (;;) {
status = FT_Write(handle, buf, len, &written);
if (status != FT_OK)
return status;
if (written == 0)
return -1; // or FT_OTHER_ERROR if no special timeout handling required
if (written == len)
return FT_OK;
len -= written;
buf += written;
}
See also Example 3, FT2232C Test Application (file t_titan.cpp, function DoRxTest at line 289)
dwBytesToWrite is a double word, that is 32 bits. A rather large number of bytes to write. My guess is that the function can return FT_OK even if the number of bytes written is < the number of bytes to write. It is useful to know how many bytes have been written, so that the next time you call the function, you know exactly where to set your transmit pointer in the buffer.

Virtual comport communication with windows 10 in C

im trying to communicate with a device via a virtual comport (comport to usb adapter,PL2303) on Win10. The device is an Eltek RC250 datalogger.
I have already installed an older PL2303 driver. The devicemanager recognized the device without any errors. Sending and receiving data between the device and the official software is working properly.
My problem is that after ReadFile is executed the program is doing nothing. I think ReadFile is waiting for more input from the device and therefore stucked in this function.
Trying it on a win7 System gets to the same issue.
The message which i write to the device is a valid message.
The following code shows the communication.
hComm = CreateFile("COM3", //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices /* establish connection to serial port */
if (hComm == INVALID_HANDLE_VALUE)
printf("Error in opening serial port");
else
printf("opening serial port successfully");
nNumberOfBytesToWrite = sizeof(message);
resW = WriteFile(
hComm,
message,
nNumberOfBytesToWrite,
&lpNumberOfBytesWritten,
NULL);
do
{
printf("\nread");
resR = ReadFile(
hComm,
&answer,
sizeof(lpNumberOfBytesRead),
&lpNumberOfBytesRead,
NULL);
SerialBuffer[i] = answer;
i++;
}
while (lpNumberOfBytesRead > 0);
return 0;
Please help me, i have no clue what the problem might be.
Thomas
In the ReadFile() call, third parameter should be sizeof(answer) (or possibly just 1 since it appears to be a single byte), but certainly not sizeof(lpNumberOfBytesRead). It is blocking waiting for 4 bytes (size of a DWORD) when presumably answer is a single byte?
Also if you have not explicitly set a Comm timeout, you have no idea how long ReadFile() will wait before returning 0 to exit the loop. If the timeout is indefinite then it will never exist the loop.
There are other potential issues in this call, but without seeing how the parameters are declared, it is not possible to say.

Error with pointers in recv() function

I am doing socket programming for achieve communication between different entities in my application. When sending a message, I prefix the message with the length of the message and I terminate it with \0. I have recv() in a loop as follows:
void receive(int socket)
{
int num_of_bytes_read = 0, msg_len;
char *msg = NULL, *msg_p = NULL;
char recv_buf[MAX_LEN];
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
{
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
msg_len = ntohl(msg_len);
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
systemError("Could not receive new message\n");
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
msg_p = msg;
}
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
systemError("memcpy failed in receive()\n");
msg_p += num_of_bytes_read;
}
printf("%p\n", msg); /* prints (nil) !!!!!*/
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
/* pass the a pointer to the beginning of the message skipping msg_len*/
int res = processMessage(msg + sizeof(uint32_t));
}
When I run the program I obviously get segmentation fault with the following error:
message=0x4
What is wrong with msg?? Can someone please help.
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
This is already wrong. You should test for > 0. If num_of_bytes is zero you should close the socket, and if it is -1 you should log the associated errno, e.g. with perror(), and close the socket, and in both cases stop reading.
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
As long as message points to four bytes of addressable memory this will succeed. You have provided no information on the point. The purpose remains obscure.
msg_len = ntohl(msg_len);
Here you are assuming that message pointed to four bytes that magically contain an int that has magically been set to a value you are prepared to regard as a message length. Why, I don't know. Again you have provided no information on the point.
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
This is complete nonsense. Is there a malloc() missing in there somewhere?
systemError("Could not receive new message\n");
A meaningless error message. The problem appears to be about allocating memory, but it's anybody's guess. It certainly has nothing to do with receiving messages.
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
Here you appear to think the address should be 4B long. I don't know why.
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
You are copying data to the address of msg_p. This doesn't make sense. Also, at this point num_of_bytes_read could be -1 due to your incorrect loop condition above, so anything could happen, including trying to copy 0xffffffff bytes.
systemError("memcpy failed in receive()\n");
The only way you can get to this line is if msg_p's address was null, which is impossible. Remove the & from &msg_p in the memcpy() call. Now you can only get to this systemError() call if msg_p was zero, which would already have caused a SEGV, so you still can't get to this line. A bit of preventative coding is indicated here.
msg_p += num_of_bytes_read;
Again num_of_bytes_read could be -1 at this point, sending your pointer backwards instead of forwards.
printf("%p\n", msg); /* prints (nil) !!!!!*/
Nil indicates that msg was zero.
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
0x4 again indicates that msg was zero.
You need to improve your code in the areas indicated.
msg = (char *)(sizeof(char) * msg_len)
You are setting msg to some address based on the msg_len. Not actually anything to do with where the msg resides in memory...

My first windows named pipe, not sure what is wrong

Edit: Here is the entire code, ignore Romanian comments. Also 2 or 3 names are untranslated from Romanian: http://pastebin.com/JjtayvXX
I am trying to learn the basics of OS, now I'm working with named pipes under windows and I can't tell what's wrong.
Honestly I'm working off an example a friend did, but he's just as bad as me if not worse. While hi's program works (albeit it does something else), he can't explain anything, most likely just copied from somewhere, still ... not important, what I was trying to say I'm learning from examples, and not professional ones.
Server receives a message from the client, returns max and min numbers.
Server.c:
#include "windows.h"
#include "stdio.h"
struct Msg {
int numbers[20];
int length;
};
...
int main () {
HANDLE inputPipe, outputPipe;
Msg msg;
while (true) {
inputPipe = CreateNamedPipe ("\\\\.\\pipe\\Client2Server",
PIPE_ACCESS_INBOUND,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
0, //Numb of output bytes
sizeof(Msg), // Numb of input bytes
0, // Wait forever
NULL); // Don't know how to use security
ConnectNamedPipe (inputPipe,NULL);
// Here is where the server dies
ReadFile (inputPipe, &msg,sizeof(Msg),NULL,NULL);
Now Client.c:
struct Msg {
int numbers[20];
int length;
};
int main () {
HANDLE outputPipe, inputPipe;
Msg msg;
// #misc: read data from keyboard, create msg
outputPipe = CreateFile ("\\\\.\\pipe\\Client2Server",
GENERIC_WRITE,
FILE_SHARE_READ, // * comment after code
NULL, // again, I know nothing about security attributes
CREATE_ALWAYS, // either create or overwrite
0,
NULL);
// Here is where it dies
WriteFile (outputPipe, &msg, sizeof(Msg), NULL, NULL);
I get Access violation writing location 0x00000000. No idea why.
I would like that this process only writes, and another process (server) only reads. Is FILE_SHARE_READ OK ?
Also I don't know how to mess with CreationDisposition / FlagsAndAttributes (last 2 parameters at CreateFile), are they OK ?
Edit: Added actual answer, reference to other topic, tried it myself
WriteFile()'s fourth parameter (pointer to variable that will store number of bytes) should not be null. Based on the API description, this parameter can ONLY be NULL if the fifth param, lpOverlapped, is NOT null.
See similar topic here:
Why does WriteFile crash when writing to the standard output?
Can you check/printf the return values of ReadFile() (failed if return = 0 or FALSE) and client.c CreateFile() (failed if returns INVALID_HANDLE_VALUE) to see if they succeed?
If failed, can you print the value returned by GetLastError() immediately after the call so that we can see the specific error?

Resources