writing "\r" to /dev/ttyS* causes segmentation fault
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
writing "\r" to /dev/ttyS* causes segmentation fault
This is a C++ program I wrote years ago that has been chugging along fine with no problems until I recently upgraded from Slackware 13.0 to 13.1. Suddenly the process dies with a segfault. I recompiled against the new libraries and still no luck.
This is the offending bit of code:
Code:
int comm_handler::transmit(const byte* out, size_t len) {
size_t written = 0;
ssize_t count;
int fail = FALSE;
while ((written < len) && !fail) {
count = write(fd,out+written,len-written);
if (count == -1) {
syslog(LOG_ERR,"transmit failed: %s",strerror(errno));
fail = TRUE;
}
else
written += count;
}
if ((written < len) || fail)
return -1;
else
return 1;
}
When it is called with out = "ATH0\r" and len = 5, I get a segfault. When I call it with out = "ATH0 " (note trailing space), it goes through. Unfortunately I need a carriage return at the end or the modem doesn't process the command.
Can anyone explain why a carriage return would cause a segfault?
The code you presented looks fine, thus I wonder if this is really the source of the SEGV. Have you debugged the code, using gdb, so verify that all of the parameter values and class member data (ie. 'fd') are valid values?
My knowledge of gdb is limited, but I have used it to step through the function. It fails consistently on the write() function. I tried to debug it with a core dump but I my libraries don't have debugging symbols so I don't get much meaningful data. fd, as far as I can tell, is valid (at least, it's the same value returned by the "open" function earlier), as is out, and len.
I've used minicom on the serial port to communicate with the modem and that much seems to work. It's really messing with me because the only thing that's changed is a minor version of the operating system and I haven't seen anything in the changelogs that might indicate this would be an issue.
It also segfaults if out is "ATH0\n", "ATH0\r ", "\rATH0".
When you call transmit(), are you hard-coding the string for 'out', or is it a variable that you are passing? If the latter, can you show how it is declared.
Wild-ass shot in the dark: something has made your literal strings look like multi-byte characters, or the system is incorrectly expecting them to be. I've never really understood the mechanisms behind all of that hocus-pocus, but is seems reasonable that it might occur with an OS upgrade.
Now that you mention it, during the install, the setup program asked me something about UTF. I didn't understand what it was asking (and can't remember what it said), but offered a "safe option" which I took. I wonder if that had anything to do with it.
On my system, root has LANG set to en_US.UTF-8, as does the regular-user account.
I do not have a USR device to play with, much less any other device that uses the /dev/ttyS* interfaces. Thus when I attempt to send data to a device such as /dev/ttyS0, I always get an "Input/output" error.
Just trying to see whether it is the carriage return, or the carriage return in combination, or...?
What if you contrive your string data to be read from somewhere at runtime, rather than as embedded literal strings?
Did any permissions/ownership on your device pseudo-files change during the upgrade? Any changes applied in the udev system? What about the driver version for that serial port (really a stretch for something as tried & true as a standard serial port, but...?)
Do you fully initialize the serial port before using it (i.e. set all of the appropriate termios parameters); something new might be applying a setting that didn't exist before.
I may have figured something out: it may not be the transmit that is choking it but the receive, hence the carriage return causing the issue. I have the modem configured not to echo any input, so it's not going to generate any output until the carriage return. That's run in a separate handler:
Code:
void comm_handler::io_handler(int status) {
int res,x;
byte buf[255];
sigset_t newset, oldset;
sigfillset(&newset);
sigprocmask(SIG_BLOCK,&newset,&oldset);
res = read(fd,buf,255);
for (x=0; x<res;x++) {
b.push(buf[x]);
}
sigprocmask(SIG_SETMASK,&oldset,NULL);
}
I have to plead ignorance to a lot of this since I grabbed it from an online tutorial somewhere and it worked; I don't understand a lot of what it is doing. I believe that init_port() registers io_handler() as a method to be called anytime there is input available at the serial port, triggered by a SIGIO signal. The sigprocmask stuff I don't have a clue what it's doing.
b is a buffer class that I wrote to contain the input data. I'll have to go digging in there to see if maybe I screwed something up, although it has been working for years.
I will also accept suggestions for a better way to do this ie. write AT commands to a US Robotics modem.
Oh! Well, then.
It turns out I have one of those. A US Robotics Courier. Once a month I use it to dial out to the National Bureau of Standards folks to find out what time it is. I wrote a C program which does this. As long as I was doing it, I wrote (inside the source file) a 950-line comment on how to program your modem in C. Can't hurt to give it a look-see, right?
For at least the next two weeks, you can get it here.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.