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
6 years ago
by
Szeberényi Imre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
v0
parents
Show 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
This diff is collapsed.
Click to expand it.
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
This diff is collapsed.
Click to expand it.
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*/
This diff is collapsed.
Click to expand it.
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