段错误

1.段错误的定义

      段错误是计算机软件运行过程中可能出现的一种特殊错误情况。当程序试图访问不允许访问的内存位置,或试图以不允许的方式访问内存位置(例如尝试写入只读位置,或覆盖部分操作系统)时会发生段错误。分段是操作系统内存管理和保护的一种方法。在大多数情况下,它已经被分页所取代,但是分段的许多术语仍然被使用,“分段错误”就是一个例子。尽管分页被用作主内存管理策略,但有些操作系统在某些逻辑级别上仍然有分段。在类Unix操作系统上,访问无效内存的进程接收SIGSEGV信号。在Microsoft Windows上,访问无效内存的进程会收到状态“访问冲突”异常。段错误的原因(这篇文章非常好)

2.段错误的常见原因

2.1 使用未经初始化及或已经释放的指针地址

  • 手动释放地址:
#include <stdio.h>
#include <stdlib.h>
int main() {
	int a = 555;
	int *str = &a;
	*str = 666;
	str = NULL;
	printf("str ==%d", *str);
	system("pause");
	return 0;
}
  •  被动释放的地址:

        地址会被释放,但不一定会崩溃。

#include <stdio.h>
#include <stdlib.h>
char *getStr() {
	char str[] = "hello world";
	return str;
}
int main() {
	char *str;
	str = getStr();
	printf("str == %s",str);
	system("pause");
	return 0;
}
  • 释放无效指针
#include <stdlib.h>

int main()
{
    char *buffer = malloc(20);
    free(buffer+2);

    return 0;
}

2.2 访问受系统保护的内存地址

#include <stdio.h>
#include <stdlib.h>
int main() {
	int *str = (int *)0x20000000;
	*str = 555;
	system("pause");
	return 0;
}

2.3  写入只读的内存地址

#include <stdio.h>
#include <stdlib.h>
int main() {
	char *str = "samson";
	*str = "cool";
	printf("name is %d",str);
	system("pause");
	return 0;
}

2.3 数组越界

#include <stdio.h>
#include <stdlib.h>
int main() {
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 100; i++) {
		arr[i] = 6;
	}
	printf("%p",arr);
	system("pause");
	return 0;
}

2.4 堆栈溢出

#include <stdio.h>
#include <stdlib.h>
int main() {
	int i = 0;
	for (; i < 10000; i++) {
		int arr[999666];
	}
	system("pause");
	return 0;
}

2.5 文件操作符超出限制

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
        for (int i = 0; i < 1025; i++) {
            int fpr, fpw,res;
            int buf[100];
            fpr = open(argv[1], O_RDONLY, 0600);
            fpw = open(argv[2], O_WRONLY|O_CREAT, 0600);
            assert(fpr != -1 && fpw != -1);
            memset(buf, 0, sizeof(buf));
            while((res = read(fpr, buf, 100)) > 0) {
                write(fpw, buf, res);

            }
        }

        return 0;
}

2.6 跨线程传递指针

例一:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
int main() {
	int fd_pipe[2];
	pid_t pid = fork();
	if (pid < 0) {
		perror("fork");
	} 
	if (pid == 0) {
		sleep(2);
        char str[] = "1234455";
	    write(fd_pipe[1], str, strlen(str));
	    free(str);
		_exit(0);
	} else {
		fcntl(fd_pipe[0], F_SETFL, 0);
		while(1) {
			sleep(4);
			char *buf;
			memset(buf, 0, sizeof(buf));
            read(fd_pipe[0], buf, sizeof(buf));
			printf("buf is %s", buf);
		}
	}

	return 0;
}

 例二:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

void *thread_func(void *buff)
{
    sleep(1);
    char *buffer = (char *)buff;
    buffer[22] = 'a';
    return NULL;
}

int main()
{
    char *buffer = malloc(20);
    pthread_t th;
    pthread_create(&th, NULL, thread_func, buffer);
    pthread_join(th, NULL);
    return 0;
}

2.7 某些有特殊要求的系统调用

       例如epool_wait,正常情况下使用close关闭一个套接字后,epool会不再返回这个socket上的事件,但是如果你使用dup或dup2操作,将导致epool无法进行移除操作,此时再进行读写操作肯定是段错误的。

 

  • 57
    点赞
  • 281
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
dlopen() 函数是一个动态链接库的加载函数,它用于在运行时加载动态链接库,并返回相应的句柄。然而,当使用 dlopen() 函数时,可能会出现段错误。 段错误是一种在程序运行过程中出现的错误,它表示程序访问了无效的、未分配的、越界或者只读内存区域,导致程序崩溃。 造成 dlopen() 函数段错误的原因可能有以下几种: 1. 动态链接库不存在或路径错误:如果指定的动态链接库文件不存在或路径错误,调用 dlopen() 函数时就会出现段错误。 2. 动态链接库缺少依赖关系:当动态链接库缺少依赖的其他动态链接库时,调用 dlopen() 函数可能会出现段错误。 3. 动态链接库中存在错误:在编写动态链接库时,如果存在错误或者内存越界的操作,使用 dlopen() 加载动态链接库时就可能导致段错误。 解决 dlopen() 函数段错误的方法: 1. 确保动态链接库存在且路径正确。 2. 检查动态链接库的依赖关系,确保所有依赖的动态链接库都存在。 3. 检查动态链接库的代码,确保没有错误或者内存越界的操作。 4. 使用调试工具,如 gdb,来查找段错误的具体原因,定位问题所在。 5. 如果问题仍然存在,尝试使用其他加载动态链接库的函数,如 dlfcn.h 头文件中的 dlsym() 函数。 总之,dlopen() 函数段错误往往是由于动态链接库的问题所导致的,可以通过确认动态链接库的存在、路径和依赖关系来解决。如仍无法解决,可以通过调试工具来定位问题所在。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值