Unix 机器上 C 程序中的总线错误
我对 C 相当缺乏经验,并且遇到了一个“总线错误”,我无法理解其原因。我从未听说过 gdb,但在这个论坛上遇到了它,并尝试在我的问题程序中使用它并得到以下输出:
% gdb Proc1 GNU gdb 5.0
...
这个 GDB 是 配置为 “sparc-sun-solaris2.8”...
(没有 发现调试符号)...
(gdb)运行
启动程序: /home/0/vlcek/CSE660/Lab3/Proc1
(没有 发现调试符号)...
(没有 发现调试符号)...
(没有 发现调试符号)...
节目 接收信号 SIGSEGV,分段 过错。 main()中的0x10a64
我不知道这意味着什么,是说我的代码第 10 行有错误吗?如果是这样,我的代码中的第 10 行只是“int main()”,所以我不确定那里的问题...当我尝试运行该程序时,它说的是“总线错误”,所以我不知道该去哪里从这里走。我什至尝试在 main 之后放置一个 printf ,它不会打印字符串,只会给我一个总线错误。
下面是我的代码:
// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ssem.h"
#include "sshm.h"
// Code of Proc1
int main()
{int i, internal_reg;
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444;
/* here create and initialize all semaphores */
int sem1 = sem_create(key1, 1);
if (sem1 < 0) {
perror("sem failed");
}
int sem2 = sem_create(key2, 1);
if (sem2 < 0) {
perror("sem failed");
}
int sem3 = sem_create(key3, 1);
if (sem3 < 0) {
perror("sem failed");
}
int sem4 = sem_create(key4, 1);
if (sem4 < 0) {
perror("sem failed");
}
/* here created: shared memory array Account of size 3 */
int *Account;
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int));
if (shmid < 0) {
perror("shm failed");
}
Account[0]=10000;
Account[1]=10000;
Account[2]=10000;
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/
for (i = 0; i < 1000; i++)
{
sem_signal(sem1);
sem_signal(sem1);
sem_signal(sem1);
internal_reg = Account[0];
internal_reg = internal_reg - 200;
Account[0] = internal_reg;
/* same thing, except we're adding $100 to Account1 now... */
internal_reg = Account[1];
internal_reg = internal_reg + 200;
Account[1] = internal_reg;
if (i % 100 == 0 && i != 0) {
printf("Account 0: $%i\n", Account[0]);
printf("Account 1: $%i\n", Account[1]);
}
if (i == 300 || i == 600) {
sleep(1);
}
sem_wait(sem2);
sem_wait(sem3);
sem_wait(sem4);
}
/* Here add a code that prints contents of each account
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/
}
/*in the code above include some wait and signal operations on semaphores. Do no
t over-synchronize. */
这是 ssem 和 sshm 的文档:
/*
* ssem.c
*
* Version 1.0.0
* Date : 10 Jan 2002
*
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "ssem.h"
#define PERMS 0600
static struct sembuf op_lock[1] = {
0, -1, 0
};
static struct sembuf op_unlock[1] = {
0, 1, IPC_NOWAIT
};
int sem_create(int key,int initval)
{
int semid,i;
semid = semget((key_t)key, 1, IPC_CREAT | PERMS);
for(i=0;i<initval;i++)
semop(semid,&op_unlock[0],1);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key,0,0);
return semid;
}
int sem_wait(int semid)
{
return semop(semid,&op_lock[0],1);
}
int sem_signal(int semid)
{
return semop(semid,&op_unlock[0],1);
}
int sem_rm(int semid)
{
return semctl(semid, 0, IPC_RMID, 0);
}
/*
* sshm.c
*
* Routines for Simpler shared memory operations
* Version : 1.0.0.
* Date : 10 Jan 2002
*
*/
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include "sshm.h"
#define PERMS 0600
int shm_get(int key, void **start_ptr, int size)
{
int shmid;
shmid = shmget((key_t) key, size, PERMS | IPC_CREAT);
(*start_ptr) = (void *) shmat(shmid, (char *) 0, 0);
return shmid;
}
int shm_rm(int shmid)
{
return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
}
使用 -ggdb 标志编译 Proc1.c 并运行 gdb 后,我得到以下内容:
程序收到信号SIGSEGV, 分段错误。 main()中的0x10a64 在 Proc1.c:36
36 帐户[0]=10000
为什么这会导致分段错误?
将Account的声明更改为
int *Account = 0;
添加
printf("Account == %p\n", Account);
Account[0] = 10000之前
;运行 Proc1 时得到以下信息:
Account == ffffffff
Bus error
I'm fairly unexperienced with C and am running into a "Bus error" that I cannot understand the cause of. I had never heard of gdb but came across it on this forum and tried using it on my problem program and got the following output:
% gdb Proc1 GNU gdb 5.0
...
This GDB was
configured as
"sparc-sun-solaris2.8"...(no
debugging symbols found)...(gdb) run
Starting program:
/home/0/vlcek/CSE660/Lab3/Proc1(no
debugging symbols found)...(no
debugging symbols found)...(no
debugging symbols found)...Program
received signal SIGSEGV, Segmentation
fault. 0x10a64 in main ()
I have no idea what this means, is that saying there's an error in line 10 in my code? If so, line 10 in my code is merely "int main()" so I'm not sure the issue there... When I try running the program all it says is "Bus error" so I'm not sure where to go from here. I even tried putting a printf right after main and it doesn't print the string, only gives me a Bus error.
Below is my code:
// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ssem.h"
#include "sshm.h"
// Code of Proc1
int main()
{int i, internal_reg;
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444;
/* here create and initialize all semaphores */
int sem1 = sem_create(key1, 1);
if (sem1 < 0) {
perror("sem failed");
}
int sem2 = sem_create(key2, 1);
if (sem2 < 0) {
perror("sem failed");
}
int sem3 = sem_create(key3, 1);
if (sem3 < 0) {
perror("sem failed");
}
int sem4 = sem_create(key4, 1);
if (sem4 < 0) {
perror("sem failed");
}
/* here created: shared memory array Account of size 3 */
int *Account;
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int));
if (shmid < 0) {
perror("shm failed");
}
Account[0]=10000;
Account[1]=10000;
Account[2]=10000;
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/
for (i = 0; i < 1000; i++)
{
sem_signal(sem1);
sem_signal(sem1);
sem_signal(sem1);
internal_reg = Account[0];
internal_reg = internal_reg - 200;
Account[0] = internal_reg;
/* same thing, except we're adding $100 to Account1 now... */
internal_reg = Account[1];
internal_reg = internal_reg + 200;
Account[1] = internal_reg;
if (i % 100 == 0 && i != 0) {
printf("Account 0: $%i\n", Account[0]);
printf("Account 1: $%i\n", Account[1]);
}
if (i == 300 || i == 600) {
sleep(1);
}
sem_wait(sem2);
sem_wait(sem3);
sem_wait(sem4);
}
/* Here add a code that prints contents of each account
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/
}
/*in the code above include some wait and signal operations on semaphores. Do no
t over-synchronize. */
Here is the documentation for ssem and sshm:
/*
* ssem.c
*
* Version 1.0.0
* Date : 10 Jan 2002
*
*/
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "ssem.h"
#define PERMS 0600
static struct sembuf op_lock[1] = {
0, -1, 0
};
static struct sembuf op_unlock[1] = {
0, 1, IPC_NOWAIT
};
int sem_create(int key,int initval)
{
int semid,i;
semid = semget((key_t)key, 1, IPC_CREAT | PERMS);
for(i=0;i<initval;i++)
semop(semid,&op_unlock[0],1);
return semid;
}
int sem_open(int key)
{
int semid;
semid = semget(key,0,0);
return semid;
}
int sem_wait(int semid)
{
return semop(semid,&op_lock[0],1);
}
int sem_signal(int semid)
{
return semop(semid,&op_unlock[0],1);
}
int sem_rm(int semid)
{
return semctl(semid, 0, IPC_RMID, 0);
}
/*
* sshm.c
*
* Routines for Simpler shared memory operations
* Version : 1.0.0.
* Date : 10 Jan 2002
*
*/
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include "sshm.h"
#define PERMS 0600
int shm_get(int key, void **start_ptr, int size)
{
int shmid;
shmid = shmget((key_t) key, size, PERMS | IPC_CREAT);
(*start_ptr) = (void *) shmat(shmid, (char *) 0, 0);
return shmid;
}
int shm_rm(int shmid)
{
return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0);
}
After compiling Proc1.c with the -ggdb flag and running gdb I got the following:
Program received signal SIGSEGV,
Segmentation fault. 0x10a64 in main ()
at Proc1.c:3636 Account[0]=10000
Why would this cause a segmentation fault?
After changing the declaration of Account to
int *Account = 0;
and adding
printf("Account == %p\n", Account);
before Account[0] = 10000;
I get the following upon running Proc1:
Account == ffffffff
Bus error
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了从 gdb 获得更合理的结果,您应该使用
-ggdb
选项编译程序。然后,这会将调试信息(如行号)包含到您的程序中。您当前看到的是程序计数器的内存地址(
0x10a64
)。这对您没有多大帮助,除非您可以自己将在那里找到的汇编指令与 C 程序的一部分相关联。看起来您正在正确使用
shm_get
。我认为库设计者在将该函数命名为类似于shmget
时犯了一个可怕的错误。和我想的一样。
Account
指针以无效值(又名0xffffffff
(又名(void *)(-1)
))结束。值(void *)(-1)
通常表示某种错误,并且在shmat
的联机帮助页中明确提及。这表明库内的shmat
调用失败。以下是如何判断它是否失败的方法:现在,它失败的原因是一个有趣的谜团。显然
shmget
调用成功了。就我个人而言,我认为 System V IPC 目前基本上已被弃用,您应该避免如果可以的话使用它。
In order to get more sensible results from gdb you should compile your program with the
-ggdb
option. This will then include debugging information (like line numbers) into your program.What you are currently seeing is the memory address (
0x10a64
) of the program counter. This will not help you very much unless you can correlate the assembly instructions you find there with a part of your C program yourself.It looks like you are using
shm_get
properly. I think the library designer has made a terrible mistake in naming the function so similarly toshmget
.It's just as I thought. The
Account
pointer is ending up with an invalid value (aka0xffffffff
(aka(void *)(-1)
)) in it. The value(void *)(-1)
generally indicates some sort of error, and it is explicitly mentioned in the manpage forshmat
. This indicates that theshmat
call inside the library failed. Here is how you can tell if it failed:Now, why it failed is an interesting mystery. Apparently the
shmget
call succeeded.Personally, I think System V IPC is basically deprecated at this point and you should avoid using it if you can.
根据您的编译器和编译器选项,您可能会遇到别名问题,因为您正在转换
Account
指针的地址。这些旧式接口与现代抗锯齿规则并不同步,这意味着优化器假设Account
的值不会改变。此外,您还应该获得尽可能接近预期类型的
shm_get
参数。尝试也许像下面这样。我没有相同的架构,所以我不知道
shm_get
的确切原型,但通常对此类函数使用固定键也是一个坏主意。应该有一些函数可以返回一些密钥以在应用程序中使用。Depending on your compiler and your compiler options you might encounter an aliasing problem because your are casting the address of your
Account
pointer. These oldish interfaces are not in phase with modern antialiasing rules, meaning that the optimizer supposes that the value ofAccount
wouldn't change.Also you should get the argument for
shm_get
as close as possible to the expected type. Try perhaps something like the following.I don't have the same architecture, so I don't know the exact prototype of your
shm_get
but usually it is also a bad idea to use fixed keys for this type of functions. There should be some function that returns you some key to use in your application.