Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Prog2
/
ell_feladat
/
Test
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
1874e6ca
authored
May 07, 2019
by
Szeberényi Imre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
v0
parents
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1126 additions
and
0 deletions
+1126
-0
gtest_lite.h
+370
-0
memtrace.cpp
+537
-0
memtrace.h
+219
-0
No files found.
gtest_lite.h
0 → 100644
View file @
1874e6ca
#ifndef GTEST_LITE_H
#define GTEST_LITE_H
/**
* \file gtest_lite.h (v3/2019)
*
* Google gtest keretrendszerhez hasonló rendszer.
* Sz.I. 2015., 2016., 2017. (_Has_X)
* Sz.I. 2018 (template), ENDM, ENDMsg, nullptr_t
* Sz.I. 2019 singleton
*
* A tesztelés legalapvetőbb funkcióit támogató függvények és makrók.
* Nem szálbiztos megvalósítás.
*
*
* Szabadon felhasználható, bővíthető.
*
* Használati példa:
* Teszteljük az f(x)=2*x függvényt:
* int f(int x) { return 2*x; }
*
* int main() {
* TEST(TeszEsetNeve, TesztNeve)
* EXPECT_EQ(0, f(0));
* EXPECT_EQ(4, f(2)) << "A függvény hibás eredményt adott" << std::endl;
* ...
* END
* ...
*
* A működés részleteinek megértése szorgalmi feladat.
*/
#include <iostream>
#include <cassert>
#include <cmath>
#include <cstring>
#include <limits>
#include <string>
#include <fstream>
#ifdef MEMTRACE
#include "memtrace.h"
#endif
// Két makró az egyes tesztek elé és mögé:
// A két makró a kapcsos zárójelekkel egy új blokkot hoz létre, amiben
// a nevek lokálisak, így elkerülhető a névütközés.
/// Teszt kezdete. A makró paraméterezése hasonlít a gtest
/// paraméterezéséhez. Így az itt elkészített testek könnyen átemelhetők
/// a gtest keretrendszerbe.
/// @param C - teszteset neve (csak a gtest kompatibilitás miatt van külön neve az eseteknek)
/// @param N - teszt neve
#define TEST(C, N) { gtest_lite::test.begin(#C"."#N);
/// Teszteset vége.
#define END gtest_lite::test.end(); }
/// Teszteset vége allokált blokkok számának összehasonlításával
/// Ez az ellenőrzés nem bomba biztos.
#define ENDM gtest_lite::test.end(true); }
/// Teszteset vége allokált blokkok számának összehasonlításával
/// Ez az ellenőrzés nem bomba biztos.
/// Ha hiba van kiírja az üzenetet.
#define ENDMsg(t) gtest_lite::test.end(true) << t << std::endl; }
// Eredmények vizsgálatát segítő makrók.
// A paraméterek és a funkciók a gtest keretrendszerrel megegyeznek.
/// Sikeres teszt makrója
#define SUCCEED() gtest_lite::test.expect(true, __FILE__, __LINE__, "SUCCEED()", true)
/// Sikertelen teszt makrója
#define FAIL() gtest_lite::test.expect(false, __FILE__, __LINE__, "FAIL()", true)
/// Azonosságot elváró makró
#define EXPECT_EQ(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::eq, __FILE__, __LINE__, "EXPECT_EQ(" #expected ", " #actual ")" )
/// Eltérést elváró makró
#define EXPECT_NE(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::ne, __FILE__, __LINE__, "EXPECT_NE(" #expected ", " #actual ")", "etalon" )
/// Kisebb, vagy egyenlő relációt elváró makró
#define EXPECT_LE(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::le, __FILE__, __LINE__, "EXPECT_LE(" #expected ", " #actual ")", "etalon" )
/// Kisebb, mint relációt elváró makró
#define EXPECT_LT(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::lt, __FILE__, __LINE__, "EXPECT_LT(" #expected ", " #actual ")", "etalon" )
/// Nagyobb, vagy egyenlő relációt elváró makró
#define EXPECT_GE(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::ge, __FILE__, __LINE__, "EXPECT_GE(" #expected ", " #actual ")", "etalon" )
/// Nagyobb, mint relációt elváró makró
#define EXPECT_GT(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::gt, __FILE__, __LINE__, "EXPECT_GT(" #expected ", " #actual ")", "etalon" )
/// Igaz értéket elváró makró
#define EXPECT_TRUE(actual) gtest_lite::EXPECT_(true, actual, gtest_lite::eq, __FILE__, __LINE__, "EXPECT_TRUE(" #actual ")" )
/// Hamis értéket elváró makró
#define EXPECT_FALSE(actual) gtest_lite::EXPECT_(false, actual, gtest_lite::eq, __FILE__, __LINE__, "EXPECT_FALSE(" #actual ")" )
/// Valós számok azonosságát elváró makró
#define EXPECT_FLOAT_EQ(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::almostEQ, __FILE__, __LINE__, "EXPECT_FLOAT_EQ(" #expected ", " #actual ")" )
/// Valós számok azonosságát elváró makró
#define EXPECT_DOUBLE_EQ(expected, actual) gtest_lite::EXPECT_(expected, actual, gtest_lite::almostEQ, __FILE__, __LINE__, "EXPECT_DOUBLE_EQ(" #expected ", " #actual ")" )
/// C stringek (const char *) azonosságát tesztelő makró
#define EXPECT_STREQ(expected, actual) gtest_lite::EXPECTSTR(expected, actual, gtest_lite::eqstr, __FILE__, __LINE__, "EXPECT_STREQ(" #expected ", " #actual ")" )
/// C stringek (const char *) eltéréset tesztelő makró
#define EXPECT_STRNE(expected, actual) gtest_lite::EXPECTSTR(expected, actual, gtest_lite::nestr, __FILE__, __LINE__, "EXPECT_STRNE(" #expected ", " #actual ")", "etalon" )
/// Kivételt várunk
#define EXPECT_THROW(statement, exception_type) try { gtest_lite::test.tmp = false; statement; } \
catch (exception_type) { gtest_lite::test.tmp = true; } \
catch (...) { } \
EXPECTTHROW(statement, "kivetelt dob.", "nem dobott '"#exception_type"' kivetelt.")
/// Kivételt várunk
#define EXPECT_ANY_THROW(statement) try { gtest_lite::test.tmp = false; statement; } \
catch (...) { gtest_lite::test.tmp = true; } \
EXPECTTHROW(statement, "kivetelt dob.", "nem dobott kivetelt.")
/// Nem várunk kivételt
#define EXPECT_NO_THROW(statement) try { gtest_lite::test.tmp = true; statement; } \
catch (...) { gtest_lite::test.tmp = false; }\
EXPECTTHROW(statement, "nem dob kivetelt.", "kivetelt dobott.")
/// Nem várunk kivételt gtest kompatibilitás miatt
#define ASSERT_NO_THROW(statement) try { gtest_lite::test.tmp = true; statement; } \
catch (...) { gtest_lite::test.tmp = false; }\
EXPECTTHROW(statement, "nem dob kivetelt.", "kivetelt dobott.")
/// Kivételt várunk és továbbdobjuk -- ilyen nincs a gtest-ben
#define EXPECT_THROW_THROW(statement, exception_type) try { gtest_lite::test.tmp = false; statement; } \
catch (exception_type) { gtest_lite::test.tmp = true; throw; } \
EXPECTTHROW(statement, "kivetelt dob.", "nem dobott '"#exception_type"' kivetelt.")
/// Segédmakró egy adattag, vagy tagfüggvény létezésének tesztelésére futási időben
/// Ötlet:
/// https://cpptalk.wordpress.com/2009/09/12/substitution-failure-is-not-an-error-2
/// Használat:
/// CREATE_Has_(size)
/// ... if (Has_size<std::string>::member)...
#define CREATE_Has_(X) \
template<typename T> struct _Has_##X { \
struct Fallback { int X; }; \
struct Derived : T, Fallback {}; \
template<typename C, C> struct ChT; \
template<typename D> static char (&f(ChT<int Fallback::*, &D::X>*))[1]; \
template<typename D> static char (&f(...))[2]; \
static bool const member = sizeof(f<Derived>(0)) == 2; \
};
/// Segédfüggvény egy publikus adattag, vagy tagfüggvény létezésének tesztelésére
/// fordítási időben
inline
void
hasMember
(...)
{}
/// Segédsablon típuskonverzió futás közbeni ellenőrzésere
template
<
typename
F
,
typename
T
>
struct
_Is_Types
{
template
<
typename
D
>
static
char
(
&
f
(
D
))[
1
];
template
<
typename
D
>
static
char
(
&
f
(...))[
2
];
static
bool
const
convertable
=
sizeof
(
f
<
T
>
(
F
()))
==
1
;
};
/// -----------------------------------
/// Belső megvalósításhoz tartozó makrók, és osztályok.
/// Nem célszerű közvetlenül használni, vagy módosítani
/// -----------------------------------
/// EXPECTTHROW: kivételkezelés
#define EXPECTTHROW(statement, exp, act) gtest_lite::test.expect(gtest_lite::test.tmp, __FILE__, __LINE__, #statement) \
<< "** Az utasitas " << (act) \
<< "\n** Azt vartuk, hogy " << (exp) << std::endl
#ifdef CPORTA
#define GTINIT(is) \
int magic; \
is >> magic;
#else
#define GTINIT(IS)
#endif // CPORTA
#ifdef CPORTA
#define GTEND(os) \
os << magic << (gtest_lite::test.fail() ? " NO" : " OK?") << std::endl;
#else
#define GTEND(os)
#endif // CPORTA
/// gtest_lite: a keretrendszer függvényinek és objektumainak névtere
namespace
gtest_lite
{
/// Tesztek állapotát tároló osztály.
/// Egyetlen egy statikus példány keletkezik, aminek a
/// destruktora a futás végén hívódik meg.
struct
Test
{
int
sum
;
///< tesztek számlálója
int
failed
;
///< hibás tesztek
int
ablocks
;
///< allokált blokkok száma
bool
status
;
///< éppen futó teszt státusza
bool
tmp
;
///< temp a kivételkezeléshez;
std
::
string
name
;
///< éppen futó teszt neve
std
::
fstream
null
;
///< nyelő, ha nem kell kiírni semmit
static
Test
&
getTest
()
{
static
Test
instance
;
///< egyedüli (singleton) példány
return
instance
;
}
private
:
/// singleton minta miatt
Test
()
:
sum
(
0
),
failed
(
0
),
status
(
false
),
null
(
"/dev/null"
)
{}
Test
(
const
Test
&
);
void
operator
=
(
const
Test
&
);
public
:
/// Teszt kezdete
void
begin
(
const
char
*
n
)
{
name
=
n
;
status
=
true
;
#ifdef MEMTRACE
ablocks
=
memtrace
::
allocated_blocks
();
#endif
#ifndef CPORTA
std
::
cerr
<<
"
\n
---> "
<<
name
<<
std
::
endl
;
#endif // CPORTA
++
sum
;
}
/// Teszt vége
std
::
ostream
&
end
(
bool
memchk
=
false
)
{
#ifdef MEMTRACE
if
(
memchk
&&
ablocks
!=
memtrace
::
allocated_blocks
())
{
status
=
false
;
return
std
::
cerr
<<
"** Lehet, hogy nem szabaditott fel minden memoriat! **"
<<
std
::
endl
;
}
#endif
#ifdef CPORTA
if
(
!
status
)
#endif // CPORTA
std
::
cerr
<<
(
status
?
" SIKERES"
:
"** HIBAS ****"
)
<<
"
\t
"
<<
name
<<
" <---"
<<
std
::
endl
;
if
(
!
status
)
return
std
::
cerr
;
else
return
null
;
}
bool
fail
()
{
return
failed
;
}
/// Eredményt adminisztráló tagfüggvény True a jó eset.
std
::
ostream
&
expect
(
bool
st
,
const
char
*
file
,
int
line
,
const
char
*
expr
,
bool
pr
=
false
)
{
if
(
!
st
)
{
++
failed
;
status
=
false
;
}
if
(
!
st
||
pr
)
{
std
::
string
str
(
file
);
size_t
i
=
str
.
rfind
(
"
\\
"
);
if
(
i
==
std
::
string
::
npos
)
i
=
str
.
rfind
(
"/"
);
if
(
i
==
std
::
string
::
npos
)
i
=
0
;
else
i
++
;
return
std
::
cerr
<<
"
\n
**** "
<<
&
file
[
i
]
<<
"("
<<
line
<<
"): "
<<
expr
<<
" ****"
<<
std
::
endl
;
}
return
null
;
}
/// Destruktor
~
Test
()
{
#ifdef CPORTA
if
(
failed
)
#endif // CPORTA
std
::
cerr
<<
"
\n
==== TESZT VEGE ==== HIBAS/OSSZES: "
<<
failed
<<
"/"
<<
sum
<<
std
::
endl
;
}
};
/// A statikus referencia minden fordítási egységben keletkezik, de
/// mindegyik egyetlen példányra fog hivatkozni a singleton minta miatt
static
Test
&
test
=
Test
::
getTest
();
/// általános sablon a várt értékhez.
template
<
typename
T1
,
typename
T2
>
std
::
ostream
&
EXPECT_
(
T1
exp
,
T2
act
,
bool
(
*
pred
)(
T1
,
T2
),
const
char
*
file
,
int
line
,
const
char
*
expr
,
const
char
*
lhs
=
"elvart"
,
const
char
*
rhs
=
"aktual"
)
{
return
test
.
expect
(
pred
(
exp
,
act
),
file
,
line
,
expr
)
<<
"** "
<<
lhs
<<
": "
<<
std
::
boolalpha
<<
exp
<<
"
\n
** "
<<
rhs
<<
": "
<<
std
::
boolalpha
<<
act
<<
std
::
endl
;
}
/// pointerre specializált sablon a várt értékhez.
template
<
typename
T1
,
typename
T2
>
std
::
ostream
&
EXPECT_
(
T1
*
exp
,
T2
*
act
,
bool
(
*
pred
)(
T1
*
,
T2
*
),
const
char
*
file
,
int
line
,
const
char
*
expr
,
const
char
*
lhs
=
"elvart"
,
const
char
*
rhs
=
"aktual"
)
{
return
test
.
expect
(
pred
(
exp
,
act
),
file
,
line
,
expr
)
<<
"** "
<<
lhs
<<
": "
<<
(
void
*
)
exp
<<
"
\n
** "
<<
rhs
<<
": "
<<
(
void
*
)
act
<<
std
::
endl
;
}
#if __cplusplus >= 201103L
/// nullptr-re specializált sablon a várt értékhez.
template
<
typename
T1
>
std
::
ostream
&
EXPECT_
(
T1
*
exp
,
std
::
nullptr_t
act
,
bool
(
*
pred
)(
T1
*
,
std
::
nullptr_t
),
const
char
*
file
,
int
line
,
const
char
*
expr
,
const
char
*
lhs
=
"elvart"
,
const
char
*
rhs
=
"aktual"
)
{
return
test
.
expect
(
pred
(
exp
,
act
),
file
,
line
,
expr
)
<<
"** "
<<
lhs
<<
": "
<<
(
void
*
)
exp
<<
"
\n
** "
<<
rhs
<<
": "
<<
(
void
*
)
act
<<
std
::
endl
;
}
#endif
/// stringek összehasonlításához.
/// azért nem spec. mert a sima EQ-ra másként kell működnie.
inline
std
::
ostream
&
EXPECTSTR
(
const
char
*
exp
,
const
char
*
act
,
bool
(
*
pred
)(
const
char
*
,
const
char
*
),
const
char
*
file
,
int
line
,
const
char
*
expr
,
const
char
*
lhs
=
"elvart"
,
const
char
*
rhs
=
"aktual"
)
{
return
test
.
expect
(
pred
(
exp
,
act
),
file
,
line
,
expr
)
<<
"** "
<<
lhs
<<
": "
<<
(
exp
==
NULL
?
"NULL pointer"
:
std
::
string
(
"
\"
"
)
+
exp
+
std
::
string
(
"
\"
"
))
<<
"
\n
** "
<<
rhs
<<
": "
<<
(
act
==
NULL
?
"NULL pointer"
:
std
::
string
(
"
\"
"
)
+
act
+
std
::
string
(
"
\"
"
))
<<
std
::
endl
;
}
/// segéd sablonok a relációkhoz.
/// azért nem STL (algorithm), mert csak a függvény lehet, hogy menjen a deduckció
template
<
typename
T1
,
typename
T2
>
bool
eq
(
T1
a
,
T2
b
)
{
return
a
==
b
;
}
inline
bool
eqstr
(
const
char
*
a
,
const
char
*
b
)
{
if
(
a
!=
NULL
&&
b
!=
NULL
)
return
strcmp
(
a
,
b
)
==
0
;
return
false
;
}
template
<
typename
T1
,
typename
T2
>
bool
ne
(
T1
a
,
T2
b
)
{
return
a
!=
b
;
}
inline
bool
nestr
(
const
char
*
a
,
const
char
*
b
)
{
if
(
a
!=
NULL
&&
b
!=
NULL
)
return
strcmp
(
a
,
b
)
!=
0
;
return
false
;
}
template
<
typename
T1
,
typename
T2
>
bool
le
(
T1
a
,
T2
b
)
{
return
a
<=
b
;
}
template
<
typename
T1
,
typename
T2
>
bool
lt
(
T1
a
,
T2
b
)
{
return
a
<
b
;
}
template
<
typename
T1
,
typename
T2
>
bool
ge
(
T1
a
,
T2
b
)
{
return
a
>=
b
;
}
template
<
typename
T1
,
typename
T2
>
bool
gt
(
T1
a
,
T2
b
)
{
return
a
>
b
;
}
/// Segédsablon valós számok összehasonlításához
/// Nem bombabiztos, de nekünk most jó lesz
/// Elméleti hátér:
/// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
template
<
typename
T
>
bool
almostEQ
(
T
a
,
T
b
)
{
// eps: ha a relatív, vagy abszolút hiba ettől kisebb, akkor elfogadjuk
T
eps
=
10
*
std
::
numeric_limits
<
T
>::
epsilon
();
// 10-szer a legkisebb érték
if
(
a
==
b
)
return
true
;
if
(
fabs
(
a
-
b
)
<
eps
)
return
true
;
double
aa
=
fabs
(
a
);
double
ba
=
fabs
(
b
);
if
(
aa
<
ba
)
{
aa
=
ba
;
ba
=
fabs
(
a
);
}
return
(
aa
-
ba
)
<
aa
*
eps
;
}
}
// namespace gtest_lite
#endif // GTEST_LITE_H
memtrace.cpp
0 → 100644
View file @
1874e6ca
/*********************************
Memoriaszivargas-detektor
Keszitette: Peregi Tamas, BME IIT, 2011
petamas@iit.bme.hu
Kanari: Szeberenyi Imre, 2013.
VS 2012: Szeberényi Imre, 2015.,
mem_dump: 2016.
meset felszabaditaskor: 2018.
typo: 2019.
*********************************/
/*definialni kell, ha nem paracssorbol allitjuk be (-DMEMTRACE) */
/*#define MEMTRACE */
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#ifdef MEMTRACE
#define FROM_MEMTRACE_CPP
#include "memtrace.h"
#define FMALLOC 0
#define FCALLOC 1
#define FREALLOC 2
#define FFREE 3
#define FNEW 4
#define FDELETE 5
#define FNEWARR 6
#define FDELETEARR 7
#define COMP(a,d) (((a)<=3 && (d)<=3) || ((d)==(a)+1))
#define PU(p) ((char*)p+CANARY_LEN) // mem pointerbol user poi
#define P(pu) ((char*)pu-CANARY_LEN) // user pointerbol mem poi
#define XSTR(s) STR(s)
#define STR(s) #s
/*******************************************************************/
/* Segedfuggvenyek es egyebek */
/*******************************************************************/
START_NAMESPACE
static
FILE
*
fperror
;
#ifdef MEMTRACE_TO_MEMORY
static
const
unsigned
int
CANARY_LEN
=
64
;
#else
static
const
unsigned
int
CANARY_LEN
=
0
;
#endif
static
const
unsigned
char
canary_byte1
=
'k'
;
static
const
unsigned
char
canary_byte2
=
'K'
;
static
unsigned
char
random_byte
;
typedef
enum
{
FALSE
,
TRUE
}
BOOL
;
static
const
char
*
pretty
[]
=
{
"malloc("
,
"calloc("
,
"realloc("
,
"free("
,
"new"
,
"delete"
,
"new[]"
,
"delete[]"
};
static
const
char
*
basename
(
const
char
*
s
)
{
const
char
*
s1
,
*
s2
;
s1
=
strrchr
(
s
,
'/'
);
if
(
s1
==
NULL
)
s1
=
s
;
else
s1
++
;
s2
=
strrchr
(
s1
,
'\\'
);
if
(
s2
==
NULL
)
s2
=
s1
;
else
s2
++
;
return
s2
;
}
static
char
*
StrCpy
(
char
**
to
,
const
char
*
from
)
{
if
(
from
==
NULL
)
{
*
to
=
NULL
;
}
else
{
*
to
=
(
char
*
)
malloc
(
strlen
(
from
)
+
1
);
if
(
*
to
)
strcpy
(
*
to
,
from
);
}
return
*
to
;
}
static
void
*
canary_malloc
(
size_t
size
,
unsigned
char
data
)
{
char
*
p
=
(
char
*
)
malloc
(
size
+
2
*
CANARY_LEN
);
if
(
p
)
{
memset
(
p
,
canary_byte1
,
CANARY_LEN
);
memset
(
p
+
CANARY_LEN
,
data
,
size
);
memset
(
p
+
CANARY_LEN
+
size
,
canary_byte2
,
CANARY_LEN
);
}
return
p
;
}
static
int
chk_canary
(
void
*
p
,
size_t
size
)
{
unsigned
char
*
pc
=
(
unsigned
char
*
)
p
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
CANARY_LEN
;
i
++
)
if
(
pc
[
i
]
!=
canary_byte1
)
return
-
1
;
pc
+=
CANARY_LEN
+
size
;
for
(
i
=
0
;
i
<
CANARY_LEN
;
i
++
)
if
(
pc
[
i
]
!=
canary_byte2
)
return
1
;
return
0
;
}
typedef
struct
{
int
f
;
/* allocator func */
int
line
;
char
*
par_txt
;
char
*
file
;
}
call_t
;
static
call_t
pack
(
int
f
,
const
char
*
par_txt
,
int
line
,
const
char
*
file
)
{
call_t
ret
;
ret
.
f
=
f
;
ret
.
line
=
line
;
StrCpy
(
&
ret
.
par_txt
,
par_txt
);
StrCpy
(
&
ret
.
file
,
file
);
return
ret
;
}
static
void
print_call
(
const
char
*
msg
,
call_t
call
)
{
if
(
msg
)
fprintf
(
fperror
,
"%s"
,
msg
);
fprintf
(
fperror
,
"%s"
,
pretty
[
call
.
f
]);
fprintf
(
fperror
,
"%s"
,
call
.
par_txt
?
call
.
par_txt
:
"?"
);
if
(
call
.
f
<=
3
)
fprintf
(
fperror
,
")"
);
fprintf
(
fperror
,
" @ %s:"
,
call
.
file
?
basename
(
call
.
file
)
:
"?"
);
fprintf
(
fperror
,
"%d
\n
"
,
call
.
line
?
call
.
line
:
0
);
}
/* memoriateruletet dump */
static
void
dump_memory
(
void
const
*
mem
,
size_t
size
,
size_t
can_len
,
FILE
*
fp
)
{
unsigned
char
const
*
m
=
(
unsigned
char
const
*
)
mem
;
unsigned
int
s
,
o
;
if
(
can_len
>
0
)
fprintf
(
fp
,
"Dump (addr: %p kanari hossz: %d):
\n
"
,
m
+
can_len
,
(
int
)
can_len
);
else
fprintf
(
fp
,
"Dump: (addr: %p)
\n
"
,
m
);
size
+=
2
*
can_len
;
for
(
s
=
0
;
s
<
(
size
+
15
)
/
16
;
s
++
)
{
fprintf
(
fp
,
"%04x:%c "
,
s
*
16
,
s
*
16
<
can_len
||
s
*
16
>=
size
-
can_len
?
' '
:
'*'
);
for
(
o
=
0
;
o
<
16
;
o
++
)
{
if
(
o
==
8
)
fprintf
(
fp
,
" "
);
if
(
s
*
16
+
o
<
size
)
fprintf
(
fp
,
"%02x "
,
m
[
s
*
16
+
o
]);
else
fprintf
(
fp
,
" "
);
}
fprintf
(
fp
,
" "
);
for
(
o
=
0
;
o
<
16
;
o
++
)
{
if
(
s
*
16
+
o
<
size
)
fprintf
(
fp
,
"%c"
,
isprint
(
m
[
s
*
16
+
o
])
?
m
[
s
*
16
+
o
]
:
'.'
);
else
fprintf
(
fp
,
" "
);
}
fprintf
(
fp
,
"
\n
"
);
}
}
void
mem_dump
(
void
const
*
mem
,
size_t
size
,
FILE
*
fp
)
{
dump_memory
(
mem
,
size
,
0
,
fp
);
}
static
BOOL
dying
;
static
void
die
(
const
char
*
msg
,
void
*
p
,
size_t
size
,
call_t
*
a
,
call_t
*
d
)
{
#ifdef MEMTRACE_ERRFILE
fperror
=
fopen
(
XSTR
(
MEMTRACE_ERRFILE
),
"w"
);
#endif
fprintf
(
fperror
,
"%s
\n
"
,
msg
);
if
(
p
)
{
fprintf
(
fperror
,
"
\t
Pointer:
\t
%p"
,
PU
(
p
));
if
(
size
)
fprintf
(
fperror
,
" (%d byte)"
,
(
int
)
size
);
fprintf
(
fperror
,
"
\n
"
);
}
if
(
a
)
print_call
(
"
\t
Foglalas:
\t
"
,
*
a
);
if
(
d
)
print_call
(
"
\t
Felszabaditas:
\t
"
,
*
d
);
if
(
p
)
dump_memory
(
p
,
size
,
CANARY_LEN
,
fperror
);
dying
=
TRUE
;
exit
(
120
);
}
static
void
initialize
();
END_NAMESPACE
/*******************************************************************/
/* MEMTRACE_TO_MEMORY */
/*******************************************************************/
#ifdef MEMTRACE_TO_MEMORY
START_NAMESPACE
typedef
struct
_registry_item
{
void
*
p
;
/* mem pointer*/
size_t
size
;
/* size*/
call_t
call
;
struct
_registry_item
*
next
;
}
registry_item
;
static
registry_item
registry
;
/*sentinel*/
static
void
print_registry_item
(
registry_item
*
p
)
{
if
(
p
)
{
print_registry_item
(
p
->
next
);
fprintf
(
fperror
,
"
\t
%p%5d byte "
,
p
->
p
,
(
int
)
p
->
size
);
print_call
(
NULL
,
p
->
call
);
if
(
p
->
call
.
par_txt
)
free
(
p
->
call
.
par_txt
);
if
(
p
->
call
.
file
)
free
(
p
->
call
.
file
);
free
(
p
);
}
}
/* ha nincs hiba, akkor 0-val tér vissza */
int
mem_check
(
void
)
{
initialize
();
if
(
dying
)
return
2
;
/* címzési hiba */
if
(
registry
.
next
)
{
/*szivarog*/
#ifdef MEMTRACE_ERRFILE
fperror
=
fopen
(
XSTR
(
MEMTRACE_ERRFILE
),
"w"
);
#endif
fprintf
(
fperror
,
"Szivargas:
\n
"
);
print_registry_item
(
registry
.
next
);
registry
.
next
=
NULL
;
return
1
;
/* memória fogyás */
}
return
0
;
}
END_NAMESPACE
#endif
/*MEMTRACE_TO_MEMORY*/
/*******************************************************************/
/* MEMTRACE_TO_FILE */
/*******************************************************************/
#ifdef MEMTRACE_TO_FILE
START_NAMESPACE
static
FILE
*
trace_file
;
END_NAMESPACE
#endif
/*******************************************************************/
/* register/unregister */
/*******************************************************************/
START_NAMESPACE
static
int
allocated_blks
;
int
allocated_blocks
()
{
return
allocated_blks
;
}
static
BOOL
register_memory
(
void
*
p
,
size_t
size
,
call_t
call
)
{
initialize
();
allocated_blks
++
;
#ifdef MEMTRACE_TO_FILE
fprintf
(
trace_file
,
"%p
\t
%d
\t
%s%s"
,
PU
(
p
),
(
int
)
size
,
pretty
[
call
.
f
],
call
.
par_txt
?
call
.
par_txt
:
"?"
);
if
(
call
.
f
<=
3
)
fprintf
(
trace_file
,
")"
);
fprintf
(
trace_file
,
"
\t
%d
\t
%s
\n
"
,
call
.
line
,
call
.
file
?
call
.
file
:
"?"
);
fflush
(
trace_file
);
#endif
#ifdef MEMTRACE_TO_MEMORY
{
/*C-blokk*/
registry_item
*
n
=
(
registry_item
*
)
malloc
(
sizeof
(
registry_item
));
if
(
n
==
NULL
)
return
FALSE
;
n
->
p
=
p
;
n
->
size
=
size
;
n
->
call
=
call
;
n
->
next
=
registry
.
next
;
registry
.
next
=
n
;
}
/*C-blokk*/
#endif
return
TRUE
;
}
#ifdef MEMTRACE_TO_MEMORY
static
registry_item
*
find_registry_item
(
void
*
p
)
{
registry_item
*
n
=
&
registry
;
for
(;
n
->
next
&&
n
->
next
->
p
!=
p
;
n
=
n
->
next
);
return
n
;
}
#endif
static
void
unregister_memory
(
void
*
p
,
call_t
call
)
{
initialize
();
#ifdef MEMTRACE_TO_FILE
fprintf
(
trace_file
,
"%p
\t
%d
\t
%s%s"
,
PU
(
p
),
-
1
,
pretty
[
call
.
f
],
call
.
par_txt
?
call
.
par_txt
:
"?"
);
if
(
call
.
f
<=
3
)
fprintf
(
trace_file
,
")"
);
fprintf
(
trace_file
,
"
\t
%d
\t
%s
\n
"
,
call
.
line
,
call
.
file
?
call
.
file
:
"?"
);
fflush
(
trace_file
);
#endif
#ifdef MEMTRACE_TO_MEMORY
{
/*C-blokk*/
registry_item
*
n
=
find_registry_item
(
p
);
if
(
n
->
next
)
{
allocated_blks
--
;
registry_item
*
r
=
n
->
next
;
n
->
next
=
r
->
next
;
if
(
COMP
(
r
->
call
.
f
,
call
.
f
))
{
int
chk
=
chk_canary
(
r
->
p
,
r
->
size
);
if
(
chk
<
0
)
die
(
"Blokk elott serult a memoria:"
,
r
->
p
,
r
->
size
,
&
r
->
call
,
&
call
);
if
(
chk
>
0
)
die
(
"Blokk utan serult a memoria"
,
r
->
p
,
r
->
size
,
&
r
->
call
,
&
call
);
/*rendben van minden*/
if
(
call
.
par_txt
)
free
(
call
.
par_txt
);
if
(
r
->
call
.
par_txt
)
free
(
r
->
call
.
par_txt
);
if
(
call
.
file
)
free
(
call
.
file
);
if
(
r
->
call
.
file
)
free
(
r
->
call
.
file
);
memset
(
PU
(
r
->
p
),
'f'
,
r
->
size
);
PU
(
r
->
p
)[
r
->
size
-
1
]
=
0
;
free
(
r
);
}
else
{
/*hibas felszabaditas*/
die
(
"Hibas felszabaditas:"
,
r
->
p
,
r
->
size
,
&
r
->
call
,
&
call
);
}
}
else
{
die
(
"Nem letezo, vagy mar felszabaditott adat felszabaditasa:"
,
p
,
0
,
NULL
,
&
call
);
}
}
/*C-blokk*/
#endif
}
END_NAMESPACE
/*******************************************************************/
/* C-stílusú memóriakezelés */
/*******************************************************************/
#ifdef MEMTRACE_C
START_NAMESPACE
void
*
traced_malloc
(
size_t
size
,
const
char
*
par_txt
,
int
line
,
const
char
*
file
)
{
void
*
p
;
initialize
();
p
=
canary_malloc
(
size
,
random_byte
);
if
(
p
)
{
if
(
!
register_memory
(
p
,
size
,
pack
(
FMALLOC
,
par_txt
,
line
,
file
)))
{
free
(
p
);
return
NULL
;
}
return
PU
(
p
);
}
return
NULL
;
}
void
*
traced_calloc
(
size_t
count
,
size_t
size
,
const
char
*
par_txt
,
int
line
,
const
char
*
file
)
{
void
*
p
;
initialize
();
size
*=
count
;
p
=
canary_malloc
(
size
,
0
);
if
(
p
)
{
if
(
!
register_memory
(
p
,
size
,
pack
(
FCALLOC
,
par_txt
,
line
,
file
)))
{
free
(
p
);
return
NULL
;
}
return
PU
(
p
);
}
return
NULL
;
}
void
traced_free
(
void
*
pu
,
const
char
*
par_txt
,
int
line
,
const
char
*
file
)
{
initialize
();
if
(
pu
)
{
unregister_memory
(
P
(
pu
),
pack
(
FFREE
,
par_txt
,
line
,
file
));
free
(
P
(
pu
));
}
else
{
/*free(NULL) eset*/
#ifdef MEMTRACE_TO_FILE
fprintf
(
trace_file
,
"%s
\t
%d
\t
%10s
\t
"
,
"NULL"
,
-
1
,
pretty
[
FFREE
]);
fprintf
(
trace_file
,
"%d
\t
%s
\n
"
,
line
,
file
?
file
:
"?"
);
fflush
(
trace_file
);
#endif
#ifndef ALLOW_FREE_NULL
{
/*C-blokk*/
call_t
call
;
call
=
pack
(
FFREE
,
par_txt
,
line
,
file
);
die
(
"free(NULL) hivasa:"
,
NULL
,
0
,
NULL
,
&
call
);
}
/*C-blokk*/
#endif
}
}
void
*
traced_realloc
(
void
*
old
,
size_t
size
,
const
char
*
par_txt
,
int
line
,
const
char
*
file
)
{
void
*
p
;
size_t
oldsize
=
0
;
registry_item
*
n
;
initialize
();
#ifdef MEMTRACE_TO_MEMORY
n
=
find_registry_item
(
P
(
old
));
if
(
n
)
oldsize
=
n
->
next
->
size
;
p
=
canary_malloc
(
size
,
random_byte
);
#else
p
=
realloc
(
old
,
size
);
#endif
if
(
p
)
{
/*Ha sikerult a foglalas, regisztraljuk*/
register_memory
(
p
,
size
,
pack
(
FREALLOC
,
par_txt
,
line
,
file
));
if
(
old
)
{
#ifdef MEMTRACE_TO_MEMORY
int
cpsize
=
2
*
CANARY_LEN
;
if
(
oldsize
<
size
)
cpsize
+=
oldsize
;
else
cpsize
+=
size
;
memcpy
(
p
,
P
(
old
),
cpsize
);
#endif
unregister_memory
(
P
(
old
),
pack
(
FREALLOC
,
par_txt
,
line
,
file
));
#ifdef MEMTRACE_TO_MEMORY
free
P
(
old
);
#endif
}
return
PU
(
p
);
}
else
{
return
NULL
;
}
}
END_NAMESPACE
#endif
/*MEMTRACE_C*/
/*******************************************************************/
/* C++-stílusú memóriakezelés */
/*******************************************************************/
#ifdef MEMTRACE_CPP
START_NAMESPACE
std
::
new_handler
_new_handler
;
void
_set_new_handler
(
std
::
new_handler
h
)
{
initialize
();
_new_handler
=
h
;
}
static
call_t
delete_call
;
static
BOOL
delete_called
;
void
set_delete_call
(
int
line
,
const
char
*
file
)
{
initialize
();
delete_call
=
pack
(
0
,
""
,
line
,
file
);
/*func értéke lényegtelen, majd felülírjuk*/
delete_called
=
TRUE
;
}
void
*
traced_new
(
size_t
size
,
int
line
,
const
char
*
file
,
int
func
)
{
initialize
();
for
(;;)
{
void
*
p
=
canary_malloc
(
size
,
random_byte
);
if
(
p
)
{
register_memory
(
p
,
size
,
pack
(
func
,
""
,
line
,
file
));
return
PU
(
p
);
}
if
(
_new_handler
==
0
)
throw
std
::
bad_alloc
();
_new_handler
();
}
}
void
traced_delete
(
void
*
pu
,
int
func
)
{
initialize
();
if
(
pu
)
{
/*kiolvasom call-t, ha van*/
memtrace
::
call_t
call
=
delete_called
?
(
delete_call
.
f
=
func
,
delete_call
)
:
pack
(
func
,
NULL
,
0
,
NULL
);
memtrace
::
unregister_memory
(
P
(
pu
),
call
);
free
(
P
(
pu
));
}
delete_called
=
FALSE
;
}
END_NAMESPACE
void
*
operator
new
(
size_t
size
,
int
line
,
const
char
*
file
)
THROW_BADALLOC
{
return
memtrace
::
traced_new
(
size
,
line
,
file
,
FNEW
);
}
void
*
operator
new
[](
size_t
size
,
int
line
,
const
char
*
file
)
THROW_BADALLOC
{
return
memtrace
::
traced_new
(
size
,
line
,
file
,
FNEWARR
);
}
void
*
operator
new
(
size_t
size
)
THROW_BADALLOC
{
return
memtrace
::
traced_new
(
size
,
0
,
NULL
,
FNEW
);
}
void
*
operator
new
[](
size_t
size
)
THROW_BADALLOC
{
return
memtrace
::
traced_new
(
size
,
0
,
NULL
,
FNEWARR
);
}
void
operator
delete
(
void
*
p
)
THROW_NOTHING
{
memtrace
::
traced_delete
(
p
,
FDELETE
);
}
void
operator
delete
[](
void
*
p
)
THROW_NOTHING
{
memtrace
::
traced_delete
(
p
,
FDELETEARR
);
}
/* Visual C++ 2012 miatt kell, mert háklis, hogy nincs megfelelő delete, bár senki sem használja */
void
operator
delete
(
void
*
p
,
int
,
const
char
*
)
THROW_NOTHING
{
memtrace
::
traced_delete
(
p
,
FDELETE
);
}
void
operator
delete
[](
void
*
p
,
int
,
const
char
*
)
THROW_NOTHING
{
memtrace
::
traced_delete
(
p
,
FDELETE
);
}
#endif
/*MEMTRACE_CPP*/
/*******************************************************************/
/* initialize */
/*******************************************************************/
START_NAMESPACE
static
void
initialize
()
{
static
BOOL
first
=
TRUE
;
if
(
first
)
{
fperror
=
stderr
;
random_byte
=
(
unsigned
char
)
time
(
NULL
);
first
=
FALSE
;
dying
=
FALSE
;
#ifdef MEMTRACE_TO_MEMORY
registry
.
next
=
NULL
;
#if !defined(USE_ATEXIT_OBJECT) && defined(MEMTRACE_AUTO)
atexit
((
void
(
*
)(
void
))
mem_check
);
#endif
#endif
#ifdef MEMTRACE_TO_FILE
trace_file
=
fopen
(
"memtrace.dump"
,
"w"
);
#endif
#ifdef MEMTRACE_CPP
_new_handler
=
NULL
;
delete_called
=
FALSE
;
delete_call
=
pack
(
0
,
NULL
,
0
,
NULL
);
#endif
}
}
#if defined(MEMTRACE_TO_MEMORY) && defined(USE_ATEXIT_OBJECT)
int
atexit_class
::
counter
=
0
;
int
atexit_class
::
err
=
0
;
#endif
END_NAMESPACE
#endif
memtrace.h
0 → 100644
View file @
1874e6ca
/*********************************
Memoriaszivargas-detektor
Keszitette: Peregi Tamas, BME IIT, 2011
petamas@iit.bme.hu
Kanari: Szeberenyi Imre, 2013.,
VS 2012: Szeberényi Imre, 2015.,
mem_dump: 2016.
inclue-ok: 2017., 2018. 2019.
*********************************/
#ifndef MEMTRACE_H
#define MEMTRACE_H
#if defined(MEMTRACE)
/*ha definiálva van, akkor a hibakat ebbe a fajlba írja, egyébkent stderr-re*/
/*#define MEMTRACE_ERRFILE MEMTRACE.ERR*/
/*ha definialva van, akkor futas kozben lancolt listat epit. Javasolt a hasznalata*/
#define MEMTRACE_TO_MEMORY
/*ha definialva van, akkor futas kozben fajlba irja a foglalasokat*/
/*ekkor nincs ellenorzes, csak naplozas*/
/*#define MEMTRACE_TO_FILE*/
/*ha definialva van, akkor a megallaskor automatikus riport keszul */
#define MEMTRACE_AUTO
/*ha definialva van, akkor malloc()/calloc()/realloc()/free() kovetve lesz*/
#define MEMTRACE_C
#ifdef MEMTRACE_C
/*ha definialva van, akkor free(NULL) nem okoz hibat*/
#define ALLOW_FREE_NULL
#endif
#ifdef __cplusplus
/*ha definialva van, akkor new/delete/new[]/delete[] kovetve lesz*/
#define MEMTRACE_CPP
#endif
#if defined(__cplusplus) && defined(MEMTRACE_TO_MEMORY)
/*ha definialva van, akkor atexit helyett objektumot hasznal*/
/*ajanlott bekapcsolni*/
#define USE_ATEXIT_OBJECT
#endif
/******************************************/
/* INNEN NE MODOSITSD */
/******************************************/
#ifdef NO_MEMTRACE_TO_FILE
#undef MEMTRACE_TO_FILE
#endif
#ifdef NO_MEMTRACE_TO_MEMORY
#undef MEMTRACE_TO_MEMORY
#endif
#ifndef MEMTRACE_AUTO
#undef USE_ATEXIT_OBJECT
#endif
#ifdef __cplusplus
#define START_NAMESPACE namespace memtrace {
#define END_NAMESPACE }
/*namespace*/
#define TRACEC(func) memtrace::func
#include <new>
#else
#define START_NAMESPACE
#define END_NAMESPACE
#define TRACEC(func) func
#endif
// THROW deklaráció változatai
#if defined(_MSC_VER)
// VS rosszul kezeli az __cplusplus makrot
#if _MSC_VER < 1900
// * nem biztos, hogy jó így *
#define THROW_BADALLOC
#define THROW_NOTHING
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#else
#if __cplusplus < 201103L
// C++2003 vagy régebbi
#define THROW_BADALLOC throw (std::bad_alloc)
#define THROW_NOTHING throw ()
#else
// C++11 vagy újabb
#define THROW_BADALLOC noexcept(false)
#define THROW_NOTHING noexcept
#endif
#endif
START_NAMESPACE
int
allocated_blocks
();
END_NAMESPACE
#if defined(MEMTRACE_TO_MEMORY)
START_NAMESPACE
int
mem_check
(
void
);
END_NAMESPACE
#endif
#if defined(MEMTRACE_TO_MEMORY) && defined(USE_ATEXIT_OBJECT)
#include <cstdio>
START_NAMESPACE
class
atexit_class
{
private
:
static
int
counter
;
static
int
err
;
public
:
atexit_class
()
{
#if defined(CPORTA) && !defined(CPORTA_NOSETBUF)
if
(
counter
==
0
)
{
setbuf
(
stdout
,
0
);
setbuf
(
stderr
,
0
);
}
#endif
counter
++
;
}
int
check
()
{
if
(
--
counter
==
0
)
err
=
mem_check
();
return
err
;
}
~
atexit_class
()
{
check
();
}
};
static
atexit_class
atexit_obj
;
END_NAMESPACE
#endif
/*MEMTRACE_TO_MEMORY && USE_ATEXIT_OBJECT*/
/*Innentol csak a "normal" include eseten kell, kulonben osszezavarja a mukodest*/
#ifndef FROM_MEMTRACE_CPP
#include <stdlib.h>
#ifdef __cplusplus
#include <iostream>
/* ide gyűjtjük a nemtrace-vel összeakadó headereket, hogy előbb legyenek */
#include <fstream> // VS 2013 headerjében van deleted definició
#include <sstream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <functional>
#endif
#ifdef MEMTRACE_CPP
namespace
std
{
typedef
void
(
*
new_handler
)();
}
#endif
#ifdef MEMTRACE_C
START_NAMESPACE
#undef malloc
#define malloc(size) TRACEC(traced_malloc)(size,#size,__LINE__,__FILE__)
void
*
traced_malloc
(
size_t
size
,
const
char
*
size_txt
,
int
line
,
const
char
*
file
);
#undef calloc
#define calloc(count,size) TRACEC(traced_calloc)(count, size, #count","#size,__LINE__,__FILE__)
void
*
traced_calloc
(
size_t
count
,
size_t
size
,
const
char
*
size_txt
,
int
line
,
const
char
*
file
);
#undef free
#define free(p) TRACEC(traced_free)(p, #p,__LINE__,__FILE__)
void
traced_free
(
void
*
p
,
const
char
*
size_txt
,
int
line
,
const
char
*
file
);
#undef realloc
#define realloc(old,size) TRACEC(traced_realloc)(old,size,#size,__LINE__,__FILE__)
void
*
traced_realloc
(
void
*
old
,
size_t
size
,
const
char
*
size_txt
,
int
line
,
const
char
*
file
);
void
mem_dump
(
void
const
*
mem
,
size_t
size
,
FILE
*
fp
);
END_NAMESPACE
#endif
/*MEMTRACE_C*/
#ifdef MEMTRACE_CPP
START_NAMESPACE
#undef set_new_handler
#define set_new_handler(f) TRACEC(_set_new_handler)(f)
void
_set_new_handler
(
std
::
new_handler
h
);
void
set_delete_call
(
int
line
,
const
char
*
file
);
END_NAMESPACE
void
*
operator
new
(
size_t
size
,
int
line
,
const
char
*
file
)
THROW_BADALLOC
;
void
*
operator
new
[](
size_t
size
,
int
line
,
const
char
*
file
)
THROW_BADALLOC
;
void
*
operator
new
(
size_t
size
)
THROW_BADALLOC
;
void
*
operator
new
[](
size_t
size
)
THROW_BADALLOC
;
void
operator
delete
(
void
*
p
)
THROW_NOTHING
;
void
operator
delete
[](
void
*
p
)
THROW_NOTHING
;
/* Visual C++ 2012 miatt kell, mert háklis, hogy nincs megfelelő delete, bár senki sem használja */
void
operator
delete
(
void
*
p
,
int
,
const
char
*
)
THROW_NOTHING
;
void
operator
delete
[](
void
*
p
,
int
,
const
char
*
)
THROW_NOTHING
;
#define new new(__LINE__, __FILE__)
#define delete memtrace::set_delete_call(__LINE__, __FILE__),delete
#ifdef CPORTA
#define system(...) // system(__VA_ARGS__)
#endif
#endif
/*MEMTRACE_CPP*/
#endif
/*FROM_MEMTRACE_CPP*/
#endif
/*MEMCHECK*/
#endif
/*MEMTRACE_H*/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment