🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

セグメンテーション違反

セグメンテーション違反とは、ソフトウェア実行時に発生するエラーのひとつであり、許可されていないメモリにアクセスしたときに起きます。しばしば、ポインタの不適切な使用、またはバッファオーバーフローによって起こります。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Q&A

解決済

3回答

5412閲覧

【C言語】ループの途中でSegmentation faultが出る

BOLTE

総合スコア26

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

セグメンテーション違反

セグメンテーション違反とは、ソフトウェア実行時に発生するエラーのひとつであり、許可されていないメモリにアクセスしたときに起きます。しばしば、ポインタの不適切な使用、またはバッファオーバーフローによって起こります。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

0グッド

0クリップ

投稿2021/02/21 10:02

状況と質問

Cで書かれたあるソースコード(念のため一番下に載せておきます)をコピペして動かしたいのですが、セグフォのエラーが出てしまいました。そこで最低限のものを書いて実験したところ、ループの途中でセグフォが出ていることがわかりました。

どうしてループの途中で、しかも決まった回数のときにsegmentation faultになるのでしょうか? またそれを解決する方法はありますか?

初歩的な質問かもしれないことは承知ですが、調べるとっかかりになるワードだけでも構いませんので、ご回答いただければ助かります。

コード

C

1// test2.h 2 3#include <stdio.h> 4 5struct udmabuf{ 6 char name[128]; 7 unsigned char * buf; 8};

C

1// test1.c 2 3#include <stdio.h> 4#include "test2.h" 5 6int main(){ 7 struct udmabuf intake_buf; 8 float a[32 * 32]; 9 int i, j; // 行列の添字 10 int m, n; // 行列のサイズ 11 m = n = 32; 12 for (i = 0; i < m*n; i++){ // 行列を初期化 13 a[i] = i / 2.0; 14 } 15 16 int count = 0; 17 for (i = 0; i < m; i++){ 18 for (j = 0; j < n; j++){ 19 ((float *)(intake_buf.buf))[i * n + j] = a[i * n + j]; 20 printf("%d\n", count); // 420までで止まる。なぜ?? 21 count = count + 1; 22 } 23 } 24 25 return 0; 26} 27

bash

1# 実行結果 2$ gcc test1.c && ./a.out 31 42 53 6... 7418 8419 9420 10Segmentation fault: 11

元にしている実際に動かしたいコード

c

1// dma_simple.h 2 3#include <stdio.h> 4#include <stdint.h> 5#include <stdlib.h> 6#include <unistd.h> 7#include <fcntl.h> 8#include <string.h> 9#include <sys/types.h> 10#include <sys/mman.h> 11 12#define DMA_INTAKE_DMACR (0x0000) 13#define DMA_INTAKE_DMASR (0x0004) 14#define DMA_INTAKE_SA (0x0018) 15#define DMA_INTAKE_LENGTH (0x0028) 16 17#define DMA_OUTLET_DMACR (0x0030) 18#define DMA_OUTLET_DMASR (0x0034) 19#define DMA_OUTLET_DA (0x0048) 20#define DMA_OUTLET_LENGTH (0x0058) 21 22#define DMA_CR_RS (1u<<0) 23#define DMA_CR_RESET (1u<<2) 24 25#define DMA_SR_HALTED (1u<<0) 26#define DMA_SR_IDLE (1u<<1) 27#define DMA_SR_IOC_Irq (1u<<12) 28#define DMA_SR_ERR_Irq (1u<<14) 29 30 31static inline uint32_t regs_read32 (void* addr){ 32 volatile uint32_t* regs_addr = (uint32_t*)(addr); 33 return *regs_addr; 34} 35 36static inline void regs_write32 (void* addr, uint32_t data){ 37 volatile uint32_t* regs_addr = (uint32_t*)(addr); 38 * regs_addr = data; 39} 40 41static inline void dma_reset (void* regs){ 42 regs_write32(regs+DMA_INTAKE_DMACR, DMA_CR_RESET); 43 while(regs_read32(regs+DMA_INTAKE_DMACR) & DMA_CR_RESET); // この構文謎い 44 regs_write32(regs+DMA_OUTLET_DMACR, DMA_CR_RESET); 45 while(regs_read32(regs+DMA_OUTLET_DMACR) & DMA_CR_RESET); 46} 47 48static inline void dma_setup ( 49 void* regs, 50 unsigned long src_addr, 51 unsigned long dst_addr 52 ){ 53 regs_write32(regs + DMA_OUTLET_DMACR, DMA_CR_RS); 54 regs_write32(regs + DMA_OUTLET_DA , dst_addr); 55 regs_write32(regs + DMA_INTAKE_DMACR, DMA_CR_RS); 56 regs_write32(regs + DMA_INTAKE_SA , src_addr); 57} 58 59static inline void dma_intake_start (void* regs, unsigned int xfer_size){ 60 regs_write32(regs + DMA_INTAKE_LENGTH, xfer_size); 61} 62 63static inline void dma_outlet_start (void* regs, unsigned int xfer_size){ 64 regs_write32(regs + DMA_OUTLET_LENGTH, xfer_size); 65} 66 67static inline void dma_wait_irq (void* regs){ 68 while (~regs_read32(regs + DMA_INTAKE_DMASR) & DMA_SR_IOC_Irq); 69 while (~regs_read32(regs + DMA_OUTLET_DMASR) & DMA_SR_IOC_Irq); 70} 71 72static inline void dma_clear_status (void* regs){ 73 regs_write32(regs + DMA_INTAKE_DMASR, DMA_SR_IOC_Irq | DMA_SR_ERR_Irq); 74 regs_write32(regs + DMA_OUTLET_DMASR, DMA_SR_IOC_Irq | DMA_SR_ERR_Irq); 75} 76 77struct udmabuf { 78 char name[128]; 79 int file; 80 unsigned char* buf; 81 unsigned int buf_size; 82 unsigned long phys_addr; 83 unsigned long debug_vma; 84 unsigned long sync_mode; 85}; 86 87int udmabuf_open (struct udmabuf* udmabuf, const char* name); 88int udmabuf_close (struct udmabuf* udmabuf);

c

1// dma_simple.c 2 3#include "dma_simple.h" 4 5int udmabuf_open (struct udmabuf* udmabuf, const char* name){ 6 char file_name[1024]; 7 int fd; 8 unsigned char attr[1024]; 9 10 strcpy(udmabuf -> name, name); 11 udmabuf -> file = -1; 12 13 // phys_addr 14 sprintf(file_name, "/sys/class/u-dma-buf/%s/phys_addr", name); 15 if ( 16 (fd = open(file_name, O_RDONLY)) == -1 17 ){ 18 printf("Can not open %s\n", file_name); 19 return (-1); 20 } 21 read(fd, (void*)attr, 1024); 22 sscanf(attr, "%x", &udmabuf->phys_addr); 23 close(fd); 24 25 // size 26 sprintf(file_name, "/sys/class/u-dma-buf/%s/size", name); 27 if ( 28 (fd = open(file_name, O_RDONLY)) == -1 29 ){ 30 printf("Can not open %s\n", file_name); 31 return (-1); 32 } 33 read(fd, (void *)attr, 1024); 34 sscanf(attr, "%x", &udmabuf -> buf_size); 35 close(fd); 36 37 sprintf(file_name, "/dev/%s", name); 38 if ( 39 (udmabuf -> file = open(file_name, O_RDWR | O_SYNC)) == -1 40 ){ 41 printf("Can not open %s\n", file_name); 42 return (-1); 43 } 44 45 udmabuf -> buf = mmap(NULL, udmabuf -> buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, udmabuf -> file, 0); 46 udmabuf -> debug_vma = 0; 47 udmabuf -> sync_mode = 1; 48 49 return 0; 50} 51 52int udmabuf_close(struct udmabuf* udmabuf){ 53 if (udmabuf -> file < 0) return -1; 54 55 close(udmabuf -> file); 56 udmabuf -> file = -1; 57 return 0; 58}

c

1// matrix.c 2 3#include "dma_simple.h" 4 5void main(){ 6 int uio1_fd = open("/dev/uio4", O_RDWR); 7 void *hls_regs = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uio1_fd, 0); 8 9 int uio2_fd = open("/dev/uio5", O_RDWR); 10 void *dma_regs = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uio2_fd, 0); 11 12 struct udmabuf intake_buf; 13 struct udmabuf outlet_buf; 14 if (udmabuf_open(&intake_buf, "udmabuf0") == -1) exit (1); 15 if (udmabuf_open(&outlet_buf, "udmabuf1") == -1) exit (1); 16 17 dma_reset(dma_regs); 18 regs_write32(hls_regs, 0x81); 19 20 float a[32*32]; 21 float b[32*32]; 22 float c[32*32]; 23 float cref[32*32]; 24 int i, j, t; 25 int m, n, k; 26 m = n = k = 32; 27 28 for (i = 0; i < m*n; i++){ 29 a[i] = (float) i/2.0; 30 b[i] = (float) i/3.0; 31 c[i] = (float) 0; 32 } 33 34 for (i = 0; i < m; i++){ 35 for (j = 0; j < n; j++){ 36 ((float *)(intake_buf.buf))[i*n + j] = a[i*n + j]; 37 } 38 } 39 for (i = 0; i < m; i++){ 40 for (j = 0; j < n; j++){ 41 ((float *)(intake_buf.buf))[i*n + j + m*m] = b[i*n + j]; 42 } 43 } 44 45 dma_setup(dma_regs, intake_buf.phys_addr, outlet_buf.phys_addr); 46 47 dma_outlet_start(dma_regs, m*m*4); 48 dma_intake_start(dma_regs, m*m*2*4); 49 50 dma_wait_irq(dma_regs); 51 dma_clear_status(dma_regs); 52 53 for (i = 0; i < m; i++){ 54 for (j = 0; j < n; j++){ 55 c[i*n + j] = ((float*)(outlet_buf.buf))[i*n + j]; 56 } 57 } 58 59 for (i = 0; i < m; i++){ 60 for (j = 0; j < n; j++){ 61 float sum = 0; 62 for (t = 0; t < k; t++){ 63 sum += a[i*k + t] * b[t*n + j]; 64 } 65 cref[i*n + j] = sum; 66 } 67 } 68 69 int cnt_ok = 0; 70 int cnt_ng = 0; 71 for (i = 0; i < m*m; i++){ 72 if (c[i] == cref[i]){ 73 cnt_ok++; 74 } else { 75 printf("NG: hw %f, sw %f\n", c[i], cref[i]); 76 cnt_ng++; 77 } 78 } 79 printf("OK: %d, NG: %d, Total: %d\n", cnt_ok, cnt_ng, m*m); 80 udmabuf_close(&outlet_buf); 81 udmabuf_close(&intake_buf); 82 close(uio2_fd); 83 close(uio1_fd); 84}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

またそれを解決する方法はありますか?

まず、原因については maisumakun氏から指摘がありますので割愛します。

原因を自力で切り分ける方法に関して2,3触れます。

  • コンパイラの警告の活用
    コンパイル時に、オプション -Wall-Wextra を指定しましょう。
    今回のような「未初期化」なら、コンパイラが十分新しければ警告を出してくれるので、何かマズそうだと気付けるはずです。
  • コアの活用
    コアの制限がなければ、セグメンテーションフォルト発生時、コアファイルが作成されます。
    ※ただし、実行環境にも依ります。ulimit -c unlimitedコマンドで制限解除できると思いますが。
    コンパイル時に -g を指定して、デバッガ gdb でコアを読み込ませれば、問題が発生した箇所を特定し、その時の変数の値を確認できます。
  • デバッガの活用
    コンパイル時に -g を指定しておけば、デバッガ gdb を使うことで動作を追うこともできます。
    ただこれは一口に言える内容ではないので、色々調べてみてください。

以下、CentOS7+devtoolset-9(gcc9)で試してみた例です。
gcc実行時に警告が出ていること、セグメンテーションフォルトにより core.6056 ファイルができていること、gdb でコアを読み込んで、intake_buf.buf を使ったアクセスの行で問題が出ていること、その時の i,j の値を p コマンドで出力していること、そういった流れの例になっています。

$ gcc -g -Wall -o test.exe test.c test.c: In function 'main': test.c:21:34: warning: 'intake_buf.buf' may be used uninitialized in this function [-Wmaybe-uninitialized] 21 | ((float *)(intake_buf.buf))[i * n + j] = a[i * n + j]; | ~~~~~~~~~~~^~~~~ $ ulimit -c unlimited $ ulimit -c unlimited $ ./test.exe Segmentation fault (core dumped) $ ls -l total 268 -rw-------. 1 angel angel 249856 Jun 8 10:01 core.6056 -rw-r--r--. 1 angel angel 608 Jun 8 09:48 test.c -rwxrwxr-x. 1 angel angel 19376 Jun 8 10:00 test.exe $ gdb test.exe core.6056 (略) Core was generated by `./test.exe'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x00000000004011d5 in main () at test.c:21 21 ((float *)(intake_buf.buf))[i * n + j] = a[i * n + j]; (略) (gdb) p i $1 = 0 (gdb) p j $2 = 0

投稿2021/02/21 11:44

編集2021/02/21 12:02
angel_p_57

総合スコア1681

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BOLTE

2021/02/24 08:57

ご回答ありがとうございました。gdbについては知っていたのですが、オプションを使ったりコアファイルを使うことができるのは、初めて知りました。やはり経験豊富な人に聞くとためになるなあと思いました。別の機会にまた同じようなエラーが起きたら、このコメントを読みにくることになると思います。どうもありがとうございました。
guest

0

ベストアンサー

セグメンテーションフォールトの原因はmaisumakunさんが既に述べています。
元のソースでは
udmabuf_openの中の
udmabuf -> buf = mmap(NULL, udmabuf -> buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, udmabuf -> file, 0);
でbufの初期化をしています。

bufの初期化をきちんと行えば、解決します。
以下は、その例です。
float b[32*32];を確保し、その先頭アドレスを割り当てています。

C

1#include <stdio.h> 2#include "test2.h" 3 4int main(){ 5 struct udmabuf intake_buf; 6 float a[32 * 32]; 7 float b[32 * 32]; //追加 8 int i, j; // 行列の添字 9 int m, n; // 行列のサイズ 10 m = n = 32; 11 for (i = 0; i < m*n; i++){ // 行列を初期化 12 a[i] = i / 2.0; 13 } 14 intake_buf.buf = (unsigned char *)b; //追加 15 16 int count = 0; 17 for (i = 0; i < m; i++){ 18 for (j = 0; j < n; j++){ 19 ((float *)(intake_buf.buf))[i * n + j] = a[i * n + j]; 20 printf("%d\n", count); // 420までで止まる。なぜ?? 21 count = count + 1; 22 } 23 } 24 25 return 0; 26}

投稿2021/02/21 11:20

tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BOLTE

2021/02/24 08:57

ご回答どうもありがとうございました。tatsu99さんのおかげで元々のソースコードにおかしなところがないということを確認することができました。どうやら問題はCのコードというよりも、デバイスが使えないことによりセグメンテーションフォールとが起きているよう模様でした。 具体的な解決策をいただいたので、ベストアンサーにさせていただきます。どうもありがとうございました。
guest

0

どうしてループの途中で、しかも決まった回数のときにsegmentation faultになるのでしょうか?

考えても仕方ありません。

intake_buf.bufは未初期化のポインタなので、そこへアクセスする操作は未定義の動作を引き起こします。何がどうなるか、一切の保証はありません。、

投稿2021/02/21 10:22

maisumakun

総合スコア145965

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/02/21 10:27 編集

paiza.ioで実行すると、何も表示せずに異常終了します。 https://paiza.io/projects/JFBqdym_l0Kg-9LRntFfhg?language=c …というように、「決まった回数のときにsegmentation faultになる」のもたまたまの結果でしかないのです(再起動すれば別な結果となるかもしれない、その程度のものです)。
BOLTE

2021/02/24 08:57

素早いご返答どうもありがとうございました。maisumakunさんのおかげで何がいけないのかを理解することができました。またpaiza.ioというものもあるのですね。参考になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問