Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux machines have indirect memory leak errors #205

Closed
nip5 opened this issue Jul 3, 2018 · 22 comments
Closed

Linux machines have indirect memory leak errors #205

nip5 opened this issue Jul 3, 2018 · 22 comments

Comments

@nip5
Copy link
Contributor

nip5 commented Jul 3, 2018

Linux machines have indirect memory leak errors when the environment variable ASAN_OPTIONS='detect_leaks=1'. Thus the temporary solution is to instead run with that variable set to 0. An instance of these errors:

Indirect leak of 232 byte(s) in 1 object(s) allocated from:
    #0 0x7f5d765d5602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x4a7a68 in Mem_Malloc(unsigned long, char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/mymemory.c:104
    #2 0x4a7b0f in Mem_Calloc(unsigned long, unsigned long, char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/mymemory.c:154
    #3 0x4ad922 in _newlayer() /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Site.c:187
    #4 0x4b27ca in _read_layers /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Site.c:553
    #5 0x4afd31 in SW_SIT_read() /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Site.c:420
    #6 0x4a28ed in SW_CTL_read_inputs_from_disk() /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Control.c:226
    #7 0x4a29ad in SW_CTL_obtain_inputs() /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Control.c:255
    #8 0x408007 in Reset_SOILWAT2_after_UnitTest() test/sw_testhelpers.cc:45
    #9 0x40970c in TestBody test/test_SW_Carbon.cc:125
    #10 0x49246a in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x49246a)
    #11 0x48c702 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x48c702)
    #12 0x46ca6b in testing::Test::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46ca6b)
    #13 0x46d3c3 in testing::TestInfo::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46d3c3)
    #14 0x46da2e in testing::TestCase::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46da2e)
    #15 0x477ea3 in testing::internal::UnitTestImpl::RunAllTests() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x477ea3)
    #16 0x4933be in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x4933be)
    #17 0x48d530 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x48d530)
    #18 0x47694f in testing::UnitTest::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x47694f)
    #19 0x407fc6 in RUN_ALL_TESTS() googletest/googletest/include/gtest/gtest.h:2329
    #20 0x407d6d in main test/sw_maintest.cc:81
    #21 0x7f5d749c882f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

@nip5 nip5 added the bug label Jul 3, 2018
@nip5 nip5 added this to the Code testing milestone Jul 3, 2018
dschlaep added a commit that referenced this issue Jul 3, 2018
- addressing #205

- added call to `SW_CTL_clear_model` before re-initializing SOILWAT2
- this is similar behavior to updated functions `start` of `rSOILWAT2` and `SXW_Reset` of `STEPWAT2`
@dschlaep
Copy link
Member

dschlaep commented Jul 3, 2018

I tried to replicate with valgrind because ASAN_OPTIONS='detect_leaks=1' isn't implemented on my platform. I run

make cleaner testci
valgrind -v --track-origins=yes --leak-check=full ./sw_test

It throws a segmentation fault at the first death test. I wonder whether the combination of macOS X, valgrind, and DEATH gtests doesn't work.

Before the segfault, I see a whole lot of

  • Conditional jump or move depends on uninitialised value(s) and Invalid read of size 8 emitted for gtest code
  • bytes in 1 blocks are definitely lost in loss record emitted for calls to localtime() and gtest's NoExecDeathTest

@dschlaep
Copy link
Member

dschlaep commented Jul 3, 2018

@nip5 Thanks for posting this issue! Did commit f69c303 do anything for you?

@nip5
Copy link
Contributor Author

nip5 commented Jul 3, 2018

Yes, it did not fix the issue entirely but it did make it significantly better as with master I get:
SUMMARY: AddressSanitizer: 1466719 byte(s) leaked in 1801 allocation(s).

and in the new branch after the commit I'm getting:
SUMMARY: AddressSanitizer: 448 byte(s) leaked in 7 allocation(s).

@dschlaep
Copy link
Member

dschlaep commented Jul 3, 2018

Nice; this is a good improvement! Could you please post (or send by email) what the remaining leaks are?

@nip5
Copy link
Contributor Author

nip5 commented Jul 3, 2018

Direct leak of 256 byte(s) in 4 object(s) allocated from:
    #0 0x7fad6777f602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x4a7a72 in Mem_Malloc(unsigned long, char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/mymemory.c:104
    #2 0x4a7b19 in Mem_Calloc(unsigned long, unsigned long, char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/mymemory.c:154
    #3 0x4dcb3c in SW_VPD_construct() /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_VegProd.c:636
    #4 0x4a2301 in SW_CTL_init_model(char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Control.c:88
    #5 0x40800c in Reset_SOILWAT2_after_UnitTest() test/sw_testhelpers.cc:46
    #6 0x455b39 in TestBody test/test_SW_SoilWater.cc:124
    #7 0x492474 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x492474)
    #8 0x48c70c in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x48c70c)
    #9 0x46ca75 in testing::Test::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46ca75)
    #10 0x46d3cd in testing::TestInfo::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46d3cd)
    #11 0x46da38 in testing::TestCase::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46da38)
    #12 0x477ead in testing::internal::UnitTestImpl::RunAllTests() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x477ead)
    #13 0x4933c8 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x4933c8)
    #14 0x48d53a in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x48d53a)
    #15 0x476959 in testing::UnitTest::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x476959)
    #16 0x407fc6 in RUN_ALL_TESTS() googletest/googletest/include/gtest/gtest.h:2329
    #17 0x407d6d in main test/sw_maintest.cc:81
    #18 0x7fad65b7282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

Direct leak of 192 byte(s) in 3 object(s) allocated from:
    #0 0x7fad6777f602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x4a7a72 in Mem_Malloc(unsigned long, char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/mymemory.c:104
    #2 0x4a7b19 in Mem_Calloc(unsigned long, unsigned long, char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/mymemory.c:154
    #3 0x4dcc16 in SW_VPD_construct() /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_VegProd.c:639
    #4 0x4a2301 in SW_CTL_init_model(char const*) /home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/SW_Control.c:88
    #5 0x40800c in Reset_SOILWAT2_after_UnitTest() test/sw_testhelpers.cc:46
    #6 0x455b39 in TestBody test/test_SW_SoilWater.cc:124
    #7 0x492474 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x492474)
    #8 0x48c70c in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x48c70c)
    #9 0x46ca75 in testing::Test::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46ca75)
    #10 0x46d3cd in testing::TestInfo::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46d3cd)
    #11 0x46da38 in testing::TestCase::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x46da38)
    #12 0x477ead in testing::internal::UnitTestImpl::RunAllTests() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x477ead)
    #13 0x4933c8 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x4933c8)
    #14 0x48d53a in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x48d53a)
    #15 0x476959 in testing::UnitTest::Run() (/home/natemccauslin/Desktop/DryLand Ecology/SOILWAT2/sw_test+0x476959)
    #16 0x407fc6 in RUN_ALL_TESTS() googletest/googletest/include/gtest/gtest.h:2329
    #17 0x407d6d in main test/sw_maintest.cc:81
    #18 0x7fad65b7282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

@dschlaep
Copy link
Member

dschlaep commented Jul 3, 2018

Thanks for posting. Lines 636 and 639 of function SW_VPD_construct are

	ForEachOutPeriod(pd)
	{
		SW_VegProd.p_accu[pd] = (SW_VEGPROD_OUTPUTS *) Mem_Calloc(1,
			sizeof(SW_VEGPROD_OUTPUTS), "SW_VPD_construct()");
		if (pd > eSW_Day) {
			SW_VegProd.p_oagg[pd] = (SW_VEGPROD_OUTPUTS *) Mem_Calloc(1,
				sizeof(SW_VEGPROD_OUTPUTS), "SW_VPD_construct()");
		}
	}

This memory should be freed by function SW_VPD_deconstruct with

	ForEachOutPeriod(pd)
	{
		if (pd > eSW_Day && !isnull(SW_VegProd.p_oagg[pd])) {
			Mem_Free(SW_VegProd.p_oagg[pd]);
			SW_VegProd.p_oagg[pd] = NULL;
		}

		if (!isnull(SW_VegProd.p_accu[pd])) {
			Mem_Free(SW_VegProd.p_accu[pd]);
			SW_VegProd.p_accu[pd] = NULL;
		}
	}

@nip5 Any idea what I am missing?

@nip5
Copy link
Contributor Author

nip5 commented Jul 3, 2018

Not from what I can see, SW_VPD_deconstruct looks good, the conditionals are being accessed how we expect, memory errors are tricky.

@nip5
Copy link
Contributor Author

nip5 commented Jul 3, 2018

It doesn't look like the code ever enters the line 127 conditional in mymemory.c, so p is never freed in memory. I think that may be the problem:

if (!fCreateBlockInfo(p, size)) {
			free( p); /* same argument as for memset() */
			p = NULL;
		}

@dschlaep
Copy link
Member

dschlaep commented Jul 3, 2018

Hm, I'm not sure. The code lines if (!fCreateBlockInfo(p, size)) { etc. are wrapped in #ifdef DEBUG_MEM, i.e., they are not compiled in our use. The DEBUG_MEM functionality is in the code from someone well before my time.

@nip5
Copy link
Contributor Author

nip5 commented Jul 3, 2018

But isn't it allocated outside of the ifdefs, so it always allocates but only sometimes deallocates? For instance it is allocated here:

#endif

	p = malloc(size);
#ifdef DEBUG_MEM_LOG

@dschlaep
Copy link
Member

dschlaep commented Jul 3, 2018

The function SW_CTL_clear_model() attempts to deallocate everything that got allocated.

For instance, SW_VPD_construct calls Mem_Calloc which calls Mem_Malloc which does the allocation with p = malloc(size); (line 104 in file mymemory.c).
This is intended to be balanced by SW_VPD_deconstruct which calls Mem_Free which deallocates with free(block); (line 263 in file mymemory.c).

Where do you see missing deallocations?

@nip5
Copy link
Contributor Author

nip5 commented Jul 5, 2018

SW_VPD_deconstruct and SW_VPD_construct seem to balance each other out but does that also free p?

@dschlaep
Copy link
Member

dschlaep commented Jul 5, 2018

I don't understand your question because *p is a local variable and does not need to be freed.

The function Mem_Malloc defines the local variable *p, i.e., static memory allocation "on the stack" (see, e.g., https://stackoverflow.com/questions/33087070/dynamically-allocated-memory-storage-clarification?noredirect=1&lq=1); the memory allocated by the call p = malloc(size); -- the address of which is assigned to *p which is returned by the function Mem_Malloc --, however, is dynamically allocated "on the heap". It is this memory that does need to be freed; this is done by the call to free() via the function Mem_Free which is called, in above example, by SW_VPD_deconstruct.

Please describe your point/question in greater detail.

@nip5
Copy link
Contributor Author

nip5 commented Jul 5, 2018

Your last point is what I meant, in that p is allocated onto the heap so we need free it and I didn't see that being done. I saw that 'SW_VegProd.p_oagg [pd]' is being freed but I missed that 'SW_VegProd.p_oagg [pd]' is set as the returned p in the contruction function.

@dschlaep
Copy link
Member

dschlaep commented Jul 5, 2018

Ok, good. So you agree with my earlier comment (#205 (comment)) that it is not obvious why the address sanitizer detects a leak in SW_VPD_construct -- its memory allocation appears to be completely balanced/de-allocated by SW_VPD_deconstruct?

@nip5
Copy link
Contributor Author

nip5 commented Jul 5, 2018

Yes, they look balanced to me.

@dschlaep
Copy link
Member

dschlaep commented Jul 5, 2018

Do you have any other idea/suggestion what to look at for this issue? If not, we just let it sit for a while and revisit at some later time? Thanks for your work and interactions over the last days to solve several memory issues!!

@nip5
Copy link
Contributor Author

nip5 commented Jul 5, 2018

I did have an idea but I just investigated it and it wasn't the problem either! The memory issues don't crash the program now even with the flag set to address sanitize on so we could revisit it at a later date. No problem, every time I have to try and work through stuff like this I end up grasping concepts better so I enjoy it.

@dschlaep
Copy link
Member

dschlaep commented Jul 9, 2018

Merge progress made so far on branch bugfix_205_TestsMemoryLeaks into master (PR #207) and revisit issue at a later time.

@dschlaep
Copy link
Member

This shows up on travis-ci if compiled with clang v5.0.0 (but not with g++ v4.9): https://travis-ci.org/DrylandEcology/SOILWAT2/jobs/403549752 for commit c64758a and only for
make clean test_severe test_run but not for make bin_debug_severe bint_run

Direct leak of 256 byte(s) in 4 object(s) allocated from:
    #0 0x4c7b93 in __interceptor_malloc /local/mnt/workspace/tmp/ubuntu_rel/llvm/utils/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:67:3
    #1 0x5dcd31 in Mem_Malloc /home/travis/build/DrylandEcology/SOILWAT2/mymemory.c:104:6
    #2 0x5dce04 in Mem_Calloc /home/travis/build/DrylandEcology/SOILWAT2/mymemory.c:154:6
    #3 0x669471 in SW_VPD_construct /home/travis/build/DrylandEcology/SOILWAT2/SW_VegProd.c:636:50
    #4 0x5d2526 in SW_CTL_init_model /home/travis/build/DrylandEcology/SOILWAT2/SW_Control.c:88:2
    #5 0x4f5af1 in Reset_SOILWAT2_after_UnitTest() /home/travis/build/DrylandEcology/SOILWAT2/test/sw_testhelpers.cc:46:3
    #6 0x57c88f in (anonymous namespace)::SWSoilWaterTest_SWSWPmatric2VWCBulk_Test::TestBody() /home/travis/build/DrylandEcology/SOILWAT2/test/test_SW_SoilWater.cc:124:5
...

and

Direct leak of 192 byte(s) in 3 object(s) allocated from:
    #0 0x4c7b93 in __interceptor_malloc /local/mnt/workspace/tmp/ubuntu_rel/llvm/utils/release/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:67:3
    #1 0x5dcd31 in Mem_Malloc /home/travis/build/DrylandEcology/SOILWAT2/mymemory.c:104:6
    #2 0x5dce04 in Mem_Calloc /home/travis/build/DrylandEcology/SOILWAT2/mymemory.c:154:6
    #3 0x6695b8 in SW_VPD_construct /home/travis/build/DrylandEcology/SOILWAT2/SW_VegProd.c:639:51
    #4 0x5d2526 in SW_CTL_init_model /home/travis/build/DrylandEcology/SOILWAT2/SW_Control.c:88:2
    #5 0x4f5af1 in Reset_SOILWAT2_after_UnitTest() /home/travis/build/DrylandEcology/SOILWAT2/test/sw_testhelpers.cc:46:3
    #6 0x57c88f in (anonymous namespace)::SWSoilWaterTest_SWSWPmatric2VWCBulk_Test::TestBody() /home/travis/build/DrylandEcology/SOILWAT2/test/test_SW_SoilWater.cc:124:5
...

dschlaep added a commit that referenced this issue Jul 13, 2018
- use suppression file on `travis-ci` for severe testing target
- address #205 (but not fixed)
@dschlaep
Copy link
Member

dschlaep commented Jul 13, 2018

To exclude known memory leaks from severe testing without disabling leak detection altogether:
ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=suppressions=.LSAN_suppr.txt make clean test_severe test_run

This reports on travis-ci:

Suppressions used:
  count      bytes template
      7        448 SW_VPD_construct

dschlaep added a commit that referenced this issue Jul 17, 2018
Better compilation and use in rSOILWAT2

we have three documented and suppressed/ignored problems:
- memory leak (use of a suppression file): #205
- compile warning #208: treating c input as c++
- compile warning #214: variable array length
@dschlaep
Copy link
Member

another way to see this memory leak

make test
MallocStackLogging=1 MallocStackLoggingNoCompact=1 MallocScribble=1 MallocPreScribble=1 MallocCheckHeapStart=0 MallocCheckHeapEach=0 leaks -quiet -atExit -- bin/sw_test

7 leaks for 896 total leaked bytes.
7 (896 bytes) << TOTAL >>
1 (128 bytes) ROOT LEAK: 0x600000cb0100 [128]
1 (128 bytes) ROOT LEAK: 0x600000cb0180 [128]
1 (128 bytes) ROOT LEAK: 0x600000cb0200 [128]
1 (128 bytes) ROOT LEAK: 0x600000cb0280 [128]
1 (128 bytes) ROOT LEAK: 0x600000cb0300 [128]
1 (128 bytes) ROOT LEAK: 0x600000cb0380 [128]
1 (128 bytes) ROOT LEAK: 0x600000cb0400 [128]

@dschlaep dschlaep self-assigned this Jul 18, 2023
dschlaep added a commit that referenced this issue Jul 20, 2023
Feature memory fixes

- fix memory issues (close #205, close #356)
- `SW_SIT_init_run()` does not need argument `PATH_INFO *PathInfo`
- Reorganized tests
    - only use test fixtures where really needed
    - do not use test fixtures in death tests
    - new class "AllTestStruct" that behaves just like "AllTestFixture" but does not inherit from `::testing::Test` -- which can be used in death tests
    - place all relevant code inside `EXPECT_DEATH` in a compound statement -- code will otherwise be run twice (including the creation of test fixtures or constructing of a local copy of "AllTestStruct")
 - tool "check_SOILWAT2.sh" now runs additional steps with the `leaks` command
dschlaep added a commit that referenced this issue Aug 4, 2023
Development for v7.1.0

* Simulation output remains the same as the previous version.

* Prepare for SOILWAT2 to become thread-safe and reentrant (#346; @N1ckP3rsl3y)
    * Definition clarifications
        * Thread-safe - Multiple threads (a future SOILWAT2 development)
          will not influence each other unintentionally. Here, we implemented
          structures to enable thread-local storage, i.e., each thread operates
          on local data structures or with static data.
        * Reentrant - The ability to correctly execute any part of the program
          by multiple threads simultaneously but independently from others.
    * All non-static variables are replaced by local variables;
      functions gained arguments to pass local variables by reference
      (replacing global variables).
    * New main abstract types
        * SW_ALL - Contains the existing structures that are relevant
          for the simulation itself, e.g., SW_MODEL, SW_SOILWAT, SW_WEATHER.
        * PATH_INFO - Holds information about location of input and output data,
          e.g., directories, file paths to input data.
        * SW_OUTPUT_POINTERS - Points to requested output subroutines.
        * LOG_INFO - Manages information for logging warnings and errors.

* Tests now require `c++14` and utilize `googletest` `v1.14.0` (issue #339).

* Bugfixes
    * Fix an error where a pointer was freed even though it was not allocated
      (issue #356; @dschlaep).
    * Fix memory leak in test of `SW_VPD_construct()` (issue #205; @dschlaep).

Changes to inputs
* The output separator `OUTSEP` has been unused since the switch (`v4.0.0`)
  from writing free-form text files to `"csv"` spreadsheets
  (where the separator is fixed to a comma); the occurrence of
  `OUTSEP` in `"outsetup.in"` is now deprecated and triggers a warning.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants