質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.31%
C

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

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

2回答

816閲覧

セグメテーションエラーの原因

daiwa

総合スコア0

C

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

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

2クリップ

投稿2023/11/01 10:41

編集2023/11/01 11:54

実現したいこと

セグメテーションエラーが特定の条件で出る原因を教えて欲しい

前提

並列化に関する課題です。完全に手詰まりしてます。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4#define SIZE 1024 5#define PRINT_SIZE 8 6 7// matrix[row][col] 8int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; 9 10void init_a(int mat[SIZE][SIZE]){ 11 int row, col; 12 for (row = 0 ; row < SIZE ; row++){ 13 for (col = 0 ; col < SIZE ; col++){ 14 mat[row][col] = row+1; 15 } 16 } 17} 18void init_b(int mat[SIZE][SIZE]){ 19 int row, col; 20 for (row = 0 ; row < SIZE ; row++){ 21 for (col = 0 ; col < SIZE ; col++){ 22 mat[row][col] = row+col+1; 23 } 24 } 25} 26 27void print_matrix_sub(int mat[SIZE][SIZE], int size, int abbr, int start_row){ 28 int row, col; 29 30 for (row = start_row ; row < start_row+size ; row++){ 31 for (col = 0 ; col < size ; col++){ 32 printf("%4d ", mat[row][col]); 33 } 34 if (abbr){ 35 printf(" ... "); 36 for (col = SIZE-size ; col < SIZE ; col++){ 37 printf("%4d ", mat[row][col]); 38 } 39 40 } 41 printf("\n"); 42 } 43} 44 45void print_matrix(int mat[SIZE][SIZE]){ 46 int size, abbr; 47 48 if (SIZE > PRINT_SIZE){ 49 size = PRINT_SIZE/2; 50 abbr = 1; 51 } 52 else { 53 size = SIZE; 54 abbr = 0; 55 } 56 57 print_matrix_sub(mat, size, abbr, 0); 58 if (abbr){ 59 printf(" ...\n"); 60 print_matrix_sub(mat, size, abbr, SIZE-size); 61 } 62} 63 64void matmul(int a[SIZE][SIZE], int b[SIZE][SIZE], int c[SIZE][SIZE]){ 65 int row, col, k, s; 66 for (row = 0 ; row < SIZE ; row++){ 67 for (col = 0 ; col < SIZE ; col++){ 68 s = 0; 69 for (k = 0 ; k < SIZE ; k++){ 70 s += a[row][k]*b[k][col]; 71 } 72 c[row][col] = s; 73 } 74 } 75} 76 77int main(void){ 78 init_a(a); 79 init_b(b); 80 printf("A\n"); 81 print_matrix(a); 82 printf("\nB\n"); 83 print_matrix(b); 84 85 matmul(a, b, c); 86 printf("\nC=AB\n"); 87 print_matrix(c); 88 return 0; 89}

SIZE×SIZEのある規則に則って生成された行列A、Bに対してC=ABを求めるコードです。このコードはベースとなるもので、SIZEに定義する数字以外は手を加えません。このコードをpthread.hを用いて並列化する課題です。元のコードをベースに自分で書いたものが以下です。

gdbの結果受け修正したものをさらに下のトピックに載せます。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include<pthread.h> 4 5#define SIZE 1024 6#define PRINT_SIZE 8 7#define THREAD_NUM 2 //分割する数 8 9#include <pthread.h> 10typedef struct { 11int start, end, ans[SIZE][SIZE]; 12} arg_t;//並列化に関わる構造体 13 14 15// matrix[row][col] 16int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; 17 18 19//Aの生成を分割できるように変更 20void init_a(int mat[SIZE][SIZE],int R_start,int R_end){ 21 int row, col; 22 for (row = R_start ; row < R_end ; row++){ 23 for (col = 0 ; col < SIZE ; col++){ 24 mat[row][col] = row+1; 25 } 26 } 27} 28void init_b(int mat[SIZE][SIZE]){ 29 int row, col; 30 for (row = 0 ; row < SIZE ; row++){ 31 for (col = 0 ; col < SIZE ; col++){ 32 mat[row][col] = row+col+1; 33 } 34 } 35} 36 37void print_matrix_sub(int mat[SIZE][SIZE], int size, int abbr, int start_row){ 38 int row, col; 39 40 for (row = start_row ; row < start_row+size ; row++){ 41 for (col = 0 ; col < size ; col++){ 42 printf("%4d ", mat[row][col]); 43 } 44 if (abbr){ 45 printf(" ... "); 46 for (col = SIZE-size ; col < SIZE ; col++){ 47 printf("%4d ", mat[row][col]); 48 } 49 50 } 51 printf("\n"); 52 } 53} 54 55void print_matrix(int mat[SIZE][SIZE]){ 56 int size, abbr; 57 58 if (SIZE > PRINT_SIZE){ 59 size = PRINT_SIZE/2; 60 abbr = 1; 61 } 62 else { 63 size = SIZE; 64 abbr = 0; 65 } 66 67 print_matrix_sub(mat, size, abbr, 0); 68 if (abbr){ 69 printf(" ...\n"); 70 print_matrix_sub(mat, size, abbr, SIZE-size); 71 } 72} 73 74//不要な部分は計算しない。 75void matmul(int a[SIZE][SIZE], int b[SIZE][SIZE], int c[SIZE][SIZE],int start,int end){ 76 int row, col, k, s; 77 for (row = start ; row < end ; row++){ 78 for (col = 0 ; col < SIZE ; col++){ 79 s = 0; 80 for (k = 0 ; k < SIZE ; k++){ 81 s += a[row][k]*b[k][col]; 82 } 83 c[row][col] = s; 84 } 85 } 86} 87 88//最後にスレッド合流後にcに格納するために追加。 89void Assmat(int vessel[SIZE][SIZE],int element[SIZE][SIZE],int start,int end){ 90 int row,col; 91 for (row = start ; row < end ; row++){ 92 for (col = 0 ; col < SIZE ; col++){ 93 vessel[row][col] = element[row][col]; 94 } 95 } 96 97} 98 99//スレッドで動かす関数 100void *f(void *varg){ 101 int tmp_a[SIZE][SIZE],tmp_b[SIZE][SIZE]; 102 arg_t *arg = (arg_t *)varg; 103 init_a(tmp_a,arg->start,arg->end); 104 init_b(tmp_b); 105 matmul(tmp_a,tmp_b,arg->ans,arg->start,arg->end); 106 return NULL; 107} 108 109 110int main(void){ 111 int i; 112 init_a(a,0,SIZE); 113 init_b(b); 114 printf("A\n"); 115 print_matrix(a); 116 printf("\nB\n"); 117 print_matrix(b); 118 pthread_t th[THREAD_NUM]; 119 arg_t arg[THREAD_NUM]; 120 for(i = 0;i < THREAD_NUM;i++){ 121 arg[i].start = i*(SIZE/THREAD_NUM); 122 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 123 //printf("%d to %d\n",arg[i].start,arg[i].end);//デバッグ用の出力 124 pthread_create(&th[i],NULL,f,&arg[i]); 125 } 126 for(i = 0; i<THREAD_NUM; i++){ 127 pthread_join(th[i],NULL); 128 Assmat(c,arg[i].ans,arg[i].start,arg[i].end); 129 } 130 printf("\nC = AB\n"); 131 print_matrix(c); 132 return 0; 133} 134

SIZEやTHREAD_NUMを調整し、元のコードとの実行時間の違いを取るのが最終目標になります。
ggc -Wall -lpthreadでのコンパイルは通過してます。ただSIZEを大きくするとセグメンテーションエラーが出ます。具体的に境界値を探せていませんが、500程度なら出力でき、1000はセグメ出ます。元のコードは1024でも出力可能です。
セグメテーションエラーの原因を教えて頂きたいです。

自力でできなかった理由(コメントのおかげで解決しました!)

gdbを使って自力での特定を試みたのですが-gでコンパイルしてもディレクトリにcoreファイルが見つからない→そもそもコアダンプがでない(ただSegmentation faultのみ表示)→ulimitのコマンドが見つからないと言われるといった状態でこっちも手詰まりです…。セグメの原因追及と同時に、こちらも色々調べてる最中です。

gdbの結果受け修正

(gdb) frame 0
#0 0x0000000000400a49 in main () at matmul-th.c:108
108 init_a(a,0,SIZE);
けっきょく何がダメなのからず。ただinit_aは仕様変更する必要無いことに気づき、元のコードのものをそのまま使用。合わせて一部変更

C

1#include <stdio.h> 2#include <stdlib.h> 3#include<pthread.h> 4 5#define SIZE 1000 6#define PRINT_SIZE 8 7#define THREAD_NUM 4 8 9#include <pthread.h> 10typedef struct { 11int start, end, ans[SIZE][SIZE]; 12} arg_t; 13 14 15// matrix[row][col] 16int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; 17 18//分割なし。aを一個だけ生成して範囲指定して使う。 19void init_a(int mat[SIZE][SIZE]){ 20 int row, col; 21 for (row = 0 ; row < SIZE ; row++){ 22 for (col = 0 ; col < SIZE ; col++){ 23 mat[row][col] = row+1; 24 } 25 } 26} 27void init_b(int mat[SIZE][SIZE]){ 28 int row, col; 29 for (row = 0 ; row < SIZE ; row++){ 30 for (col = 0 ; col < SIZE ; col++){ 31 mat[row][col] = row+col+1; 32 } 33 } 34} 35 36void print_matrix_sub(int mat[SIZE][SIZE], int size, int abbr, int start_row){ 37 int row, col; 38 39 for (row = start_row ; row < start_row+size ; row++){ 40 for (col = 0 ; col < size ; col++){ 41 printf("%4d ", mat[row][col]); 42 } 43 if (abbr){ 44 printf(" ... "); 45 for (col = SIZE-size ; col < SIZE ; col++){ 46 printf("%4d ", mat[row][col]); 47 } 48 49 } 50 printf("\n"); 51 } 52} 53 54void print_matrix(int mat[SIZE][SIZE]){ 55 int size, abbr; 56 57 if (SIZE > PRINT_SIZE){ 58 size = PRINT_SIZE/2; 59 abbr = 1; 60 } 61 else { 62 size = SIZE; 63 abbr = 0; 64 } 65 66 print_matrix_sub(mat, size, abbr, 0); 67 if (abbr){ 68 printf(" ...\n"); 69 print_matrix_sub(mat, size, abbr, SIZE-size); 70 } 71} 72 73void matmul(int a[SIZE][SIZE], int b[SIZE][SIZE], int c[SIZE][SIZE],int start,int end){ 74 int row, col, k, s; 75 for (row = start ; row < end ; row++){ 76 for (col = 0 ; col < SIZE ; col++){ 77 s = 0; 78 for (k = 0 ; k < SIZE ; k++){ 79 s += a[row][k]*b[k][col]; 80 } 81 c[row][col] = s; 82 } 83 } 84} 85 86void Assmat(int vessel[SIZE][SIZE],int element[][SIZE],int start,int end){ 87 int row,col; 88 for (row = start ; row < end ; row++){ 89 for (col = 0 ; col < SIZE ; col++){ 90 vessel[row][col] = element[row][col]; 91 } 92 } 93 94} 95 96void *f(void *varg){ 97 arg_t *arg = (arg_t *)varg; 98 //tmpは不要になったので削除 99 matmul(a,b,arg->ans,arg->start,arg->end); 100 return NULL; 101} 102 103int main(void){ 104 int i; 105 init_a(a); 106 init_b(b); 107 printf("A\n"); 108 print_matrix(a); 109 printf("\nB\n"); 110 print_matrix(b); 111 pthread_t th[THREAD_NUM]; 112 arg_t arg[THREAD_NUM]; 113 for(i = 0;i < THREAD_NUM;i++){ 114 arg[i].start = i*(SIZE/THREAD_NUM); 115 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 116 //printf("%d to %d\n",arg[i].start,arg[i].end); 117 pthread_create(&th[i],NULL,f,&arg[i]); 118 } 119 for(i = 0; i<THREAD_NUM; i++){ 120 pthread_join(th[i],NULL); 121 Assmat(c,arg[i].ans,arg[i].start,arg[i].end); 122 } 123 printf("\nC = AB\n"); 124 print_matrix(c); 125 return 0; 126}

ただし状況変わらずです…。SIZEが大きいとセグメですし、やっぱりinit_a(a)が原因だと言われます。元のコードが大丈夫なのもよく分からないです…。

補足情報(FW/ツールのバージョンなど)

OSはlinuxです。ただ学校配布の物をそのまま使ってるので詳しい環境設定は分かりません。

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

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

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

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

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

melian

2023/11/01 11:10 編集

ログインシェルが bash や zsh の場合、ulimit はビルトインコマンドなので、「ulimit のコマンドが見つからない」というエラーは発生しません。ログインシェルは何をお使いでしょうか? ちなみに、 ulimit -c unlimited をコマンドライン上で実行すれば core ファイルのサイズの制限を取り払ってくれます。 ※ 追記 csh や tcsh ではビルトインコマンドの limit を使う様です。 limit coredumpsize unlimited
daiwa

2023/11/01 11:17

/bin/tcshらしいです
tmp

2023/11/01 11:36

関数fの int tmp_a[SIZE][SIZE],tmp_b[SIZE][SIZE]; がスタックを8MB近く使っているので、恐らくスタックのサイズは、8MBなのでオーバーしたのかと思います。
daiwa

2023/11/01 11:55

gdbが使えるようになりました!ありがとうございます。 その結果main内のinit_a(a,0,SIZE);が原因だというところまでたどり着けました。 ただそれでも原因が分からなかったため、コード全体を見直しわざわざaを分割して生成する意味がないと思い、関わる部分を全体的に修正しました。 ただなぜセグメなのかは分かんないままです…
退会済みユーザー

退会済みユーザー

2023/11/01 12:23 編集

tmpさんの言う通り、stackが足りないだけですよ。 具体的には元のコード101行と元のコード119行です。 元のコード119行のargはグローバル変数にしちゃうと楽です。 必要ないかもしれませんが、元のコード101行でtmp_a, tmp_bをmallocで確保するコードは int (*tmp_a)[SIZE] = malloc(SIZE * sizeof(*tmp_a)); int (*tmp_b)[SIZE] = malloc(SIZE * sizeof(*tmp_b)); と書けます。
退会済みユーザー

退会済みユーザー

2023/11/01 12:12

shellの設定はなくともcommand lineでgdbが使えれば $ gdb 実行可能ファイル > run とかで普通にデバッグできます。IDEを使うと楽です。
daiwa

2023/11/01 12:37

>>dameoさん 修正前のコードでtmp_a,tmp_bについてmallocで動的にメモリ確保したのち、使用終わり(matmulした直後)にそれぞれfreeすることでセグメ抜けました!スタック不足を指摘してくださったtmpさんもありがとうございます。課題として提出するには充分なのですが、自学のため追加で質問よろしいでしょうか? ①arg_t arg[THREAD_NUM]をmainの外に出すのと出さないのではどういった差が考えられますか? ②修正後コードのセグメとして考えられる原因はありますか?こちらはtmp_a,tmp_bをそもそも生成しません。
退会済みユーザー

退会済みユーザー

2023/11/01 12:46

ローカルに宣言された変数は基本的にスタックから確保されます。スタックはプロセスやスレッドごとに使えるサイズに制限があり、しかもあまり大きくないので、まとまった量を動的に確保するときはすぐにスタックがオーバーフローします。gccなどではこれをなるべく早く検出させるために、意図的に関数呼び出し時にセグメンテーションフォルトが起きるようなコードが生成されています。スタックがオーバーフローする場合は、ヒープからmallocで確保するか、ローカル変数をstaticに確保するか、グローバル変数にしてスタックの消費を削ります。 ①グローバル変数になるのでスタックの消費が抑えられます。 ②現象を見てないので分かりません。正確に報告してください。
melian

2023/11/01 16:21 編集

> ①arg_t arg[THREAD_NUM]をmainの外に出すのと出さないのではどういった差が考えられますか? main 関数内にあると、arg はスタックに確保されます。Linux の場合、スタックのサイズはデフォルトで 8M bytes なので、結果的に stack overflow が発生します。(gcc の AddressSanitizer で検出可能) グローバル変数化や malloc(3) でヒープ領域に確保する以外に、先の limit を使用してスタックサイズを拡張する方法があります。具体的にはコマンドライン(tcsh)で以下を実行すると、スタックサイズが 40 MB になります。 limit stacksize 41960 この状態でプログラムを実行すると結果が表示されて正常終了します。
daiwa

2023/11/02 06:54

回答ありがとうございます。
guest

回答2

0

原因

スタックのオーバーフローです。

調査

gdbを使った調査

問題のコードをgdbで動作させると、以下のようになります。

text

1root:/src# gcc -g -pthread -Wall hoge.c -o hoge 2root:/src# gdb hoge 3GNU gdb (Debian 13.1-3) 13.1 4... 5(gdb) run 6run 7Starting program: /src/hoge 8warning: Error disabling address space randomization: Operation not permitted 9[Thread debugging using libthread_db enabled] 10Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 11 12Program received signal SIGSEGV, Segmentation fault. 130x00000000004014ef in main () at hoge.c:105 14105 init_a(a); 15(gdb) list 16100 return NULL; 17101 } 18102 19103 int main(void){ 20104 int i; 21105 init_a(a); 22106 init_b(b); 23107 printf("A\n"); 24108 print_matrix(a); 25109 printf("\nB\n"); 26(gdb) disassemble 27Dump of assembler code for function main: 28 0x00000000004014df <+0>: push %rbp 29 0x00000000004014e0 <+1>: mov %rsp,%rbp 30 0x00000000004014e3 <+4>: sub $0xf42450,%rsp 31 0x00000000004014ea <+11>: mov $0x404060,%edi 32=> 0x00000000004014ef <+16>: call 0x401166 <init_a> 33... 34(gdb)

セグメンテーションフォルトを起こして落ちているのが分かります。アセンブラからはcall命令で関数init_a()に飛ぼうとしてるところで起きています。この命令はスタックに現在のripレジスタの値を積んでからジャンプするので、現在のスタック(rspレジスタ)が領域外を指していることが予想されます。

text

1(gdb) info proc mappings 2process 276 3Mapped address spaces: 4 5 Start Addr End Addr Size Offset Perms objfile 6 0x400000 0x401000 0x1000 0x0 r--p /src/hoge 7... 8 0x7ffe21673000 0x7ffe21694000 0x21000 0x0 rw-p [stack] 9... 10(gdb) info registers 11... 12rsp 0x7ffe2074fbd0 0x7ffe2074fbd0 13... 14rip 0x4014ef 0x4014ef <main+16> 15... 16(gdb)

案の定、スタックに割り当てられている領域0x7ffe21673000~0x7ffe21694000を下回る0x7ffe2074fbd0にrspが下がっています。この領域には何も割当がないため、セグメンテーションフォルトが発生していました。

つまり、スタックがオーバーフローしていたということです。

gccのオプションを使った調査

スタックオーバーフローやメモリ破壊、リークが疑わしい場合、gccのオプションを使うことで効率的にチェックすることができます。-fsanitize=address-fsanitize=leakです。詳細はググってください。
これらを使用すると、アセンブラコードやレジスタを調べなくても現象を追うことができます。

text

1root:/src# gcc -g -pthread -Wall -fsanitize=address -fsanitize=leak hoge.c -o hoge 2root:/src# ./hoge 3AddressSanitizer:DEADLYSIGNAL 4================================================================= 5==284==ERROR: AddressSanitizer: stack-overflow on address 0x7ffff33bde00 (pc 0x00000040185a bp 0x7ffff4300390 sp 0x7ffff33bddf0 T0) 6 #0 0x40185a in main /src/hoge.c:103 7 #1 0x7f6a5051a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 8 #2 0x7f6a5051a284 in __libc_start_main_impl ../csu/libc-start.c:360 9 #3 0x401110 in _start (/src/hoge+0x401110) 10 11SUMMARY: AddressSanitizer: stack-overflow /src/hoge.c:103 in main 12==284==ABORTING 13root:/src#

ちゃんとスタックオーバーフローを検出してくれています。

あとはmain関数内で大きなローカル変数を探せば終わりです。コードを読めば一目瞭然で大きいのはargsですね。

対策

グローバル変数へ

diff

1--- a/hoge.c 2+++ b/hoge.c 3@@ -100,6 +100,8 @@ void *f(void *varg){ 4 return NULL; 5 } 6 7+arg_t arg[THREAD_NUM]; 8+ 9 int main(void){ 10 int i; 11 init_a(a); 12@@ -109,7 +111,6 @@ int main(void){ 13 printf("\nB\n"); 14 print_matrix(b); 15 pthread_t th[THREAD_NUM]; 16- arg_t arg[THREAD_NUM]; 17 for(i = 0;i < THREAD_NUM;i++){ 18 arg[i].start = i*(SIZE/THREAD_NUM); 19 arg[i].end = (i+1)*(SIZE/THREAD_NUM);

ローカル変数のまま静的確保

diff

1--- a/hoge.c 2+++ b/hoge.c 3@@ -109,7 +109,7 @@ int main(void){ 4 printf("\nB\n"); 5 print_matrix(b); 6 pthread_t th[THREAD_NUM]; 7- arg_t arg[THREAD_NUM]; 8+ static arg_t arg[THREAD_NUM]; 9 for(i = 0;i < THREAD_NUM;i++){ 10 arg[i].start = i*(SIZE/THREAD_NUM); 11 arg[i].end = (i+1)*(SIZE/THREAD_NUM);

ヒープから動的に確保

diff

1--- a/hoge.c 2+++ b/hoge.c 3@@ -109,7 +109,7 @@ int main(void){ 4 printf("\nB\n"); 5 print_matrix(b); 6 pthread_t th[THREAD_NUM]; 7- arg_t arg[THREAD_NUM]; 8+ arg_t *arg = malloc(THREAD_NUM * sizeof(*arg)); 9 for(i = 0;i < THREAD_NUM;i++){ 10 arg[i].start = i*(SIZE/THREAD_NUM); 11 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 12@@ -122,5 +122,6 @@ int main(void){ 13 } 14 printf("\nC = AB\n"); 15 print_matrix(c); 16+ free(arg); 17 return 0; 18 }

いずれにしても、問題は発生しなくなります。

スタックサイズの確認方法・調整方法

Linuxではスタックサイズは、基本的にシェルが管理しています。当該シェルでスタックサイズを確認してください。
ただし、ここで決められるのはプロセスのスタックサイズだけで、スレッドごとに割り当てられるスタックサイズはまた別にあり、シェルの管理外なので注意してください。Linuxのpthreadに限定すれば、このサイズはプログラム側で決められるもので、amd64だとデフォルトでは2MBになります。

いずれにしてもこれらのサイズは環境依存なので、なるべく大きなサイズのデータをローカルで確保しないように心掛ける方が賢明です。

確認用のコード

要docker&bash

bash

1cat >hoge.c <<EOF 2#include <stdio.h> 3#include <stdlib.h> 4#include<pthread.h> 5 6#define SIZE 1000 7#define PRINT_SIZE 8 8#define THREAD_NUM 4 9 10#include <pthread.h> 11typedef struct { 12int start, end, ans[SIZE][SIZE]; 13} arg_t; 14 15 16// matrix[row][col] 17int a[SIZE][SIZE], b[SIZE][SIZE], c[SIZE][SIZE]; 18 19//分割なし。aを一個だけ生成して範囲指定して使う。 20void init_a(int mat[SIZE][SIZE]){ 21 int row, col; 22 for (row = 0 ; row < SIZE ; row++){ 23 for (col = 0 ; col < SIZE ; col++){ 24 mat[row][col] = row+1; 25 } 26 } 27} 28void init_b(int mat[SIZE][SIZE]){ 29 int row, col; 30 for (row = 0 ; row < SIZE ; row++){ 31 for (col = 0 ; col < SIZE ; col++){ 32 mat[row][col] = row+col+1; 33 } 34 } 35} 36 37void print_matrix_sub(int mat[SIZE][SIZE], int size, int abbr, int start_row){ 38 int row, col; 39 40 for (row = start_row ; row < start_row+size ; row++){ 41 for (col = 0 ; col < size ; col++){ 42 printf("%4d ", mat[row][col]); 43 } 44 if (abbr){ 45 printf(" ... "); 46 for (col = SIZE-size ; col < SIZE ; col++){ 47 printf("%4d ", mat[row][col]); 48 } 49 50 } 51 printf("\n"); 52 } 53} 54 55void print_matrix(int mat[SIZE][SIZE]){ 56 int size, abbr; 57 58 if (SIZE > PRINT_SIZE){ 59 size = PRINT_SIZE/2; 60 abbr = 1; 61 } 62 else { 63 size = SIZE; 64 abbr = 0; 65 } 66 67 print_matrix_sub(mat, size, abbr, 0); 68 if (abbr){ 69 printf(" ...\n"); 70 print_matrix_sub(mat, size, abbr, SIZE-size); 71 } 72} 73 74void matmul(int a[SIZE][SIZE], int b[SIZE][SIZE], int c[SIZE][SIZE],int start,int end){ 75 int row, col, k, s; 76 for (row = start ; row < end ; row++){ 77 for (col = 0 ; col < SIZE ; col++){ 78 s = 0; 79 for (k = 0 ; k < SIZE ; k++){ 80 s += a[row][k]*b[k][col]; 81 } 82 c[row][col] = s; 83 } 84 } 85} 86 87void Assmat(int vessel[SIZE][SIZE],int element[][SIZE],int start,int end){ 88 int row,col; 89 for (row = start ; row < end ; row++){ 90 for (col = 0 ; col < SIZE ; col++){ 91 vessel[row][col] = element[row][col]; 92 } 93 } 94 95} 96 97void *f(void *varg){ 98 arg_t *arg = (arg_t *)varg; 99 //tmpは不要になったので削除 100 matmul(a,b,arg->ans,arg->start,arg->end); 101 return NULL; 102} 103 104int main(void){ 105 int i; 106 init_a(a); 107 init_b(b); 108 printf("A\n"); 109 print_matrix(a); 110 printf("\nB\n"); 111 print_matrix(b); 112 pthread_t th[THREAD_NUM]; 113 arg_t arg[THREAD_NUM]; 114 for(i = 0;i < THREAD_NUM;i++){ 115 arg[i].start = i*(SIZE/THREAD_NUM); 116 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 117 //printf("%d to %d\n",arg[i].start,arg[i].end); 118 pthread_create(&th[i],NULL,f,&arg[i]); 119 } 120 for(i = 0; i<THREAD_NUM; i++){ 121 pthread_join(th[i],NULL); 122 Assmat(c,arg[i].ans,arg[i].start,arg[i].end); 123 } 124 printf("\nC = AB\n"); 125 print_matrix(c); 126 return 0; 127} 128EOF 129cat >global.diff <<EOF 130diff --git a/hoge.c b/hoge.c 131index 6df35aa..45d4e2b 100644 132--- a/hoge.c 133+++ b/hoge.c 134@@ -100,6 +100,8 @@ void *f(void *varg){ 135 return NULL; 136 } 137 138+arg_t arg[THREAD_NUM]; 139+ 140 int main(void){ 141 int i; 142 init_a(a); 143@@ -109,7 +111,6 @@ int main(void){ 144 printf("\\nB\\n"); 145 print_matrix(b); 146 pthread_t th[THREAD_NUM]; 147- arg_t arg[THREAD_NUM]; 148 for(i = 0;i < THREAD_NUM;i++){ 149 arg[i].start = i*(SIZE/THREAD_NUM); 150 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 151EOF 152cat >static.diff <<EOF 153diff --git a/hoge.c b/hoge.c 154index 6df35aa..f68cf0f 100644 155--- a/hoge.c 156+++ b/hoge.c 157@@ -109,7 +109,7 @@ int main(void){ 158 printf("\\nB\\n"); 159 print_matrix(b); 160 pthread_t th[THREAD_NUM]; 161- arg_t arg[THREAD_NUM]; 162+ static arg_t arg[THREAD_NUM]; 163 for(i = 0;i < THREAD_NUM;i++){ 164 arg[i].start = i*(SIZE/THREAD_NUM); 165 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 166EOF 167cat >malloc.diff <<EOF 168diff --git a/hoge.c b/hoge.c 169index 6df35aa..8712646 100644 170--- a/hoge.c 171+++ b/hoge.c 172@@ -109,7 +109,7 @@ int main(void){ 173 printf("\\nB\\n"); 174 print_matrix(b); 175 pthread_t th[THREAD_NUM]; 176- arg_t arg[THREAD_NUM]; 177+ arg_t *arg = malloc(THREAD_NUM * sizeof(*arg)); 178 for(i = 0;i < THREAD_NUM;i++){ 179 arg[i].start = i*(SIZE/THREAD_NUM); 180 arg[i].end = (i+1)*(SIZE/THREAD_NUM); 181@@ -122,5 +122,6 @@ int main(void){ 182 } 183 printf("\nC = AB\n"); 184 print_matrix(c); 185+ free(arg); 186 return 0; 187 } 188EOF 189docker run -i --rm -v `pwd`:/src/ gcc:12 bash <<EOF 190apt-get update 191apt-get install -y gdb 192cd src 193gcc -g -pthread -Wall hoge.c -o hoge 194gdb ./hoge 195run 196list 197disassemble 198info proc mappings 199info registers 200continue 201quit 202gcc -g -pthread -Wall -fsanitize=address -fsanitize=leak hoge.c -o hoge 203./hoge 204patch -p1 <global.diff 205gcc -g -pthread -Wall -fsanitize=address -fsanitize=leak hoge.c -o hoge 206./hoge 207patch -p1 -R <global.diff 208patch -p1 <static.diff 209gcc -g -pthread -Wall -fsanitize=address -fsanitize=leak hoge.c -o hoge 210./hoge 211patch -p1 -R <static.diff 212patch -p1 <malloc.diff 213gcc -g -pthread -Wall -fsanitize=address -fsanitize=leak hoge.c -o hoge 214./hoge 215patch -p1 -R <malloc.diff 216exit 217EOF

投稿2023/11/01 19:32

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

daiwa

2023/11/02 07:03

gdbの解説から、解析結果から分かる原因とその回避方法までご丁寧にありがとうございます。 スタックの大きさを意識することが無かったので見解が広がりました。
guest

0

C言語のプログラムでは、実行時のエラーチェックは全く行われません。
たとえアクセス違反があろうと、いかなるバグがあろうとそれで暴走しようが、それは全くチェックされず実行を続けます

では、なぜ実行時にエラーが出るのか、というと、どこかでアクセス違反があるコードを実行したために、その後のコード実行において何らかの動作異常を、OSのカーネルが検出したために、OSの動作異常として表に出てきます。
C言語のコードの異常、ではなくて、OSの動作異常というところがポイントです。

ってことで、いくらGDBでステップ実行してこのタイミングでエラーが出た、といってもたまたまこのタイミングでエラーが顕在化した、というだけでその場所で異常が起こったとは限りません。

ってことで、いくらデバッガを使ったところで、エラーの場所を特定することはできない、ってことに注意しましょう

投稿2023/11/01 12:05

y_waiwai

総合スコア88163

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

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

daiwa

2023/11/02 06:56

デバッガ―の仕様について大きな誤解があったみたいです。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問