Skip to content

Commit d6fb40f

Browse files
committed
Adding tests for static initializers, and a fix that avoids false positives from C++ statics
1 parent 46f87d3 commit d6fb40f

16 files changed

Lines changed: 712 additions & 47 deletions

setup/version.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11

2-
#define VLDVERSION L"2.5.5"
3-
#define VERSION_NUMBER 2,5,5,0
4-
#define VERSION_STRING "2.5.5.0"
2+
#define VLDVERSION L"2.5.6"
3+
#define VERSION_NUMBER 2,5,6,0
4+
#define VERSION_STRING "2.5.6.0"
55
#define VERSION_COPYRIGHT "Copyright (C) 2005-2020"
66

77
#ifndef __FILE__
8-
!define VLD_VERSION "2.5.5" // NSIS Script
8+
!define VLD_VERSION "2.5.6" // NSIS Script
99
#endif

setup/vld-setup.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
33

44
#define MyAppName "Visual Leak Detector"
5-
#define MyAppVersion "2.5.5"
5+
#define MyAppVersion "2.5.6"
66
#define MyAppPublisher "VLD Team"
77
#define MyAppURL "http://vld.codeplex.com/"
88
#define MyAppRegKey "Software\Visual Leak Detector"

src/callstack.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,26 @@ UINT CallStack::isCrtStartupFunction( LPCWSTR functionName ) const
546546
}
547547

548548
if (endWith(functionName, len, L"DllMainCRTStartup")
549-
|| endWith(functionName, len, L"mainCRTStartup")
550-
|| beginWith(functionName, len, L"`dynamic initializer for '")) {
549+
|| endWith(functionName, len, L"mainCRTStartup")
550+
551+
// NOTE: This is tricky...
552+
// This happens for c++ static initialization
553+
// In some cases, we will see
554+
// "namespace::`dynamic initializer for 'symbol'"
555+
// In other cases, there is no namespace prepended, even if the symbol is in a namespace:
556+
// "`dynamic initializer for 'namespace::symbol'"
557+
// This happens above initterm in the stack, which means these statics can be ignored by the code above if they have the namespace
558+
559+
// Ideally, we would ignore dynamic initializers if we (somehow) know there is also a matching "`dynamic atexit destructor for 'symbol'"
560+
// It's possible to use some kind of heuristic to detect this (the stack will have ..., classname::classname, dynamic initializer for, initterm, ...)
561+
// That means that the caller really needs a state machine as we are doing some context-sensitive parsing
562+
563+
// For now, we just make the (possibly wrong) assumption that all dynamic initializations will be cleaned up
564+
// Therefore, the following line is commented out.
565+
// Clearly wrong when we have a global written as "static void* foo = malloc(1);"
566+
// But we can look at a more complex fix if we need to handle that
567+
//|| beginWith(functionName, len, L"`dynamic initializer for '")
568+
) {
551569
// When we reach this point there is no reason going further down the stack
552570
return CALLSTACK_STATUS_NOTSTARTUPCRT;
553571
}

src/runtests.bat

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ ECHO ---------------------------------------------------------------------------
3030
ECHO [ RUNNING ] %tests_path%\vld_main_test.exe
3131
ECHO -------------------------------------------------------------------------------
3232
!tests_path!\vld_main_test.exe --gtest_output="xml:!tests_path!\vld_main_test.exe.xml"
33+
ECHO -------------------------------------------------------------------------------
34+
ECHO [ RUNNING ] %tests_path%\static_string_test.exe
35+
ECHO -------------------------------------------------------------------------------
36+
!tests_path!\static_string_test.exe --gtest_output="xml:!tests_path!\static_string_test.exe.xml"
3337
ECHO -------------------------------------------------------------------------------
3438
EXIT /b 0
3539

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
namespace my_string
6+
{
7+
const std::string the_string("foobar");
8+
}
9+
10+
const std::string string_global("xyz1234567");
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// static_string_test.cpp : Defines the entry point for the console application.
2+
//
3+
4+
#include "stdafx.h"
5+
#include "vld.h"
6+
#include "static_string.h"
7+
8+
void access_strings()
9+
{
10+
// Just do something with the string so it isn't optimized away
11+
std::string copied_string = my_string::the_string;
12+
printf("Copied string %s\n", copied_string.c_str());
13+
14+
std::string copied_string2 = string_global;
15+
printf("Copied string %s\n", copied_string2.c_str());
16+
}
17+
18+
int main(int argc, char **argv)
19+
{
20+
access_strings();
21+
22+
int leaks = static_cast<int>(VLDGetLeaksCount());
23+
if (0 != leaks)
24+
{
25+
printf("!!! FAILED - Leaks detected: %i\n", leaks);
26+
VLDReportLeaks();
27+
}
28+
else
29+
{
30+
printf("PASSED\n");
31+
}
32+
33+
34+
return leaks;
35+
}

0 commit comments

Comments
 (0)