串行设备读取功能中的段错误

SegFault in read function for serial device

我正在尝试通过串口连接测量设备。我已经创建了一个成功的程序,它可以运行并执行我想要的操作,但它没有实时用户输入。 我的问题来自我正在创建的程序,我想在其中制作一个实时串行终端与设备进行交互。在这个程序中,我让用户向机器键入命令,对于某些命令,机器必须 return a 1 或 0。这就是问题所在。在实时环境中,当我在命令后读取 1 时出现段错误。

这是处理要求机器发送 1 或 0 的命令的段。

buf = malloc(1);
if (buf == NULL)
{
    perror("memory error");
    goto fail;
}
...
if (write == 0)
{
      for (i = 0; i < read_com.num; i++)
      {
            if (strcmp(buff, read_com.check[i]) == 0)
            {
                ret = write_port(fd, buff, strlen(buff));
                if (ret < 0)
                    goto fail;
                ret = read_port(fd, buf, 1);
                if (ret < 0)
                    goto fail;
                printf("Read success");
                write = 1;
                break;
            }
      }
}

这是发生段错误的读取端口函数

int read_port(int fd, char *buf, const size_t size)
{
    ssize_t r;
    size_t received;
    received = 0;
    while (received < size)
    {
        r = read(fd, buf + received, size - received);
        if (r < 0)
        {
            perror("failed to read from port");
            return -1;
        }
        if (r == 0)
        {
            break;
        }
        received += r;
    }
    return received;
}

以下所有代码:

live.c:

#include "GPIB_prof.h"
#include "serial.h"
#include "commands.h"

#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

const struct com read_com = {3, {"OPC?;PRES;\r", "OPC?;WAIT;\r", "CORRON;\r"}};
const struct com numc = {3, {"STAR", "STOP", "POIN"}};

int main(int argc, char *argv[])
{
    int fd;
    int ret;
    char *buff;
    char *buf;
    int i;
    bool write = 0;
    int fin = 0;
    char *numb;
    char *rem;
    int star;
    int stop;
    int poin;
    char *dat;
    int fc = 0;
    char *file;
    FILE *temp;
    FILE *f;

    rem = malloc(256);
    if (rem == NULL)
    {
        perror("memory error");
        goto fail;
    }
    numb = malloc(4);
    if (numb == NULL)
    {
        perror("memory error");
        goto fail;
    }
    buff = malloc(256);
    if (buff == NULL)
    {
        perror("memory error");
        goto fail;
    }
    buf = malloc(1);
    if (buf == NULL)
    {
        perror("memory error");
        goto fail;
    }
    file = malloc(5);
    if (file == NULL)
    {
        perror("memory error");
        goto fail;
    }

    if (argc < 3)
    {
        printf("Usage: %s [serial device] [baud rate]", argv[0]);
        goto fail;
    }

    fd = open_port(argv[1], atoi(argv[2]));
    if (fd < 0)
        goto fail;

    ret = GPIB_conf(fd, 0);
    if (ret < 0)
        goto fail;

    while (fin == 0)
    {
        write = 0;
        scanf("%s", buff);
        strcat(buff, "\r");
        //if (ret<0) goto fail;
        for (i = 0; i < strlen(buff); i++)
        {
            if (i < 4)
            {
                numb[i] = buff[i];
            }
            else
            {
                rem[i - 4] = buff[i];
            }
        }
        if (strcmp(numb, "OUTP") == 0)
        {
            ret = write_port(fd, buff, strlen(buff));
            if (ret < 0)
                goto fail;
            write = 1;
            ret = read_port(fd, dat, 50 * poin);
            if (ret < 0)
                goto fail;
            else
                goto data;
        }
        if (write == 0)
        {
            for (i = 0; i < read_com.num; i++)
            {
                if (strcmp(buff, read_com.check[i]) == 0)
                {
                    ret = write_port(fd, buff, strlen(buff));
                    if (ret < 0)
                        goto fail;
                    ret = read_port(fd, buf, 1);
                    if (ret < 0)
                        goto fail;
                    printf("Read success");
                    write = 1;
                    break;
                }
            }
        }
        if (write == 0)
        {
            for (i = 0; i < numc.num; i++)
            {
                if (strcmp(numb, numc.check[i]) == 0)
                {
                    ret = write_port(fd, buff, strlen(buff));
                    if (ret < 0)
                        goto fail;
                    write = 1;
                    if (strcmp(numb, "STAR") == 0)
                    {
                        star = atoi(rem);
                    }
                    else if (strcmp(numb, "STOP") == 0)
                    {
                        stop = atoi(rem);
                    }
                    else if (strcmp(numb, "POIN") == 0)
                    {
                        poin = atoi(rem);
                        dat = malloc(50 * poin);
                        if (dat == NULL)
                        {
                            perror("memory error");
                            goto fail;
                        }
                        fc++;
                    }
                    break;
                }
            }
            if (write == 0)
            {
                ret = write_port(fd, buff, strlen(buff));
                if (ret < 0)
                    goto fail;
                write = 1;
            }
        }
    }

    printf("Start freq: %d\nStop freq: %d\n", star, stop);

    free(rem);
    free(numb);
    free(buff);
    free(buf);
    free(file);
    free(dat);
    return 0;
data:
    ret = sprintf(file, "data%d", fc);
    if (ret < 0)
        goto fail;
    temp = fopen(file, "w+");
    if (temp == NULL)
    {
        perror("failed to open file");
        fclose(temp);
        goto fail;
    }
    fclose(temp);
    ret = remove(file);
    if (ret != 0)
    {
        perror("failed to remove file");
        goto fail;
    }
    f = fopen(file, "w");
    if (f == NULL)
    {
        perror("failed to open file");
        fclose(f);
        goto fail;
    }

    for (i = 0; i < (50 * poin); i++)
    {
        ret = fprintf(f, "%c", dat[i]);
        if (ret < 0)
        {
            fclose(f);
            goto fail;
        }
    }
    fclose(f);
    fin++;

fail:
    free(rem);
    free(numb);
    free(buff);
    free(buf);
    free(file);
    free(dat);
    return -1;
}

serial.c:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <termios.h>
    #include <stdint.h>
    #include <unistd.h>
    
    #include "serial.h"
    #include "GPIB_prof.h"
    
    struct termios options;
    
    int open_port(const char *dev, uint32_t baud)
    {
        int fd;
        int ret;
        char *baud_f;
        struct termios opt;
    
        baud_f = malloc(8 * sizeof(char));
        if (baud_f == NULL)
        {
            perror("memory error");
            goto fail;
        }
    
        fd = open(dev, O_RDWR, 0777);
        if (fd < 0)
        {
            perror(dev);
            goto fail;
        }
        ret = tcflush(fd, TCIOFLUSH);
        if (ret)
        {
            perror("tcgetattr failed");
            goto fail;
        }
    
        opt.c_cflag = (opt.c_cflag & ~CSIZE) | CS8;
        opt.c_cflag &= ~IGNBRK;
        opt.c_lflag = 0;
        opt.c_oflag = 0;
    
        opt.c_cc[VTIME] = 5;
        opt.c_cc[VMIN] = 1;
    
        opt.c_iflag &= ~(IXON | IXOFF | IXANY);
        opt.c_cflag |= (CLOCAL | CREAD);
        opt.c_cflag &= ~(PARENB | PARODD);
        opt.c_cflag |= 0;
        opt.c_cflag &= ~CSTOPB;
    
        ret = sprintf(baud_f, "B%d", baud);
        if (ret < 0)
        {
            perror("memory error");
            goto fail;
        }
        baud = (uintptr_t)baud_f;
        cfsetospeed(&opt, baud);
        cfsetispeed(&opt, baud);
    
        ret = tcsetattr(fd, TCSANOW, &opt);
        if (ret)
        {
            perror("tcsetarre failed");
            goto fail;
        }
    
        free(baud_f);
        return fd;
    
    fail:
        free(baud_f);
        close(fd);
        return -1;
    }
    
    int read_port(int fd, char *buf, const size_t size)
    {
        ssize_t r;
        size_t received;
        received = 0;
        while (received < size)
        {
            r = read(fd, buf + received, size - received);
            if (r < 0)
            {
                perror("failed to read from port");
                return -1;
            }
            if (r == 0)
            {
                break;
            }
            received += r;
        }
        return received;
    }
    
    int write_port(int fd, const char *buf, const size_t size)
    {
        ssize_t res;
        res = write(fd, buf, size);
        if (res != (ssize_t)size)
        {
            perror("failed to write to port");
            return -1;
        }
        usleep(size * 100);
        return 0;
    }
    
    int GPIB_conf(int fd, int profile)
    {
        int ret;
    
        switch (profile)
        {
        case 0:
            ret = def(fd);
            if (ret < 0)
                goto fail;
        }
        return 0;
    
    fail:
        return -1;
    }

serial.h

#ifndef _SERIAL_H_
#define _SERIAL_H_

#include <stdint.h>
#include <stddef.h>
#include "GPIB_prof.h"

int open_port (const char *dev, uint32_t baud);
int read_port (int fd, char *buf, size_t size);
int write_port (int fd, const char *buf, size_t size);
int GPIB_conf (int fd, int profile);

#endif

commands.h:

#ifndef _COMMANDS_H_
#define _COMMANDS_H_

struct com
{
    const int num;
    const char *check[]; 
};

#endif

GPIB_prof.c:

#include "GPIB_prof.h"
#include "serial.h"

int def(int fd)
{
    int ret;

    ret = write_port(fd, "++mode 1\r", 9);
    if (ret < 0)
        goto fail;
    ret = write_port(fd, "++addr 16\r", 10);
    if (ret < 0)
        goto fail;
    ret = write_port(fd, "++eoi 0\r", 8);
    if (ret < 0)
        goto fail;
    ret = write_port(fd, "++eot_enable 1\r", 15);
    if (ret < 0)
        goto fail;
    ret = write_port(fd, "++eot_char 13\r", 14);
    if (ret < 0)
        goto fail;
    ret = write_port(fd, "++ifc\r", 6);
    if (ret < 0)
        goto fail;
    ret = write_port(fd, "++auto 1\r", 9);
    if (ret < 0)
        goto fail;

    return 0;
fail:
    return -1;
}

GPIB_prof.h:

#ifndef _PROFILE_H_
#define _PROFILE_H_

int def(int fd);

#endif

警告:这可能不是一个完整的解决方案,因为有许多编译器警告可能未初始化的变量等

请注意,我会重命名一些变量。您有一个名为 read 的全局变量。这往往与标准 read 函数冲突。 (即)不要定义与标准 functions/variables 冲突的 functions/variables:买者自负。


这是我为(例如)cc -o orig orig.c -Wall -Wextra -O2.

获得的编译器输出

值得注意的是,许多 pointer 变量可能具有未初始化的值。这确实应该重组并修复警告,因为代码很脆弱,编译器会指出可以轻松解释运行时错误的事情。

orig.c: In function ‘GPIB_conf’:
orig.c:136:15: warning: unused parameter ‘fd’ [-Wunused-parameter]
 GPIB_conf(int fd, int profile)
           ~~~~^~
orig.c: In function ‘main’:
orig.c:217:17: warning: comparison of integer expressions of different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
   for (i = 0; i < strlen(buff); i++) {
                 ^
orig.c:325:5: warning: increment of a boolean expression [-Wbool-operation]
  fin++;
     ^~
orig.c: In function ‘open_port’:
orig.c:96:2: warning: ‘fd’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  close(fd);
  ^~~~~~~~~
orig.c: In function ‘main’:
orig.c:295:27: warning: ‘%d’ directive writing between 1 and 10 bytes into a region of size 1 [-Wformat-overflow=]
  ret = sprintf(file, "data%d", fc);
                           ^~
orig.c:295:22: note: directive argument in the range [0, 2147483647]
  ret = sprintf(file, "data%d", fc);
                      ^~~~~~~~
orig.c:295:8: note: ‘sprintf’ output between 6 and 15 bytes into a destination of size 5
  ret = sprintf(file, "data%d", fc);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~
orig.c:332:2: warning: ‘file’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  free(file);
  ^~~~~~~~~~
orig.c:333:2: warning: ‘dat’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  free(dat);
  ^~~~~~~~~
orig.c:329:2: warning: ‘numb’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  free(numb);
  ^~~~~~~~~~
orig.c:331:2: warning: ‘buf’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  free(buf);
  ^~~~~~~~~
orig.c:330:2: warning: ‘buff’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  free(buff);
  ^~~~~~~~~~
orig.c:230:32: warning: ‘poin’ may be used uninitialized in this function [-Wmaybe-uninitialized]
    ret = read_port(fd, dat, 50 * poin);
                             ~~~^~~~~~

我必须 refactor/nop 一些代码才能在 [missing] .h 文件中没有完整定义的情况下进行编译。但是,这些技巧不会解释上述警告。


#include "GPIB_prof.h"
#include "serial.h"
#include "commands.h"

#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

#define def(_fd) \
    0

struct com {
    int num;
    char *check[3];
};

const struct com read_com = { 3, {"OPC?;PRES;\r", "OPC?;WAIT;\r", "CORRON;\r"} };
const struct com numc = { 3, {"STAR", "STOP", "POIN"} };

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdint.h>
#include <unistd.h>

#include "serial.h"
#include "GPIB_prof.h"

struct termios options;

int
open_port(const char *dev, uint32_t baud)
{
    int fd;
    int ret;
    char *baud_f;
    struct termios opt;

    baud_f = malloc(8 * sizeof(char));
    if (baud_f == NULL) {
        perror("memory error");
        goto fail;
    }

    fd = open(dev, O_RDWR, 0777);
    if (fd < 0) {
        perror(dev);
        goto fail;
    }
    ret = tcflush(fd, TCIOFLUSH);
    if (ret) {
        perror("tcgetattr failed");
        goto fail;
    }

    opt.c_cflag = (opt.c_cflag & ~CSIZE) | CS8;
    opt.c_cflag &= ~IGNBRK;
    opt.c_lflag = 0;
    opt.c_oflag = 0;

    opt.c_cc[VTIME] = 5;
    opt.c_cc[VMIN] = 1;

    opt.c_iflag &= ~(IXON | IXOFF | IXANY);
    opt.c_cflag |= (CLOCAL | CREAD);
    opt.c_cflag &= ~(PARENB | PARODD);
    opt.c_cflag |= 0;
    opt.c_cflag &= ~CSTOPB;

    ret = sprintf(baud_f, "B%d", baud);
    if (ret < 0) {
        perror("memory error");
        goto fail;
    }
    baud = (uintptr_t) baud_f;
    cfsetospeed(&opt, baud);
    cfsetispeed(&opt, baud);

    ret = tcsetattr(fd, TCSANOW, &opt);
    if (ret) {
        perror("tcsetarre failed");
        goto fail;
    }

    free(baud_f);
    return fd;

  fail:
    free(baud_f);
    close(fd);
    return -1;
}

int
read_port(int fd, char *buf, const size_t size)
{
    ssize_t r;
    size_t received;

    received = 0;
    while (received < size) {
        r = read(fd, buf + received, size - received);
        if (r < 0) {
            perror("failed to read from port");
            return -1;
        }
        if (r == 0) {
            break;
        }
        received += r;
    }
    return received;
}

int
write_port(int fd, const char *buf, const size_t size)
{
    ssize_t res;

    res = write(fd, buf, size);
    if (res != (ssize_t) size) {
        perror("failed to write to port");
        return -1;
    }
    usleep(size * 100);
    return 0;
}

int
GPIB_conf(int fd, int profile)
{
    int ret;

    switch (profile) {
    case 0:
        ret = def(fd);
        if (ret < 0)
            goto fail;
    }
    return 0;

  fail:
    return -1;
}

int
main(int argc, char *argv[])
{
    int fd;
    int ret;
    char *buff;
    char *buf;
    int i;
    bool write = 0;
    bool fin = 0;
    char *numb;
    char *rem;
    int star;
    int stop;
    int poin;
    char *dat;
    int fc = 0;
    char *file;
    FILE *temp;
    FILE *f;

    rem = malloc(256);
    if (rem == NULL) {
        perror("memory error");
        goto fail;
    }
    numb = malloc(4);
    if (numb == NULL) {
        perror("memory error");
        goto fail;
    }
    buff = malloc(256);
    if (buff == NULL) {
        perror("memory error");
        goto fail;
    }
    buf = malloc(1);
    if (buf == NULL) {
        perror("memory error");
        goto fail;
    }
    file = malloc(5);
    if (file == NULL) {
        perror("memory error");
        goto fail;
    }

    if (argc < 3) {
        printf("Usage: %s [serial device] [baud rate]", argv[0]);
        goto fail;
    }

    fd = open_port(argv[1], atoi(argv[2]));
    if (fd < 0)
        goto fail;

    ret = GPIB_conf(fd, 0);
    if (ret < 0)
        goto fail;

    while (fin == 0) {
        write = 0;
        scanf("%s", buff);
        strcat(buff, "\r");
        // if (ret<0) goto fail;
        for (i = 0; i < strlen(buff); i++) {
            if (i < 4) {
                numb[i] = buff[i];
            }
            else {
                rem[i - 4] = buff[i];
            }
        }
        if (strcmp(numb, "OUTP") == 0) {
            ret = write_port(fd, buff, strlen(buff));
            if (ret < 0)
                goto fail;
            write = 1;
            ret = read_port(fd, dat, 50 * poin);
            if (ret < 0)
                goto fail;
            else
                goto data;
        }
        if (write == 0) {
            for (i = 0; i < read_com.num; i++) {
                if (strcmp(buff, read_com.check[i]) == 0) {
                    ret = write_port(fd, buff, strlen(buff));
                    if (ret < 0)
                        goto fail;
                    ret = read_port(fd, buf, 1);
                    if (ret < 0)
                        goto fail;
                    printf("Read success");
                    write = 1;
                    break;
                }
            }
        }
        if (write == 0) {
            for (i = 0; i < numc.num; i++) {
                if (strcmp(numb, numc.check[i]) == 0) {
                    ret = write_port(fd, buff, strlen(buff));
                    if (ret < 0)
                        goto fail;
                    write = 1;
                    if (strcmp(numb, "STAR") == 0) {
                        star = atoi(rem);
                    }
                    else if (strcmp(numb, "STOP") == 0) {
                        stop = atoi(rem);
                    }
                    else if (strcmp(numb, "POIN") == 0) {
                        poin = atoi(rem);
                        dat = malloc(50 * poin);
                        if (dat == NULL) {
                            perror("memory error");
                            goto fail;
                        }
                        fc++;
                    }
                    break;
                }
            }
            if (write == 0) {
                ret = write_port(fd, buff, strlen(buff));
                if (ret < 0)
                    goto fail;
                write = 1;
            }
        }
    }

    printf("Start freq: %d\nStop freq: %d\n", star, stop);

    free(rem);
    free(numb);
    free(buff);
    free(buf);
    free(file);
    free(dat);
    return 0;
  data:
    ret = sprintf(file, "data%d", fc);
    if (ret < 0)
        goto fail;
    temp = fopen(file, "w+");
    if (temp == NULL) {
        perror("failed to open file");
        fclose(temp);
        goto fail;
    }
    fclose(temp);
    ret = remove(file);
    if (ret != 0) {
        perror("failed to remove file");
        goto fail;
    }
    f = fopen(file, "w");
    if (f == NULL) {
        perror("failed to open file");
        fclose(f);
        goto fail;
    }

    for (i = 0; i < (50 * poin); i++) {
        ret = fprintf(f, "%c", dat[i]);
        if (ret < 0) {
            fclose(f);
            goto fail;
        }
    }
    fclose(f);
    fin++;

  fail:
    free(rem);
    free(numb);
    free(buff);
    free(buf);
    free(file);
    free(dat);
    return -1;
}