Sanitizer false-positive?

Hi :wave:

Are there any known issues with -fsanitize=address -fstack-protector-all -fsanitize=undefined and acados v0.2.0?

I’ve observed the following error when building with sanitizer flags (both for gcc and clang):

==201836==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7f3bd5e04c20 at pc 0x55ebc74906e1 bp 0x7ffd7d851890 sp 0x7ffd7d851888
READ of size 4 at 0x7f3bd5e04c20 thread T0
error: did not detect a valid list table with base = 0x0 *** This is repeated 130-140 times ***
warning: parsing line table prologue at 0x0029b77c should have ended at 0x0029baad but it ended at 0x0029baac
    #0 0x55ebc74906e0 in ocp_nlp_dynamics_cont_opts_set <acados-path>/acados/acados/ocp_nlp/ocp_nlp_dynamics_cont.c:307:30
    #1 0x55ebc729bb80 in ocp_nlp_opts_set <acados-path>/acados/acados/ocp_nlp/ocp_nlp_common.c:1243:17
    #2 0x55ebc73ea961 in ocp_nlp_sqp_rti_opts_set <acados-path>/acados/acados/ocp_nlp/ocp_nlp_sqp_rti.c:225:13
    #3 0x55ebc73a2563 in ocp_nlp_solver_opts_set <acados-path>/acados/interfaces/acados_c/ocp_nlp_interface.c:964:5
    #4 0x55ebc721d699 in ocp_acados_create_6_set_opts acados_solver_ocp.c:719:9
    #5 0x55ebc71fe62d in ocp_acados_create_with_discretization acados_solver_ocp.c:887:5
    #6 0x55ebc71f933f in zenseact::optimaltrajectoryplanner::test::TestOptimalController_Test_Test::TestBody() test/tmp.cpp:41:18
    #7 0x55ebc7c76129 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (test/tmp+0x1128129) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #8 0x55ebc7be4943 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (test/tmp+0x1096943) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #9 0x55ebc7b73861 in testing::Test::Run() (test/tmp+0x1025861) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #10 0x55ebc7b7691d in testing::TestInfo::Run() (test/tmp+0x102891d) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #11 0x55ebc7b791d8 in testing::TestSuite::Run() (test/tmp+0x102b1d8) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #12 0x55ebc7bb07f1 in testing::internal::UnitTestImpl::RunAllTests() (test/tmp+0x10627f1) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #13 0x55ebc7c8ed44 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (test/tmp+0x1140d44) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #14 0x55ebc7bf2228 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (test/tmp+0x10a4228) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #15 0x55ebc7baf025 in testing::UnitTest::Run() (test/tmp+0x1061025) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118)
    #16 0x55ebc7b2d41b in RUN_ALL_TESTS() external/googletest/googletest/include/gtest/gtest.h:2310:73
    #17 0x55ebc7b2d27e in main /proc/self/cwd/external/googletest/googlemock/src/gmock_main.cc:70:10
    #18 0x7f3bd8373082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #19 0x55ebc7125579 in _start (test/tmp+0x5d7579) (BuildId: f1a28b113f9d89e2cf95586b3f4ea118) *** This is the test file ***

Address 0x7f3bd5e04c20 is located in stack of thread T0 at offset 32 in frame
    #0 0x55ebc721cedf in ocp_acados_create_6_set_opts acados_solver_ocp.c:704 *** This is the auto generated acados solver file ***

  This frame has 19 object(s):
    [32, 33) 'nlp_solver_exact_hessian' (line 715) <== Memory access at offset 32 partially overflows this variable
    [48, 52) 'exact_hess_dyn' (line 721)
    [64, 68) 'exact_hess_cost' (line 724)
    [80, 84) 'exact_hess_constr' (line 727)
    [96, 100) 'full_step_dual' (line 729)
    [112, 116) 'collocation_type' (line 733)
    [128, 132) 'sim_method_num_steps' (line 739)
    [144, 148) 'sim_method_num_stages' (line 745)
    [160, 164) 'newton_iter_val' (line 749)
    [176, 177) 'tmp_bool' (line 755)
    [192, 200) 'nlp_solver_step_length' (line 759)
    [224, 232) 'levenberg_marquardt' (line 762)
    [256, 260) 'qp_solver_cond_N' (line 766)
    [272, 276) 'nlp_solver_ext_qp_res' (line 772)
    [288, 292) 'qp_solver_iter_max' (line 779)
    [304, 308) 'print_level' (line 782)
    [320, 324) 'qp_solver_cond_ric_alg' (line 784)
    [336, 340) 'qp_solver_ric_alg' (line 787)
    [352, 356) 'ext_cost_num_hess' (line 791)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow <acados-path>/acados/ocp_nlp/ocp_nlp_dynamics_cont.c:307:30 in ocp_nlp_dynamics_cont_opts_set
Shadow bytes around the buggy address:
  0x7f3bd5e04980: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f3bd5e04a00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f3bd5e04a80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f3bd5e04b00: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7f3bd5e04b80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
=>0x7f3bd5e04c00: f1 f1 f1 f1[01]f2 f8 f2 f8 f2 f8 f2 f8 f2 f8 f2
  0x7f3bd5e04c80: f8 f2 f8 f2 f8 f2 f8 f2 f8 f2 f2 f2 f8 f2 f2 f2
  0x7f3bd5e04d00: f8 f2 f8 f2 f8 f2 f8 f2 f8 f2 f8 f2 f8 f3 f3 f3
  0x7f3bd5e04d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f3bd5e04e00: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f3bd5e04e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==201836==ABORTING

which I don’t really know how to handle.

  1. I’m using the python interface to generate the acados c code
  2. I’m using Bazel to build a c++ wrapper that instantiates and calls the acados solver

Note 1: When I’m compiling the generated main c file with -fsanitize=address -fstack-protector-all -fsanitize=undefined and adding to LDLIBS+= -lasan -lubsan I see no issues. In other words, I modify

Update: When building the auto generated main file in the bazel environment I’m using, I get the same issue. So either my bazel environment is causing a false-positive or there is a potential bug here.

Any ideas on which steps I can take to identify if it’s a false positive, an implementation issue on my side, or a potential bug in acados?

1 Like

I back tracked the calls to the generated acados solver c file, and it seems that this is the function call:

    bool nlp_solver_exact_hessian = true;
    // TODO: this if should not be needed! however, calling the setter with false leads to weird behavior. Investigate!
    if (nlp_solver_exact_hessian)
    {
        ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "exact_hess", &nlp_solver_exact_hessian);
    }

This address of the bool is taken as a void pointer argument by the function and in
acados/ocp_nlp/ocp_nlp_dynamics_cont.c:307:30 is being cast to an int pointer

Hey @ivob

Thanks for finding and narrow the issue down! :pray:
That probably explains the TODO comment there…

I guess this should fix it:

Best,
Jonathan