'Valgrind errors not reported when function is inlined

I've been trying to track down the cause of an error reported by Valgrind (see below). It says that a 'Conditional jump or move depends on uninitialised value(s)', pointing to a function call. When I inline that function however, the error is no longer reported.

Original function

bool is_unsafe_piece_hook(Gamestate & gs, const Square s) {

    Piece p = gs.board.get(s);
    Colour c = colour(p);
    if (p == EMPTY) { return true; }

    SquareControlStatus ss = gs.control_cache->get_control_status(s);

    if (is_weak_status(gs, s, c, ss)) {
        return gs.add_frame(unsafe_piece_hook.id, FeatureFrame{s, SQUARE_SENTINEL, ss.min_w, ss.min_b});
    }

*   if (pawn_is_en_passantable(gs, s)) {
        return gs.add_frame(unsafe_piece_hook.id, FeatureFrame{s, SQUARE_SENTINEL, ss.min_w, ss.min_b});
    }

    return true;
}

Error reported

The line referred to is marked with an asterisk above.

==22305== Conditional jump or move depends on uninitialised value(s)
==22305==    at 0x196D56: is_unsafe_piece_hook(Gamestate&, Square) (unsafe_piece.cpp:38)
==22305==    by 0x194963: discover_feature_frames (cands.cpp:22)
==22305==    by 0x194963: cands(Gamestate&, CandSet*) (cands.cpp:65)
==22305==    by 0x192910: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:117)
==22305==    by 0x192AD0: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:77)
==22305==    by 0x192A01: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:133)
==22305==    by 0x192A01: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:133)
==22305==    by 0x192F8B: visit_node(SearchNode*, Observer&) [clone .part.0] (greedy.cpp:181)
==22305==    by 0x193135: visit_node (greedy.cpp:151)
==22305==    by 0x193135: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:272)
==22305==    by 0x193117: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:271)
==22305==    by 0x193117: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:271)
==22305==    by 0x193117: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:271)
==22305==    by 0x1932B1: visit_best_line (greedy.cpp:271)
==22305==    by 0x1932B1: greedy_search(SearchNode*, int, Observer&) (greedy.cpp:299)
==22305==  Uninitialised value was created by a heap allocation
==22305==    at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==22305==    by 0x18FC3C: new_node(Gamestate const&, Move) (search.cpp:183)
==22305==    by 0x1928D5: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:116)
==22305==    by 0x192AD0: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:77)
==22305==    by 0x192A01: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:133)
==22305==    by 0x192A01: deepen(SearchNode*, CandList, int, Observer&, bool) (greedy.cpp:133)
==22305==    by 0x192F8B: visit_node(SearchNode*, Observer&) [clone .part.0] (greedy.cpp:181)
==22305==    by 0x193135: visit_node (greedy.cpp:151)
==22305==    by 0x193135: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:272)
==22305==    by 0x193117: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:271)
==22305==    by 0x193117: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:271)
==22305==    by 0x193117: visit_best_line(SearchNode*, bool, Observer&) (greedy.cpp:271)
==22305==    by 0x1932B1: visit_best_line (greedy.cpp:271)
==22305==    by 0x1932B1: greedy_search(SearchNode*, int, Observer&) (greedy.cpp:299)

Modified function

Valgrind reports no errors when using the modified version. The function pawn_is_en_passantable has been inlined (manually) corresponding to the code within the inner block marked with asterisks.

bool is_unsafe_piece_hook(Gamestate & gs, const Square s) {

    Piece p = gs.board.get(s);
    Colour c = colour(p);
    if (p == EMPTY) { return true; }

    SquareControlStatus ss = gs.control_cache->get_control_status(s);

    if (is_weak_status(gs, s, c, ss)) {
        return gs.add_frame(unsafe_piece_hook.id, FeatureFrame{s, SQUARE_SENTINEL, ss.min_w, ss.min_b});
    }

    bool en_passantable;
*   {
        Piece p2 = gs.board.get(s);
        Colour c2 = colour(p2);

        // check we have a pawn on the correct square
        if (!gs.board.get_ep_exists()
            || type(p2) != PAWN
            || !equal(s, gs.board.get_ep_pawn_square())) {
            return false;
        }

        // check there is indeed a pawn to capture it
        Square l_sq = mksq(s.x + 1, s.y);
        Square r_sq = mksq(s.x - 1, s.y);
        Piece enemy_pawn = (c2 == WHITE ? B_PAWN : W_PAWN);

        en_passantable =
                (s.x > 0 && gs.board.get(l_sq) == enemy_pawn)
               || (s.x < 7 && gs.board.get(r_sq) == enemy_pawn);
*   }

    if (en_passantable) {
        return gs.add_frame(unsafe_piece_hook.id, FeatureFrame{s, SQUARE_SENTINEL, ss.min_w, ss.min_b});
    }

    return true;
}

Question

  1. Is there actually an error here?
  2. Why does Valgrind behave like this?

I appreciate there might not be enough information to answer (1) - any suggestions on how to continue debugging also appreciated (this is the only error reported; I've check the initialisation the error refers to several times and the project also compiles cleanly with -Wall -Wextra).

Edit: using g++ 9.4.0 on Ubuntu.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source