LINUX.ORG.RU

С, причина сегфолта.

 ,


0

1

Нужно прожку написать, которая из лог файла выводила статистику сканирования портов по секундно, каждой минуты.

вот файл: http://pastebin.com/SGiBnszW

вот код: почему после вызова add происходит сегфолт?

// #3 log file
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>

struct scan // Информация о сканировании в течении одной минуты
{
	char hr; // Час
	char mn; // Минута
	char qty[60];// Количество сканирований в каждую секунду
	struct scan* next;
};

typedef struct scan Scan;

void foll(FILE* f, char lim)//Бежим по файлу до символа lim(пропуск)
{
	if (getc(f) == lim)
		return;
	foll(f,lim);
}

char dtcd[8] = "Detected";
char prt[4] = "Port";
char scn[4] = "Scan";

char d[8];
char p[4];
char s[4];

char check()
{
	char res = 1;
	for(int i=4; i<8; i++)
		res = res & (d[i] == dtcd[i]);
	for(int i=0; i<4; i++)
	{
		res = res & (d[i] == dtcd[i]) & (p[i] == prt[i]) & (s[i] == scn[i]);
	}
	return res;
}

Scan* head;

void printLine(char q[])
{
	printf("sec qty\n");
	for(int i=0; i<60; i++)
	{
		if (q[i] != 0)
			printf("%3d %3d\n",i,q[i]);
	}
}

void add(int h, int m, int s)
{
	char flag = 1;
	if (head)
	{
		if ((head -> hr == h) & (head -> mn == m))
		{
			((head -> qty)[s]) += 1;
			flag = 0;
		}
	}
	if (flag)
	{
		Scan* tmp = calloc(1,sizeof(Scan));
		tmp -> hr = h;
		tmp -> mn = m;
		tmp -> qty[s] = 1;
		tmp -> next = head;
		head = tmp;
	}
	printf("get One %d %d:\n",h,m);
	printLine(head -> qty);
	getchar();
}

void delList(Scan* s)
{
	if (s == 0)
		return;
	delList(s -> next);
	free(s);
}

void show()
{
	printf("show one more or quit?(s,q): ");
	if (getchar() == 'q')
		return;
	printf("input hour and minute to show(h m): ");
	int h,m;
	scanf("%d %d",&h,&m);
	for(Scan* s=head; s!=0; s = s -> next)
	{
		if ((s -> hr == h) & (s -> mn == m))
		{
			printLine(s -> qty);
			show();
			return;
		}
	}
	printf("there is not scans at this time\n");
	show();
}

int main()
{
	char path[50];
	printf("input filename: ");
	scanf("%s",path);
	FILE* f = fopen(path,"rt");
	if (f == 0) // Если файл не открылся
	{
		printf("can't open\n");
		return 1;
	}
	fseek(f,0,SEEK_END);
	long long endP = ftell(f);
	fseek(f,0,SEEK_SET);
	head = 0;
	int th;
	int tm;
	int ts;
	printf("scanning file...");
	while (ftell(f) != endP)
	{
		foll(f,' ');
		foll(f,' ');
		foll(f,' ');
		fscanf(f,"%d:%d:%d",&th,&tm,&ts);
		foll(f,']');
		foll(f,']');
		fscanf(f,"%s %s %s",d,p,s);
		if (check())
		{
			add(th,tm,ts);
		}
		foll(f,'\n');
	}
	printf(" Ok\n");
//	show();
	delList(head);
	return 0;
}
★★★★★
Ответ на: комментарий от yandzee

чел тут символьные массивы инициализирует символами . и видимо :) для краткости записал в виде «abdc» а не ['а','b','c','d] концевые нули ему тут не нужны в дальнейшем :)

qulinxao ★★☆
()

строка в логе «Detected Smurf Attack» порет память вашей программы. А на запоротой памяти могут происходить разные чудеса :)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Угу. А теперь смотрим первую строку файла:

[Wed Mar 28 10:48:16 2012][FW]Detected Port Scan from 77.93.43.186, drop it
Считаем буквы в словах. Теперь внимательно смотрим man fscanf...

delete83 ★★
()
Ответ на: комментарий от delete83

Ничего, что они добавятся автоматом?

ваша неправда в си если места под терминатора нет то компилятор спокойно проглотит такой код просто массив будет без завершающего нуля а вот в сипипи компилятор развергнется гневными сообщениями что нет места для терминатора и откажется компилировать

anonymous
()
Ответ на: комментарий от delete83

не факт( если глобальное - не добавится(тем более что размеры кратны 4 :) ))

char a[1]="123";
char* b="456";

чему в каких случаях равно a[1]?

qulinxao ★★☆
()
Ответ на: комментарий от delete83

культурный человек
знает наряду с тем, как нельзя поступать, причины по которым так поступать нельзя, иначе ...

qulinxao ★★☆
()
Ответ на: комментарий от qulinxao

культурный человек знает наряду с тем, как нельзя поступать, причины по которым так поступать нельзя, иначе ...

в данном случае нет нужды знать, канделябром вас будут бить, или подсвечником.

drBatty ★★
()
Ответ на: комментарий от qulinxao

в данном случае необходимо писать char a[] = «string»; и никак иначе. Ваше a[123] даже если и будет работать, то обязательно поломается в процессе эксплуатации, за что вас и нужно бить канделябрами :-) Суть в том, что поломаться это всё может от разных причин, как например char a[7]=«строка»; может с лёгкостью рухнуть ежели мы перейдём на юникод. Что там на эту тему пишет стандарт - меня волнует мало, я просто по опыту это знаю.

drBatty ★★
()
head = 0;

А где выделяется память под структуру?

andreyu ★★★★★
()
char dtcd[8] = "Detected";
char prt[4] = "Port";
char scn[4] = "Scan";

О нуль-терминаторе строк слышали?

andreyu ★★★★★
()

Вообще ваша программа является примером того, как делать не нужно. Так что точите ее дальше, с опытом все получится.

andreyu ★★★★★
()
Ответ на: комментарий от fero

Глядя на код приходит в голову только одна мысль: ошибкой было писать эту программу. Ее всю надо переписывать.

delete83 ★★
()
Ответ на: комментарий от AptGet

C99 явно разрешает

и что? x-----x; C99 тоже не запрещает. Создателей C99 мало волнует, что x-----x; компиллится в НЁХ. Если тебя это тоже не волнует - флаг в руки, и барабан на шею. Барабан можешь взять в Windows98, а флажок выдери из Windows7.

drBatty ★★
()
Ответ на: комментарий от nozh

Не подскажете хоть один компилятор/платформу, где NULL != 0 ?

раньше были такие. Там указатель «в никуда» имел машинное представление в котором не все биты были равны 0, и потому, после преобразования в int получался не нуль (если преобразовывать например через union, при обычном преобразовании получается 0. Что вовсе не говорит о том, что NULL === 0)

И да, в C++ NULL тождественно равен 0. ЕМНИП.

Но НЕ в простом C.

И кстати, раньше было полно машин, в которых по адресу 0 лежали вполне себе осмысленные данные. Как к ним обращаться, если указатель на них ложный?

drBatty ★★
()
Ответ на: комментарий от drBatty

на лоре неоднократно :

Классика кунг-фу  
Сначала ты не знаешь, что нельзя делать то-то 

Потом знаешь, что нельзя делать то-то 
Потом ты понимаешь, что иногда таки можно делать то-то 
Ну а потом ты понимаешь, что помимо того-то существует еще шестьдесять шесть способов добиться желаемого, и все из них практически равноправны. 
Когда тебя спрашивают «как мне добиться желаемого», ты быстро перебираешь в уме эти шестьдесять шесть способов, прикидываешь то общее, что в них есть, вздыхаешь и говоришь: «вообще-то, главное — гармония.» 
На вопрос обиженных учеников: «а как ее добиться?», ты говоришь: «никогда не делайте то-то». 

qulinxao ★★☆
()
Ответ на: комментарий от drBatty

и что? x-----x; C99 тоже не запрещает.

это UB, а результат char a[3] = «abc»; определен и описан в стандарте. И даже приведен пример использования.

Создателей C99 мало волнует, что x-----x; компиллится в НЁХ. Если тебя это тоже не волнует - флаг в руки, и барабан на шею. Барабан можешь взять в Windows98, а флажок выдери из Windows7.

Мимо.

AptGet ★★★
()
Ответ на: комментарий от nozh

И на сколько раньше были эти машины? Они еще работают?

думаю да. Всякая встраиваемая хрень, типа холодильника. Скажем там всего 256 байт памяти, 0, 1, ... 255. Очевидно, что раз 0 - это вполне валидный адрес, то требуется в качестве NULL задать какое-то другое значение, например -1, или 256. Потому как NULL НИКУДА не указывает, а разименованный нуль == НЁХ (UB). Естественно, требуется при преобразовании «указатель -> целое» учитывать, что просто так, побитно, этого делать нельзя.

drBatty ★★
()
Ответ на: комментарий от AptGet

это UB, а результат char a[3] = «abc»; определен и описан в стандарте. И даже приведен пример использования.

да? можно поточнее ссылку? Интересует, ЗАЧЕМ это может понадобится?

Мимо.

почему «мимо»? всё точно. Кстати, x-----x это совсем не UB - поведение тут вполне определено. Произойдёт ровно ТРИ вычитания. Правда стандарт не говорит, ЧТО будет вычитаться, и В КАКОМ ПОРЯДКЕ (доктор сказал, что я беременна! А от кого? Доктор не сказал...). Но поведение вполне детерминировано. IRL компилятор распараллеливает на два потока (gcc i686), и выполняет два вычитания сразу в U и V трубах, получается эпичная фигня, но это мало кого волнует.

Поведение при a[3] = {'a', 'b', 'c', '\0'}; может и описано, может оно даже и работает, но это ИМХО скорее PHP, а не C. За кой ляд этот быдлокод вставили в стандарт - мне неведомо. И да, что стандарт говорит об этом:

a[100] = {'a', 'b', 'c', '\0'};

?

Ну если массив НЕстатический? (со статическим всё более-менее ясно).

drBatty ★★
()
Ответ на: комментарий от drBatty

думаю да. Всякая встраиваемая хрень, типа холодильника.

Даже на встраиваемой хери NULL == 0, несмотря на то, что по адресу 0 находится регистр данных параллельного порта. Вот, например: http://stackoverflow.com/questions/3401039/address-0-being-overwritten-by-nul...

nozh
()
Ответ на: комментарий от nozh

Ещё вброшу:
It is only in pointer contexts that NULL and 0 are equivalent. NULL should not be used when another kind of 0 is required, even though it might work, because doing so sends the wrong stylistic message. (Furthermore, ANSI allows the definition of NULL to be ((void *)0), which will not work at all in non-pointer contexts.)
http://c-faq.com/null/nullor0.html
Замечательно расписано.

fero ★★★★
()
Ответ на: комментарий от nozh

дело в том, что в С нет логического типа TRUE/FALSE. Вместо него используется целый тип int. И при ПРЕОБРАЗОВАНИИ указателя в целый тип получается 0 для NULL, и НЕ ноль для ptr != NULL. Однако, это вовсе не говорит о том, что NULL === 0.

NULL should not be used when another kind of 0 is required, even though it might work, because doing so sends the wrong stylistic message. (Furthermore, ANSI allows the definition of NULL to be ((void *)0), which will not work at all in non-pointer contexts.) In particular, do not use NULL when the ASCII null character (NUL) is desired. Provide your own definition

	#define NUL '\0'

if you must.

drBatty ★★
()
Ответ на: комментарий от drBatty

дело в том, что в С нет логического типа TRUE/FALSE. Вместо него используется целый тип int. И при ПРЕОБРАЗОВАНИИ указателя в целый тип получается 0 для NULL, и НЕ ноль для ptr != NULL. Однако, это вовсе не говорит о том, что NULL === 0.

Вернемся к началу дискуссии... Вот допустим, я пишу в коде «if (ptr == 0) return;», у вас к этому коду есть претензии? Если нет, то к чему вы все это написали? Если же есть, то прошу указать хотя бы один компилятор/архитектуру, на которой этот код не будет работать.

nozh
()
Ответ на: комментарий от nozh

nozh

Вернемся к началу дискуссии... Вот допустим, я пишу в коде «if (ptr == 0) return;», у вас к этому коду есть претензии?

претензий нет. Если преобразовать NULL в int, то получится 0. Что совсем не говорит о том, что NULL это ноль. ЕМНИП это даже не говорит о том, что если преобразовать (int)0 в указатель, то получится NULL.

drBatty ★★
()
Ответ на: комментарий от drBatty

претензий нет.

Т.е. таки нет таких архитектур/компиляторов, где while (NULL != 0) {} был бы вечным циклом?

Если преобразовать NULL в int, то получится 0. Что совсем не говорит о том, что NULL это ноль. ЕМНИП это даже не говорит о том, что если преобразовать (int)0 в указатель, то получится NULL.

К чему вы все это пишете?

nozh
()
Ответ на: комментарий от nozh

Полистал ISO/IEC 9899:1999. Нигде не написано, что NULL равно 0. Во всяком случае я не нашел. Получается, что if(ptr == 0) - говнокод, не зависимо от того работает оно или нет.

fero ★★★★
()
Ответ на: комментарий от fero

Полистал ISO/IEC 9899:1999. Нигде не написано, что NULL равно 0. Во всяком случае я не нашел.

6.3.2.3

3. An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

6.5.9 Equality operators

5. Otherwise, at least one operand is a pointer. If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer. If one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void, the former is converted to the type of the latter

Получается, что if(ptr == 0) - говнокод, не зависимо от того работает оно или нет.

Не получается.

nozh
()
Ответ на: комментарий от nozh

Моё мнение не изменилось. Не вижу смысла продолжать спор. Спасибо за уделенное время.

fero ★★★★
()
Ответ на: комментарий от nozh

nozh

Т.е. таки нет таких архитектур/компиляторов, где while (NULL != 0) {} был бы вечным циклом?

нет.

nozh

К чему вы все это пишете?

к тому, что NULL это НЕ 0. Единственное, что есть в стандарте, так это то, что NULL преобразуется в целое 0.

drBatty ★★
()
Ответ на: комментарий от fero

fero

Полистал ISO/IEC 9899:1999. Нигде не написано, что NULL равно 0. Во всяком случае я не нашел. Получается, что if(ptr == 0) - говнокод, не зависимо от того работает оно или нет.

if(ptr == 0) это вполне себе нормальный код. Единственное но, можно опечататься, и получить говнокод if(ptr = 0), потому, ИМХО, лучше писать так if(!ptr), ИМХО это легко и просто читается, ведь ptr это указатель, который куда-то указывает. Но только если (int)ptr истинно. Если ложно (истинно !ptr), то этот «указатель» никуда не указывает, и следовательно - не указатель.

drBatty ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.