Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-41129

Query Cache replays an oversized GROUP_CONCAT result after max_allowed_packet is reduced

    XMLWordPrintable

Details

    • Bug
    • Status: Confirmed (View Workflow)
    • Major
    • Resolution: Unresolved
    • 13.0, 12.3.3
    • 12.3, 13.0
    • Query Cache

    Description

      The Query Cache key includes `group_concat_max_len`, but not
      `max_allowed_packet`, even though both variables now determine the effective
      `GROUP_CONCAT` limit. A result cached while `max_allowed_packet=4096` is reused
      by a new session after the global value is reduced to 1024. The new session
      receives the old 2687-byte aggregate; the same query forced through fresh
      execution returns 1024 bytes.

      Steps to reproduce

      set -eu
      IMAGE='mariadb@sha256:dd9b303aed4f4890ed09f766d8ca9ddfd176c0c6f6267feff53b3192ec65a979'
      C="mdev-mfu09-$$"
      OWNER="edbf-report-mfu09-$$"
      cleanup() {
        if docker inspect --format '{{ index .Config.Labels "io.encryptiondbfuzz.owner" }}' \
             "$C" 2>/dev/null | grep -Fqx "$OWNER"; then
          docker rm -f "$C" >/dev/null 2>&1 || true
        fi
      }
      trap cleanup EXIT
       
      docker run --detach --name "$C" \
        --label "io.encryptiondbfuzz.owner=$OWNER" \
        --network none --read-only --cap-drop ALL \
        --security-opt no-new-privileges=true --pids-limit 160 \
        --memory 1g --cpus 1 --user 999:999 \
        --tmpfs /var/lib/mysql:rw,nosuid,nodev,size=512m,uid=999,gid=999 \
        --tmpfs /run/mysqld:rw,nosuid,nodev,size=16m,uid=999,gid=999 \
        --tmpfs /tmp:rw,nosuid,nodev,size=64m,uid=999,gid=999 \
        --env MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 "$IMAGE" \
        --query-cache-size=8M --query-cache-type=ON \
        --max-allowed-packet=4096 >/dev/null
       
      READY=0
      for I in $(seq 1 90); do
        if docker exec --user 999:999 "$C" mariadb --protocol=socket \
             --socket=/run/mysqld/mysqld.sock -uroot -NBe 'SELECT @@port' \
             2>/dev/null | grep -qx 3306; then
          READY=1
          break
        fi
        sleep 1
      done
      test "$READY" -eq 1
       
      db() {
        docker exec --user 999:999 "$C" mariadb --protocol=socket \
          --socket=/run/mysqld/mysqld.sock -uroot --batch --skip-column-names "$@"
      }
       
      db -e "CREATE DATABASE d;
        CREATE TABLE d.t(v VARCHAR(20));
        INSERT INTO d.t VALUES(REPEAT('x',20));
        INSERT INTO d.t SELECT v FROM d.t;
        INSERT INTO d.t SELECT v FROM d.t;
        INSERT INTO d.t SELECT v FROM d.t;
        INSERT INTO d.t SELECT v FROM d.t;
        INSERT INTO d.t SELECT v FROM d.t;
        INSERT INTO d.t SELECT v FROM d.t;
        INSERT INTO d.t SELECT v FROM d.t"
       
      echo 'hits_before:'
      db -e "SHOW GLOBAL STATUS LIKE 'Qcache_hits'"
       
      echo 'producer_packet_and_length:'
      db -e "SELECT @@max_allowed_packet;
        USE d;
        SET SESSION group_concat_max_len=4096;
        SELECT LENGTH(GROUP_CONCAT(v ORDER BY v)) FROM t"
       
      # This changes the default for the next connection.
      db -e 'SET GLOBAL max_allowed_packet=1024'
       
      echo 'consumer_packet_and_cached_length:'
      db -e "SELECT @@max_allowed_packet;
        USE d;
        SET SESSION group_concat_max_len=4096;
        SELECT LENGTH(GROUP_CONCAT(v ORDER BY v)) FROM t"
       
      echo 'hits_after:'
      db -e "SHOW GLOBAL STATUS LIKE 'Qcache_hits'"
       
      echo 'new_session_noncacheable_length:'
      db -e "SELECT @@max_allowed_packet;
        USE d;
        SET SESSION group_concat_max_len=4096;
        SELECT LENGTH(GROUP_CONCAT(v ORDER BY v)) FROM t WHERE RAND()>=0"
      

      Actual result

      hits_before:
      Qcache_hits  0
      producer_packet_and_length:
      4096
      2687
      consumer_packet_and_cached_length:
      1024
      2687
      hits_after:
      Qcache_hits  1
      new_session_noncacheable_length:
      1024
      1024
      

      `Qcache_hits` increasing from 0 to 1 proves that the 1024-byte session received
      the cached 2687-byte result. The non-cacheable control recomputes under the same
      1024-byte setting and returns exactly 1024 bytes. The server remained healthy.

      Expected result

      A query result produced under a different effective aggregate limit must not be
      reused. `max_allowed_packet` should participate in the Query Cache compatibility
      key, or the cached result should be revalidated/truncated for the consuming
      session.

      Impact and boundary

      Session semantics depend on whether an identical query happens to be cached.
      After an administrator reduces `max_allowed_packet`, new sessions can still
      receive older oversized aggregate results until cache invalidation. This is a
      configuration-isolation and result-consistency issue; no crash or memory
      corruption was observed. Only 12.3.3 was tested. This report is
      researcher-reproduced and not yet maintainer-confirmed.

      Attachments

        Issue Links

          Activity

            People

              sanja Oleksandr Byelkin
              csfuzz csfuzz
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.