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

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

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

charは文字データ型を指します。一文字分の文字コードの格納を想定としている型です。

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Q&A

解決済

1回答

5996閲覧

C言語 プログラムを実行した際に「zsh: abort ./a.out」と出てしまいます

退会済みユーザー

退会済みユーザー

総合スコア0

char

charは文字データ型を指します。一文字分の文字コードの格納を想定としている型です。

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

0グッド

1クリップ

投稿2020/11/18 15:13

プログラムの概要

c言語で、ファイルから読み取ったデータをもとにサーバーが動いているかどうかを確認するプログラムを作成しています。

読み取るファイル
20201019133124,10.20.30.1/16,2
20201019133125,10.20.30.2/16,1
20201019133134,192.168.1.1/24,10
20201019133135,192.168.1.2/24,5
20201019133224,10.20.30.1/16,522
20201019133225,10.20.30.2/16,1
20201019133234,192.168.1.1/24,8
20201019133235,192.168.1.2/24,15
20201019133324,10.20.30.1/16,-
20201019133325,10.20.30.2/16,2
20201019133334,10.20.30.1/16,-
20201019134040,10.20.30.1/16,5
20201019134440,10.20.30.1/16,-
20201019134450,10.20.30.1/16,5
20201019134460,192.168.1.1/24,-
20201019135050,192.168.1.2/24,15

左から<確認日時>,<サーバアドレス>,<応答結果>という並びになっています。
応答結果で-が返ってきた場合にサーバー故障とみなすようになっています。

発生している問題・エラーメッセージ

サーバー10.20.30.1/16が故障状態です 故障期間は1秒です サーバー10.20.30.1/16が故障状態です 故障期間は7分6秒です サーバー10.20.30.1/16が故障状態です 故障期間は10秒です サーバー192.168.1.1/24が故障状態です 故障期間は5分90秒です zsh: abort ./a.out

該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#define N 50 6 7struct LOG{ 8 long time; 9 char server_name[N]; 10 char result[N]; 11}; 12 13void printTime(long kikan){ 14 char kikan2[14]; 15 sprintf(kikan2,"%ld",kikan); 16 int len = strlen(kikan2); 17 long sec,min,hour,day,month,year; 18 year = kikan/10000000000; 19 month = (kikan/1000000)%100; 20 day = (kikan/10000)%100; 21 hour = (kikan/100)%100; 22 min = kikan/100; 23 sec = kikan%100; 24 25 26 if(len<=2){ 27 printf("故障期間は%ld秒です\n",sec); 28 }else if(len<=4){ 29 printf("故障期間は%ld分%ld秒です\n",min,sec); 30 }else if(len<=6){ 31 printf("故障期間は%ld時%ld分%ld秒です\n",hour,min,sec); 32 }else if(len<=8){ 33 printf("故障期間は%ld日%ld時%ld分%ld秒です\n",day,hour,min,sec); 34 }else if(len<=10){ 35 printf("故障期間は%ld月%ld日%ld時%ld分%ld秒です\n",month,day,hour,min,sec); 36 }else if(len<=14){ 37 printf("故障期間は%ld年%ld月%ld日%ld時%ld分%ld秒です\n",year,month,day,hour,min,sec); 38 } 39} 40 41 42 43int main(){ 44 FILE *fp; 45 struct LOG log[10]; 46 47 char s[N][N],*cp,handan_name[N]; 48 49 50 const char *sikiri=","; 51 long handan_time=0,kikan; 52 int i = 0,j = 0,len=0,ct=0; //ctによって一度のエラーにつき一回のみと判断 53 54 55 fp = fopen("server.txt","r"); 56 57 while(fgets(s[i],N,fp)!=NULL){ 58 cp = strtok(s[i],sikiri); 59 log[i].time=atol(cp);//ここで時間を挿入、文字列から数に変換 60 int c=0; 61 while(cp!=NULL){ 62 cp = strtok(NULL,sikiri); 63 if(cp!=NULL&&c==0){ 64 strcpy(log[i].server_name,cp); //ここでサーバーの名前を挿入 65 c++; 66 67 68 if(strcmp(&handan_name[len-1],"1")&& 69 strncmp(handan_name,log[i].server_name,8)==0&&ct==1){ //if(故障していたら)ここでサーバーの名前がかぶってないか判断 70 kikan=log[i].time-handan_time; 71 printTime(kikan); 72 ct--; 73 }else if(strcmp(&handan_name[len-1],"2")&& 74 strncmp(handan_name,log[i].server_name,9)==0&&ct==1){ 75 kikan=log[i].time-handan_time; 76 printTime(kikan); 77 ct--; 78 } 79 } 80 81 if(cp!=NULL&&c==1){ 82 strcpy(log[i].result,cp);//ここで結果を挿入 83 if(strncmp(log[i].result,"-",1)==0&&ct==0){ 84 printf("サーバー%sが故障状態です\n",log[i].server_name);//サーバーが故障しているか判断 85 len=strlen(log[i].server_name); 86 handan_time = log[i].time; 87 strcpy(handan_name,log[i].server_name); 88 ct++; 89 } 90 } 91 } 92 i++; 93 } 94 95 96 fclose(fp); 97 return 0; 98}

試したこと

自分なりに調べたところ、zsh: abort ./a.outというエラーはメモリ解放に関するエラーだということが書いてあったのですが、例は全てmallocでのメモリ確保が前提となっており、char *cpをmallocでメモリ確保しfreeしてみる、などを行いましたが何も変わりませんでした。

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

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

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

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

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

guest

回答1

0

ベストアンサー

こういうときはUndefined Behavior Sanitiserを使ってみましょう。
https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html

提示のプログラムを(C++としてコンパイルする必要があるのでソースコードをmain.cppとした)

clang++ main.cpp -Wall -Wextra -pedantic -std=c++17 -g -fsanitize=undefined

のようにしてコンパイルして実行すると

bash

1$./a.out 2main.cpp:68:16: runtime error: index -1 out of bounds for type 'char [50]' 3SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:68:16 in 4main.cpp:73:22: runtime error: index -1 out of bounds for type 'char [50]' 5SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:73:22 in 6サーバー10.20.30.1/16が故障状態です 7故障期間は1秒です 8main.cpp:59:5: runtime error: index 10 out of bounds for type 'struct LOG [10]' 9SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:59:5 in 10main.cpp:64:12: runtime error: index 10 out of bounds for type 'struct LOG [10]' 11SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:64:12 in 12main.cpp:69:28: runtime error: index 10 out of bounds for type 'struct LOG [10]' 13SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:69:28 in 14main.cpp:74:30: runtime error: index 10 out of bounds for type 'struct LOG [10]' 15SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:74:30 in 16main.cpp:82:12: runtime error: index 10 out of bounds for type 'struct LOG [10]' 17SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:82:12 in 18main.cpp:83:16: runtime error: index 10 out of bounds for type 'struct LOG [10]' 19SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:83:16 in 20main.cpp:84:54: runtime error: index 10 out of bounds for type 'struct LOG [10]' 21SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:84:54 in 22サーバー10.20.30.1/16が故障状態です 23main.cpp:85:18: runtime error: index 10 out of bounds for type 'struct LOG [10]' 24SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:85:18 in 25main.cpp:86:21: runtime error: index 10 out of bounds for type 'struct LOG [10]' 26SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:86:21 in 27main.cpp:87:26: runtime error: index 10 out of bounds for type 'struct LOG [10]' 28SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:87:26 in 29UndefinedBehaviorSanitizer:DEADLYSIGNAL 30==9562==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address (pc 0x7ff102159bab bp 0x7ffd51fcdd26 sp 0x7ffd51fcd790 T9562) 31==9562==The signal is caused by a READ memory access. 32==9562==Hint: this fault was caused by a dereference of a high value address (see register values below). Dissassemble the provided pc to learn which register was used. 33UndefinedBehaviorSanitizer:DEADLYSIGNAL 34UndefinedBehaviorSanitizer: nested bug in the same thread, aborting.

のように結果が得られます。つまり、全般に配列へのアクセスに問題があります。

多少書き直してデバッグログも仕込んでみました

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#define N 50 6 7struct LOG { 8 long time; 9 char server_name[N]; 10 char result[N]; 11}; 12 13void printTime(long kikan) { 14 char kikan2[14]; 15 sprintf(kikan2, "%ld", kikan); 16 int len = strlen(kikan2); 17 long sec, min, hour, day, month, year; 18 year = kikan / 10000000000; 19 month = (kikan / 1000000) % 100; 20 day = (kikan / 10000) % 100; 21 hour = (kikan / 100) % 100; 22 min = kikan / 100; 23 sec = kikan % 100; 24 25 if (len <= 2) { 26 printf("故障期間は%ld秒です\n", sec); 27 } else if (len <= 4) { 28 printf("故障期間は%ld分%ld秒です\n", min, sec); 29 } else if (len <= 6) { 30 printf("故障期間は%ld時%ld分%ld秒です\n", hour, min, sec); 31 } else if (len <= 8) { 32 printf("故障期間は%ld日%ld時%ld分%ld秒です\n", day, hour, min, sec); 33 } else if (len <= 10) { 34 printf("故障期間は%ld月%ld日%ld時%ld分%ld秒です\n", month, day, hour, min, sec); 35 } else if (len <= 14) { 36 printf("故障期間は%ld年%ld月%ld日%ld時%ld分%ld秒です\n", year, month, day, hour, min, sec); 37 } 38} 39 40int main() { 41 FILE *fp; 42 struct LOG log[30]; 43 44 char s[N][N], *cp, handan_name[N]; 45 46 const char *sikiri = ","; 47 long handan_time = 0, kikan; 48 int i = 0, len = 0, ct = 0; // ctによって一度のエラーにつき一回のみと判断 49 50 fp = fopen("server.txt", "r"); 51 52 while (fgets(s[i], N, fp) != NULL) { 53 printf("Debug(line %d): i=%d\n", __LINE__, i); 54 cp = strtok(s[i], sikiri); 55 log[i].time = atol(cp); //ここで時間を挿入、文字列から数に変換 56 int c = 0; 57 while (NULL != (cp = strtok(NULL, sikiri))) { 58 if (c == 0) { 59 strcpy(log[i].server_name, cp); //ここでサーバーの名前を挿入 60 c++; 61 62 if (strcmp(&handan_name[len - 1], "1") && strncmp(handan_name, log[i].server_name, 8) == 0 && 63 ct == 1) { // if(故障していたら)ここでサーバーの名前がかぶってないか判断 64 kikan = log[i].time - handan_time; 65 printTime(kikan); 66 ct--; 67 } else if (strcmp(&handan_name[len - 1], "2") && strncmp(handan_name, log[i].server_name, 9) == 0 && ct == 1) { 68 kikan = log[i].time - handan_time; 69 printTime(kikan); 70 ct--; 71 } 72 } 73 74 if (cp != NULL && c == 1) { 75 strcpy(log[i].result, cp); //ここで結果を挿入 76 if (strncmp(log[i].result, "-", 1) == 0 && ct == 0) { 77 printf("サーバー%sが故障状態です\n", log[i].server_name); //サーバーが故障しているか判断 78 len = strlen(log[i].server_name); 79 handan_time = log[i].time; 80 strcpy(handan_name, log[i].server_name); 81 ct++; 82 } 83 } 84 } 85 i++; 86 } 87 88 fclose(fp); 89 return 0; 90}

同様に実行すると

Debug(line 53): i=0 main.cpp:62:21: runtime error: index -1 out of bounds for type 'char [50]' SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:62:21 in main.cpp:67:28: runtime error: index -1 out of bounds for type 'char [50]' SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior main.cpp:67:28 in Debug(line 53): i=1 Debug(line 53): i=2 Debug(line 53): i=3 Debug(line 53): i=4 Debug(line 53): i=5 Debug(line 53): i=6 Debug(line 53): i=7 Debug(line 53): i=8 サーバー10.20.30.1/16が故障状態です Debug(line 53): i=9 故障期間は1秒です Debug(line 53): i=10 サーバー10.20.30.1/16が故障状態です Debug(line 53): i=11 故障期間は7分6秒です Debug(line 53): i=12 サーバー10.20.30.1/16が故障状態です Debug(line 53): i=13 故障期間は10秒です Debug(line 53): i=14 サーバー192.168.1.1/24が故障状態です Debug(line 53): i=15 故障期間は5分90秒です Debug(line 53): i=16

56行目で初期化されている変数cに着目すると、cが0となるのは初めてループに入ったときのみとなります。このときlenは確実に0です。にも関わらすlen -1のようにアクセスしているため、配列外参照になっています。これは多分ロジックがおかしいのではないのですかね。

投稿2020/11/18 17:15

編集2020/11/18 17:45
yumetodo

総合スコア5852

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

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

退会済みユーザー

退会済みユーザー

2020/11/19 02:27

ありがとうございます、解決しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問