Skip to content

Commit c0abf48

Browse files
nihuiprofessor-moodybeilzx
authored
harden paramdict parsing and typed access (#6983)
Co-authored-by: Nathan Keys <nathan.keys@pm.me> Co-authored-by: beilzx <2069360659@qq.com>
1 parent 9041b0b commit c0abf48

9 files changed

Lines changed: 1365 additions & 596 deletions

File tree

docs/developer-guide/param-and-model-file-structure.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ Softmax softmax 1 1 fc prob 0=0
1818
* layer count : count of the layer line follows, should be exactly the count of all layer names
1919
* blob count : count of all blobs, usually greater than or equals to the layer count
2020
### layer line
21+
22+
each layer must occupy exactly one physical line, including all blob names and parameters; do not split a layer across lines or put multiple layers on the same line
23+
24+
Custom `DataReader::scan()` implementations and C API `ncnn_datareader_t::scan` callbacks must follow scanf conversion and input consumption rules, including field widths and scansets. Parameter parsing uses `%1023[^\r\n]` to read up to 1023 characters without skipping leading whitespace or consuming CR/LF, repeating the scan for longer lines. A successful scanset conversion must append a null terminator and return 1. Returning 0 for an unsupported format can be interpreted as an empty parameter list and silently select default parameter values.
25+
2126
```
2227
[layer type] [layer name] [input count] [output count] [input blobs] [output blobs] [layer specific params]
2328
```
@@ -36,13 +41,21 @@ key index should be unique in each layer line, pair can be omitted if the defaul
3641

3742
the meaning of existing param key index can be looked up at [operation-param-weight-table](operation-param-weight-table)
3843

39-
* integer or float key : index 0 ~ 19
44+
* integer or float key : index 0 ~ 31
4045
* integer value : int
4146
* float value : float
42-
* integer array or float array key : -23300 minus index 0 ~ 19
47+
* integer array or float array key : -23300 minus index 0 ~ 31
4348
* integer array value : [array size],int,int,...,int
4449
* float array value : [array size],float,float,...,float
4550

51+
Use a decimal point or exponent when generating floating-point scalar values, including integral values, for example `1=6.0`, `1=6e0`, or `1=0.0`. When loading text parameters, the float getter also converts integer spellings such as `1=6` and `1=0` to `6.0f` and `0.0f`. The int getter does not convert floating-point parameters to integers.
52+
53+
Keep floating-point spellings when converting models with `ncnn2mem`: binary scalar parameters do not retain integer/float type tags, and the converter writes integer spellings as integer bit patterns without this numeric conversion.
54+
55+
Use a decimal point or exponent for every element of a floating-point array, including integral values, for example `-23303=2,1.0,2.0`. Mixed integer and float element spellings within an array are not defined by the format.
56+
57+
A zero-length array such as `-23300=0` explicitly supplies an empty array. Array getters return that empty array even when a nonempty default is supplied; omitting the parameter returns the default.
58+
4659
In modern ncnn param file
4760

4861
* array could be represented as `3=2.0,3.0` that is much more human friendly

src/c_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ struct NCNN_EXPORT __ncnn_datareader_t
224224
void* pthis;
225225

226226
#if NCNN_STRING
227+
/* follow scanf conversion and input consumption rules, including field widths and scansets */
228+
/* %1023[^\r\n] must preserve leading whitespace and leave CR/LF unread */
229+
/* append a null terminator on a successful scanset conversion and return 1 */
227230
int (*scan)(ncnn_datareader_t dr, const char* format, void* p);
228231
#endif /* NCNN_STRING */
229232
size_t (*read)(ncnn_datareader_t dr, void* buf, size_t size);

src/datareader.cpp

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "datareader.h"
55

6+
#include <ctype.h>
67
#include <string.h>
78

89
namespace ncnn {
@@ -187,23 +188,12 @@ int DataReaderFromAndroidAsset::scan(const char* format, void* p) const
187188
std::string line;
188189
{
189190
off64_t remain_length = AAsset_getRemainingLength64(d->asset);
190-
const char* newline_pos;
191-
if (remain_length > 1 && ((const char*)d->mem)[0] == '\n')
192-
{
193-
// skip the leading newline
194-
// however, it is fine to create "\nXYZ 123 abc" as sscanf will skip the leading newline silently
195-
newline_pos = (const char*)memchr((const char*)d->mem + 1, '\n', remain_length - 1);
196-
}
197-
else if (remain_length > 2 && ((const char*)d->mem)[0] == '\r' && ((const char*)d->mem)[1] == '\n')
198-
{
199-
// skip the leading newline
200-
// however, it is fine to create "\r\nXYZ 123 abc" as sscanf will skip the leading newline silently
201-
newline_pos = (const char*)memchr((const char*)d->mem + 2, '\n', remain_length - 2);
202-
}
203-
else
204-
{
205-
newline_pos = (const char*)memchr((const char*)d->mem, '\n', remain_length);
206-
}
191+
// include all leading whitespace and the following line in the buffer
192+
// sscanf decides whether the conversion consumes that whitespace
193+
size_t offset = 0;
194+
while (offset < (size_t)remain_length && isspace(d->mem[offset]))
195+
offset++;
196+
const char* newline_pos = (const char*)memchr(d->mem + offset, '\n', (size_t)remain_length - offset);
207197

208198
size_t line_length = newline_pos ? newline_pos - (const char*)d->mem : (size_t)remain_length;
209199
line = std::string((const char*)d->mem, line_length);

src/datareader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class NCNN_EXPORT DataReader
2626

2727
#if NCNN_STRING
2828
// parse plain param text
29+
// follow scanf conversion and input consumption rules, including field widths and scansets
30+
// %1023[^\r\n] reads at most 1023 characters without skipping whitespace or consuming CR/LF
31+
// append a null terminator on a successful scanset conversion
2932
// return 1 if scan success
3033
virtual int scan(const char* format, void* p) const;
3134
#endif // NCNN_STRING

0 commit comments

Comments
 (0)