schemagen: reject duplicate unknown keys in non-strict objects
Track unknown keys in a per-object unordered_set so that permissive objects (additionalProperties absent/true) still reject duplicate keys, matching the README guarantee. - Add std::unordered_set<std::string> to Frame. - Insert unknown keys in cbKeyData and reject duplicates before skipping. - Add a permissive "loose" subobject to example.schema.json. - Test single unknown key accepted and duplicate unknown/known keys rejected.
This commit is contained in:
@@ -566,6 +566,7 @@ class Emitter:
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "weaseljson.h"
|
||||
@@ -931,6 +932,7 @@ private:
|
||||
void *dest;
|
||||
int field = -1; // object: selected field (-1 want key, -2 skip)
|
||||
std::vector<uint64_t> seen; // populated field bitset (object frames)
|
||||
std::unordered_set<std::string> unknown; // unknown keys seen in non-strict objects
|
||||
}};
|
||||
static constexpr int kWantKey = -1;
|
||||
static constexpr int kSkip = -2;
|
||||
@@ -1014,12 +1016,16 @@ private:
|
||||
scratch_.append(buf, len);
|
||||
if (!done) return;
|
||||
int idx = matchKey(f.kind, scratch_);
|
||||
scratch_.clear();
|
||||
if (idx < 0) {{
|
||||
if (isStrict(f.kind)) {{ reject(); return; }}
|
||||
if (!f.unknown.insert(scratch_).second) {{
|
||||
reject(); return; // duplicate unknown key
|
||||
}}
|
||||
scratch_.clear();
|
||||
f.field = kSkip;
|
||||
return;
|
||||
}}
|
||||
scratch_.clear();
|
||||
if (f.seen[idx >> 6] & (1ull << (idx & 63))) {{
|
||||
reject(); return; // duplicate key
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user