Explicit `!!null` tag with empty content loads as a Scalar node instead of Null

Aperta Adatta ai principianti
#1,517 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
82/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
cpp
Ambito
tooling

Direzione di ricerca

Il bug si trova alla fine di SingleDocParser::HandleNode in src/singledocparser.cpp, dove il ramo tag == "?" emette OnNull e ogni altro tag ricade in OnScalar con un valore vuoto. Compila la libreria, poi esegui la riproduzione della issue (YAML::Load("---\ntest: !!null \nfoo: bar")) e verifica che doc["test"].IsNull() restituisca false. È completato quando questa verifica restituisce true, l'ancora continua a essere passata e i test esistenti continuano a passare, incluso quello per !!str su contenuto vuoto, che deve mantenere il comportamento attuale.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Location (jbeder/yaml-cpp @ default branch c5e6536):

  if (tag == "?")
    eventHandler.OnNull(mark, anchor);
  else
    eventHandler.OnScalar(mark, tag, anchor, "");

Problem

YAML::Node doc = YAML::Load("---\ntest: !!null \nfoo: bar");
doc["test"].IsNull();   // false: Scalar node, value "", tag "tag:yaml.org,2002:null"
doc["foo"].as<std::string>();  // "bar" (rest of the document is fine)

For a node with properties but no content, HandleNode emits OnNull only when the tag is the non-specific "?". An explicit tag always goes to OnScalar(mark, tag, anchor, ""), including tag:yaml.org,2002:null.

Expected: doc["test"].IsNull() == true (Type() == YAML::NodeType::Null), the same as for test: with no tag. Here the node is explicitly tagged tag:yaml.org,2002:null (10.2.1.1 Null), and its content is empty, which the Core schema also resolves to null (/* Empty */ → tag:yaml.org,2002:null, 10.3.2). So it isn't an empty string like "" or !!str, and the input is valid.

Scope: only explicit !!null with empty content. No change is proposed to how other explicit tags on empty nodes (e.g. !!str → "") are handled, or to non-empty !!null content.

Reproduction

#include <iostream>
#include "yaml-cpp/yaml.h"

int main() {
  YAML::Node doc = YAML::Load("---\ntest: !!null \nfoo: bar");
  std::cout << std::boolalpha
            << "IsNull: " << doc["test"].IsNull() << "\n"
            << "IsScalar: " << doc["test"].IsScalar() << "\n"
            << "Tag: " << doc["test"].Tag() << "\n";
}

Observed (gtest on the commit above):

Value of: doc["test"].IsNull()
  Actual: false
Expected: true

Environment:

  • Commit: c5e65360373d1d99d6b6848c991cd4fcee435009 (master)
  • Toolchain: GCC 11.5.0

Already fixed in nodeca/js-yaml
js-yaml is another YAML implementation of the same spec; it fixed the same input. PR: https://github.com/nodeca/js-yaml/pull/155 — "error parsing named null" (merged 2014-12-18T21:08:19Z, merge commit cb5a2d8409e). Its null-type resolver now accepts an empty (no content) node, so test: !!null with empty content loads as null instead of failing; the added test uses the same document as above.

How js-yaml fixed it:

--- a/lib/js-yaml/type/null.js
+++ b/lib/js-yaml/type/null.js
@@ -3,6 +3,10 @@
 var Type = require('../type');
 
 function resolveYamlNull(data) {
+  if (null === data) {
+    return true;
+  }
+
   var max = data.length;
 
   return (max === 1 && data === '~') ||
--- a/test/issues/0155.js
+++ b/test/issues/0155.js
@@ -0,0 +1,10 @@
+'use strict';
+
+
+var assert = require('assert');
+var yaml   = require('../../');
+
+
+test('Named null', function () {
+  assert.deepEqual(yaml.load('---\ntest: !!null \nfoo: bar'), { test: null, foo: 'bar' });
+});

Suggested fix
In HandleNode, emit OnNull for an empty node tagged tag:yaml.org,2002:null, as for the non-specific ? tag (the anchor is kept); other explicit tags on empty content are unchanged:

diff --git a/src/singledocparser.cpp b/src/singledocparser.cpp
--- a/src/singledocparser.cpp
+++ b/src/singledocparser.cpp
@@ -146,7 +146,7 @@ void SingleDocParser::HandleNode(EventHandler& eventHandler) {
       break;
   }
 
-  if (tag == "?")
+  if (tag == "?" || tag == "tag:yaml.org,2002:null")
     eventHandler.OnNull(mark, anchor);
   else
     eventHandler.OnScalar(mark, tag, anchor, "");

Verified on c5e6536 (GCC 11.4.0, bundled GoogleTest 1.16.0): the test above fails without this patch and passes with it; no other test results change.

I can submit a PR for this.

Related: #1290 (untagged empty value converts to the string "null"; about as<std::string>() on a Null node, while here the node is not Null), #1460 (closed; source text for plain null scalars) and #641 (open draft; general tag resolver design) do not report this case.

Lingua principale
C++
Stelle
6.1k
Fork
2.2k
Merge medio
22h 2m
PR unite (30g)
1

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di jbeder/yaml-cpp

Tutte le issue di jbeder/yaml-cpp

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.