1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Create AVal vectors in-place, do not copy

At startup with -O, this change reduces overall memory use by 4%, total
alloc/frees by 70%, and total instructions by 45%.
This commit is contained in:
dmiller
2022-09-13 16:10:05 +00:00
parent 9a494348c5
commit 1d8bf1deff
3 changed files with 98 additions and 84 deletions

View File

@@ -97,7 +97,7 @@ void FingerPrint::sort() {
unsigned int i;
for (i = 0; i < tests.size(); i++)
std::stable_sort(tests[i].results.begin(), tests[i].results.end());
std::stable_sort(tests[i].results->begin(), tests[i].results->end());
std::stable_sort(tests.begin(), tests.end());
}
@@ -178,28 +178,28 @@ static int AVal_match(const FingerTest *reference, const FingerTest *fprint, con
char *endptr;
/* We rely on AVals being sorted by attribute. */
prev_ref = reference->results.end();
prev_fp = fprint->results.end();
current_ref = reference->results.begin();
current_fp = fprint->results.begin();
current_points = points->results.begin();
while (current_ref != reference->results.end()
&& current_fp != fprint->results.end()) {
prev_ref = reference->results->end();
prev_fp = fprint->results->end();
current_ref = reference->results->begin();
current_fp = fprint->results->begin();
current_points = points->results->begin();
while (current_ref != reference->results->end()
&& current_fp != fprint->results->end()) {
int d;
/* Check for sortedness. */
if (prev_ref != reference->results.end())
if (prev_ref != reference->results->end())
assert(*prev_ref < *current_ref);
if (prev_fp != fprint->results.end())
if (prev_fp != fprint->results->end())
assert(*prev_fp < *current_fp);
d = strcmp(current_ref->attribute, current_fp->attribute);
if (d == 0) {
for (; current_points != points->results.end(); current_points++) {
for (; current_points != points->results->end(); current_points++) {
if (strcmp(current_ref->attribute, current_points->attribute) == 0)
break;
}
if (current_points == points->results.end())
if (current_points == points->results->end())
fatal("%s: Failed to find point amount for test %s.%s", __func__, reference->name ? reference->name : "", current_ref->attribute);
errno = 0;
pointsThisTest = strtol(current_points->value, &endptr, 10);
@@ -511,8 +511,8 @@ static int test2str(const FingerTest *test, char *s, const size_t n) {
goto error;
*p++ = '(';
for (av = test->results.begin(); av != test->results.end(); av++) {
if (av != test->results.begin()) {
for (av = test->results->begin(); av != test->results->end(); av++) {
if (av != test->results->begin()) {
if (p + 1 > end)
goto error;
*p++ = '%';
@@ -556,14 +556,14 @@ static const char *strchr_p(const char *str, const char *end, char c) {
return NULL;
}
static std::vector<struct AVal> str2AVal(const char *str, const char *end) {
static std::vector<struct AVal> *str2AVal(const char *str, const char *end) {
int i = 1;
int count = 1;
const char *q = str, *p=str;
std::vector<struct AVal> AVs;
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
if (!*str || str == end)
return std::vector<struct AVal>();
return AVs;
/* count the AVals */
while ((q = strchr_p(q, end, '%'))) {
@@ -571,7 +571,7 @@ static std::vector<struct AVal> str2AVal(const char *str, const char *end) {
q++;
}
AVs.reserve(count);
AVs->reserve(count);
for (i = 0; i < count; i++) {
struct AVal av;
@@ -591,7 +591,7 @@ static std::vector<struct AVal> str2AVal(const char *str, const char *end) {
av.value = string_pool_substr(p, end);
}
p = q + 1;
AVs.push_back(av);
AVs->push_back(av);
}
return AVs;
@@ -603,13 +603,13 @@ static std::vector<struct AVal> str2AVal(const char *str, const char *end) {
static bool test_match_literal(const FingerTest *a, const FingerTest *b) {
std::vector<struct AVal>::const_iterator ia, ib;
for (ia = a->results.begin(), ib = b->results.begin();
ia != a->results.end() && ib != b->results.end();
for (ia = a->results->begin(), ib = b->results->begin();
ia != a->results->end() && ib != b->results->end();
ia++, ib++) {
if (strcmp(ia->attribute, ib->attribute) != 0)
return false;
}
if (ia != a->results.end() || ib != b->results.end())
if (ia != a->results->end() || ib != b->results->end())
return false;
return true;

View File

@@ -125,7 +125,12 @@ struct FingerMatch {
struct FingerTest {
const char *name;
std::vector<struct AVal> results;
std::vector<struct AVal> *results;
FingerTest() : name(NULL), results(NULL) {}
~FingerTest() {
// name is allocated from string_pool
// results freed via ~FingerPrint()
}
bool operator<(const FingerTest& other) const {
return strcmp(name, other.name) < 0;
}
@@ -135,6 +140,13 @@ struct FingerPrint {
FingerMatch match;
std::vector<FingerTest> tests;
FingerPrint();
~FingerPrint() {
for (std::vector<FingerTest>::iterator t = this->tests.begin();
t != this->tests.end(); t++) {
if (t->results)
delete t->results;
}
}
void sort();
};
/* This structure contains the important data from the fingerprint
@@ -185,7 +197,6 @@ void match_fingerprint(const FingerPrint *FP, FingerPrintResultsIPv4 *FPR,
/* Returns true if perfect match -- if num_subtests & num_subtests_succeeded are non_null it updates them. if shortcircuit is zero, it does all the tests, otherwise it returns when the first one fails */
void freeFingerPrint(FingerPrint *FP);
void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP,
const char *engine_id,
const struct sockaddr_storage *addr, int distance,

View File

@@ -2051,12 +2051,12 @@ void HostOsScan::makeFP(HostOsScanStats *hss) {
hss->FPtests[i] = new FingerTest;
AV.attribute = "R";
AV.value = "N";
hss->FPtests[i]->results.push_back(AV);
hss->FPtests[i]->results->push_back(AV);
hss->FPtests[i]->name = (i == 3)? "ECN" : (i == 4)? "T1" : (i == 5)? "T2" : (i == 6)? "T3" : (i == 7)? "T4" : (i == 8)? "T5" : (i == 9)? "T6" : (i == 10)? "T7" : (i == 11)? "U1" : "IE";
}
else if (hss->FPtests[i]) {
/* Replace TTL with initial TTL. */
for (it = hss->FPtests[i]->results.begin(); it != hss->FPtests[i]->results.end(); it++) {
for (it = hss->FPtests[i]->results->begin(); it != hss->FPtests[i]->results->end(); it++) {
if (strcmp(it->attribute, "T") == 0) {
/* Found TTL item. The value for this attribute is the
* received TTL encoded in decimal. We replace it with the
@@ -2312,11 +2312,11 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
int good_tcp_ipid_num, good_tcp_closed_ipid_num, good_icmp_ipid_num;
int tsnewval = 0;
std::vector<struct AVal> seq_AVs;
std::vector<struct AVal> *seq_AVs = new std::vector<struct AVal>;
struct AVal AV;
/* Need 8 AVals for SP, GCD, ISR, TI, CI, II, SS, TS. */
seq_AVs.reserve(8);
seq_AVs->reserve(8);
/* Now we make sure there are no gaps in our response array ... */
for (i = 0, j = 0; i < NUM_SEQ_SAMPLES; i++) {
@@ -2399,13 +2399,13 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
AV.attribute = "SP";
AV.value = string_pool_sprintf("%X", hss->si.index);
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
AV.attribute = "GCD";
AV.value = string_pool_sprintf("%X", seq_gcd);
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
AV.attribute = "ISR";
AV.value = string_pool_sprintf("%X", (unsigned int) seq_rate);
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
} else if (hss->si.responses > 0) {
if (o.debugging)
log_write(LOG_PLAIN, "Insufficient responses from %s for TCP sequencing (%d), OS detection may be less accurate\n", hss->target->targetipstr(), hss->si.responses);
@@ -2461,11 +2461,11 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
/* This fills in TI=Z or something like that. */
if (make_aval_ipid_seq(&AV, "TI", tcp_ipid_seqclass, hss->ipid.tcp_ipids) != NULL)
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
if (make_aval_ipid_seq(&AV, "CI", tcp_closed_ipid_seqclass, hss->ipid.tcp_closed_ipids) != NULL)
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
if (make_aval_ipid_seq(&AV, "II", icmp_ipid_seqclass, hss->ipid.icmp_ipids) != NULL)
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
/* SS: Shared IP ID sequence boolean */
if ((tcp_ipid_seqclass == IPID_SEQ_INCR ||
@@ -2483,7 +2483,7 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
} else {
AV.value = "O";
}
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
}
/* Now we look at TCP Timestamp sequence prediction */
@@ -2541,7 +2541,7 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
case TS_SEQ_ZERO:
AV.attribute = "TS";
AV.value = "0";
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
break;
case TS_SEQ_2HZ:
case TS_SEQ_100HZ:
@@ -2571,28 +2571,30 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
}
AV.value = string_pool_sprintf("%X", tsnewval);
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
break;
case TS_SEQ_UNSUPPORTED:
AV.attribute = "TS";
AV.value = "U";
seq_AVs.push_back(AV);
seq_AVs->push_back(AV);
break;
}
/* Now generate the SEQ line of the fingerprint if there are any test results
in seq_AVs. */
if (!seq_AVs.empty()) {
if (!seq_AVs->empty()) {
hss->FP_TSeq = new FingerTest;
hss->FP_TSeq->name = "SEQ";
hss->FP_TSeq->results = seq_AVs;
}
else {
delete seq_AVs;
}
}
void HostOsScan::makeTOpsFP(HostOsScanStats *hss) {
assert(hss);
std::vector<struct AVal> AVs;
int i, n;
if (hss->TOpsReplyNum != 6)
@@ -2608,10 +2610,11 @@ void HostOsScan::makeTOpsFP(HostOsScanStats *hss) {
return;
}
AVs.reserve(n);
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
AVs->reserve(n);
for (i = 0; i < n; i++)
AVs.push_back(*hss->TOps_AVs[i]);
AVs->push_back(*hss->TOps_AVs[i]);
hss->FP_TOps = new FingerTest;
hss->FP_TOps->results = AVs;
@@ -2621,7 +2624,6 @@ void HostOsScan::makeTOpsFP(HostOsScanStats *hss) {
void HostOsScan::makeTWinFP(HostOsScanStats *hss) {
assert(hss);
std::vector<struct AVal> AVs;
int i, n;
if (hss->TWinReplyNum != 6)
@@ -2637,10 +2639,11 @@ void HostOsScan::makeTWinFP(HostOsScanStats *hss) {
return;
}
AVs.reserve(n);
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
AVs->reserve(n);
for (i = 0; i < n; i++)
AVs.push_back(*hss->TWin_AVs[i]);
AVs->push_back(*hss->TWin_AVs[i]);
hss->FP_TWin = new FingerTest;
hss->FP_TWin->results = AVs;
@@ -2796,7 +2799,6 @@ bool HostOsScan::processTWinResp(HostOsScanStats *hss, const struct tcp_hdr *tcp
bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
std::vector<struct AVal> AVs;
struct AVal AV;
char ops_buf[256];
char quirks_buf[10];
@@ -2809,11 +2811,12 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
return false;
/* Create the Avals */
AVs.reserve(numtests);
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
AVs->reserve(numtests);
AV.attribute = "R";
AV.value = "Y";
AVs.push_back(AV);
AVs->push_back(AV);
/* don't frag flag */
AV.attribute = "DF";
@@ -2821,17 +2824,17 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "Y";
else
AV.value = "N";
AVs.push_back(AV);
AVs->push_back(AV);
/* TTL */
AV.attribute = "T";
AV.value = string_pool_sprintf("%d", ip->ip_ttl);
AVs.push_back(AV);
AVs->push_back(AV);
/* TCP Window size */
AV.attribute = "W";
AV.value = string_pool_sprintf("%hX", ntohs(tcp->th_win));
AVs.push_back(AV);
AVs->push_back(AV);
/* Now for the TCP options ... */
AV.attribute = "O";
@@ -2844,7 +2847,7 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
}
AV.value = string_pool_insert(ops_buf);
AVs.push_back(AV);
AVs->push_back(AV);
/* Explicit Congestion Notification support test */
AV.attribute = "CC";
@@ -2859,7 +2862,7 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "N";
else
AV.value = "O";
AVs.push_back(AV);
AVs->push_back(AV);
/* TCP miscellaneous quirks test */
AV.attribute = "Q";
@@ -2876,7 +2879,7 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
}
*p = '\0';
AV.value = string_pool_insert(quirks_buf);
AVs.push_back(AV);
AVs->push_back(AV);
hss->FP_TEcn = new FingerTest;
hss->FP_TEcn->name = "ECN";
@@ -2887,7 +2890,6 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int replyNo) {
std::vector<struct AVal> AVs;
struct AVal AV;
assert(replyNo >= 0 && replyNo < 7);
@@ -2909,13 +2911,14 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
else numtests = 10;
/* Create the Avals */
AVs.reserve(numtests);
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
AVs->reserve(numtests);
/* First we give the "response" flag to say we did actually receive
a packet -- this way we won't match a template with R=N */
AV.attribute = "R";
AV.value = "Y";
AVs.push_back(AV);
AVs->push_back(AV);
/* Next we check whether the Don't Fragment bit is set */
AV.attribute = "DF";
@@ -2923,18 +2926,18 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
AV.value = "Y";
else
AV.value = "N";
AVs.push_back(AV);
AVs->push_back(AV);
/* TTL */
AV.attribute = "T";
AV.value = string_pool_sprintf("%d", ip->ip_ttl);
AVs.push_back(AV);
AVs->push_back(AV);
if (replyNo != 0) {
/* Now we do the TCP Window size */
AV.attribute = "W";
AV.value = string_pool_sprintf("%hX", ntohs(tcp->th_win));
AVs.push_back(AV);
AVs->push_back(AV);
}
/* Seq test values:
@@ -2952,7 +2955,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
AV.value = "A+";
else
AV.value = "O";
AVs.push_back(AV);
AVs->push_back(AV);
/* ACK test values:
Z = zero
@@ -2969,7 +2972,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
AV.value = "S+";
else
AV.value = "O";
AVs.push_back(AV);
AVs->push_back(AV);
/* Flags. They must be in this order:
E = ECN Echo
@@ -3001,7 +3004,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
}
*p = '\0';
AV.value = string_pool_insert(flags_buf);
AVs.push_back(AV);
AVs->push_back(AV);
if (replyNo != 0) {
char ops_buf[256];
@@ -3016,7 +3019,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
}
AV.value = string_pool_insert(ops_buf);
AVs.push_back(AV);
AVs->push_back(AV);
}
/* Rst Data CRC32 */
@@ -3027,7 +3030,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
} else {
AV.value = "0";
}
AVs.push_back(AV);
AVs->push_back(AV);
/* TCP miscellaneous quirks test */
AV.attribute = "Q";
@@ -3044,7 +3047,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
}
*p = '\0';
AV.value = string_pool_insert(quirks_buf);
AVs.push_back(AV);
AVs->push_back(AV);
hss->FPtests[FP_T1_7_OFF + replyNo] = new FingerTest;
hss->FPtests[FP_T1_7_OFF + replyNo]->results = AVs;
@@ -3055,7 +3058,6 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
std::vector<struct AVal> AVs;
struct AVal AV;
assert(hss);
@@ -3094,12 +3096,13 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
}
/* Create the Avals */
AVs.reserve(numtests);
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
AVs->reserve(numtests);
/* First of all, if we got this far the response was yes */
AV.attribute = "R";
AV.value = "Y";
AVs.push_back(AV);
AVs->push_back(AV);
/* Also, we now know that the port we reached was closed */
if (hss->target->FPR->osscan_closedudpport == -1)
@@ -3111,23 +3114,23 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "Y";
else
AV.value = "N";
AVs.push_back(AV);
AVs->push_back(AV);
/* TTL */
AV.attribute = "T";
AV.value = string_pool_sprintf("%d", ip->ip_ttl);
AVs.push_back(AV);
AVs->push_back(AV);
/* Now we look at the IP datagram length that was returned, some
machines send more of the original packet back than others */
AV.attribute = "IPL";
AV.value = string_pool_sprintf("%hX", ntohs(ip->ip_len));
AVs.push_back(AV);
AVs->push_back(AV);
/* unused filed not zero in Destination Unreachable Message */
AV.attribute = "UN";
AV.value = string_pool_sprintf("%hX", ntohl(icmp->icmp_void));
AVs.push_back(AV);
AVs->push_back(AV);
/* OK, lets check the returned IP length, some systems @$@ this
up */
@@ -3136,7 +3139,7 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "G";
else
AV.value = string_pool_sprintf("%hX", ntohs(ip2->ip_len));
AVs.push_back(AV);
AVs->push_back(AV);
/* This next test doesn't work on Solaris because the lamers
overwrite our ip_id */
@@ -3148,7 +3151,7 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "G"; /* The good "expected" value */
else
AV.value = string_pool_sprintf("%hX", ntohs(ip2->ip_id));
AVs.push_back(AV);
AVs->push_back(AV);
#endif
@@ -3171,7 +3174,7 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
}
*checksumptr = checksum;
}
AVs.push_back(AV);
AVs->push_back(AV);
/* UDP checksum */
AV.attribute = "RUCK";
@@ -3179,7 +3182,7 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "G"; /* The "expected" good value */
else
AV.value = string_pool_sprintf("%hX", ntohs(udp->uh_sum));
AVs.push_back(AV);
AVs->push_back(AV);
/* Finally we ensure the data is OK */
datastart = ((unsigned char *)udp) + 8;
@@ -3195,7 +3198,7 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
AV.value = "I"; /* They modified it */
else
AV.value = "G";
AVs.push_back(AV);
AVs->push_back(AV);
hss->FP_TUdp = new FingerTest;
hss->FP_TUdp->name = "U1";
@@ -3213,7 +3216,6 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int replyNo) {
assert(replyNo == 0 || replyNo == 1);
std::vector<struct AVal> AVs;
struct AVal AV;
int numtests = 4;
const struct ip *ip1, *ip2;
@@ -3249,11 +3251,12 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int
assert(icmp1->icmp_type == 0 && icmp2->icmp_type == 0);
/* Create the Avals */
AVs.reserve(numtests);
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
AVs->reserve(numtests);
AV.attribute = "R";
AV.value = "Y";
AVs.push_back(AV);
AVs->push_back(AV);
/* DFI test values:
* Y. Both set DF;
@@ -3275,13 +3278,13 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int
AV.value = "N";
else
AV.value = "O";
AVs.push_back(AV);
AVs->push_back(AV);
/* TTL */
AV.attribute = "T";
AV.value = string_pool_sprintf("%d", ip1->ip_ttl);
AVs.push_back(AV);
AVs->push_back(AV);
/* ICMP Code value. Test values:
* [Value]. Both set Code to the same value [Value];
@@ -3302,7 +3305,7 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int
AV.value = "S";
else
AV.value = "O";
AVs.push_back(AV);
AVs->push_back(AV);
hss->FP_TIcmp= new FingerTest;
hss->FP_TIcmp->name = "IE";