Hi Leo

On Sat, Apr 19, 2025 at 06:36:56AM -0400, Leo Izen wrote:
> On 4/17/25 12:52, Michael Niedermayer wrote:
[...]
> > +typedef struct{
> > +    AVMapEntry map_entry;
> > +    uint8_t treenode_and_keyvalue[0];
> > +} AVMapInternalEntry;
> > +
> > +struct AVMap{
> > +#define CMP_MASK 31
> > +    AVMapCompareFunc cmp[27];
> > +    AVMapCopyFunc copy;
> > +    AVMapFreeFunc freef;
> > +    int count;
> > +    int deleted;
> > +    int next;                   ///< index of entry in root array after 
> > all used entries
> 
> Indices into arrays and counts and the like should be size_t.

I guess AVMap will be one of the first parts of FFmpeg doing that

git grep 'int count' | wc
    354    2493   27289
git grep 'size_t count' | wc
      2       8      97

git grep 'int [a-zA-Z_]*index' | wc
   1279    7735   94963
git grep 'size_t [a-zA-Z_]*index' | wc
     29     118    1888

also we use av_fast_realloc() which doesnt use size_t
and av_map_realloc() must return a signed value to allow error codes so it will 
use int64_t not size_t


> 
> > +    unsigned internal_entries_len;
> > +    AVTreeNode *tree_root;
> > +    AVMapInternalEntry *internal_entries;
> > +};
> > +
> > +static uint8_t deleted_entry;
> 
> static const should allow the compiler to put it in a different section if
> it wishes. You can still address it even then.

I dont want to put it in a different section. Its value should be available
with a minimum of computation.


[...]
> > +int av_map_add_cmp_func(AVMap *m, AVMapCompareFunc cmp, int cmp_flags)
> > +{
> > +    static const uint8_t sensitivity[27][3] = {
> > +        {0,0, 0},{1,0, 0},{2,0, 0}, {0,3, 0},{1,3, 0},{2,3, 0}, {0,6, 
> > 0},{1,6, 0},{2,6, 0},
> > +        {0,0, 9},{1,0, 9},{2,0, 9}, {0,3, 9},{1,3, 9},{2,3, 9}, {0,6, 
> > 9},{1,6, 9},{2,6, 9},
> > +        {0,0,18},{1,0,18},{2,0,18}, {0,3,18},{1,3,18},{2,3,18}, 
> > {0,6,18},{1,6,18},{2,6,18},};
> > +    int case_sensitive       =  sensitivity[cmp_flags][0];
> > +    int keyvalue_sensitive   =  sensitivity[cmp_flags][1];
> > +    int truncated_sensitive  =  sensitivity[cmp_flags][2];
> > +
> > +    if (!keyvalue_sensitive || !truncated_sensitive || cmp_flags >= 27U)
> > +        return AVERROR(EINVAL);
> 
> Need to check for cmp_flags >= 27U before indexing into the array. The

ok


> compiler may pull this array off the stack cause it's static const so you
> risk hitting a dead page here.

printf("A"+5) also might hit a dead page, the user is not supposed to input
invalid data, and theres no gurantee that passing invalid data will not crash


[...]
> > +AVMap *av_map_new(AVMapCompareFunc cmp_keyvalue, int cmp_flags, 
> > AVMapCopyFunc copy, AVMapFreeFunc freef)
> > +{
> > +    AVMap *s = av_mallocz(sizeof(*s));
> > +    if (!s)
> > +        return NULL;
> > +
> > +    s->copy          = copy;
> > +    s->freef         = freef;
> > +
> > +    av_map_add_cmp_func(s, cmp_keyvalue, cmp_flags);
> 
> No check for return value. av_map_add_cmp_func can return AVERROR(EINVAL)
> depending on cmp_flags.

indeed, i missed that, good find


[...]
> > +    return advance;
> > +}
> > +
> > +int av_map_add(AVMap *s, const char *key, int keylen, const char *value, 
> > int valuelen, int flags)
> > +{
> > +    av_assert2(keylen || valuelen); // patch welcome but how would the 
> > compare function compare a len=0 element without knowing it is a len 0 
> > element
> > +
> 
> This is a public function so we should be returning AVERROR(EINVAL) on
> invalid input rather than asserting. Since a library user could do that.

Its a speed relevent function
testing for the caller to do something stupid is not its job
The assert helps the user to find such a mistake


[...]
> > +int av_map_copy(AVMap *dst, const AVMap *src)
> > +{
> > +    const AVMapEntry *t = NULL;
> > +    AVMap *bak = av_memdup(dst, sizeof(*dst));
> > +    if (!bak)
> > +        return AVERROR(ENOMEM);
> > +
> > +    AVMapInternalEntry *new_internal_entries = 
> > av_memdup(bak->internal_entries, bak->internal_entries_len);
> > +    AVMapInternalEntry *old_internal_entries = dst->internal_entries;
> 
> We don't allow mixed delcarations and statements. Hoist the defintion above
> if (!bak) and then put the assignment below it.

commit 890b8da1ce27fd365eaffefc7efcbadae9f01f2a

    configure: Allow mixing declarations and statements


> 
> > +
> > +    while ((t = av_map_iterate(src, t))) {
> > +        int ret = av_map_add(dst, t->key, t->keylen, t->value, 
> > t->valuelen, 0);
> > +
> > +        if (ret < 0) {
> > +            update_pointers(bak, new_internal_entries, 
> > old_internal_entries);
> > +            av_free(dst->internal_entries);
> > +            memcpy(dst, bak, sizeof(*dst));
> > +            return ret;
> 
> You leak bak here. Possibly new_internal_entries as well.

fixed


[...]
> > +typedef struct AVMapEntry {
> > +    uint8_t *key;
> > +    uint8_t *value;
> 
> Any particular reason to use unsigned char here rather than just char when
> working with strings? Most string stuff expects signed char.

changed to char*
AVMap is not limited to strings


> 
> > +    int keylen;
> > +    int valuelen;
> 
> size_t for lengths
> 
> > +} AVMapEntry;
> > +
> > +typedef struct AVMap AVMap;
> > +typedef void (* AVMapFreeFunc)(AVMapEntry *c);
> > +typedef void (* AVMapCopyFunc)(AVMapEntry *dst, const AVMapEntry *src, 
> > size_t len);
> > +typedef int  (* AVMapCompareFunc)(const void *keyvalue, const void *b);
> > +
> > +/**
> > + * like strcmp() but compares concatenated keyvalues.
> > + *
> > + * A map initialized with this will allow duplicate keys as long as their 
> > values differ.
> > + */
> > +int av_map_strcmp_keyvalue(const char *a, const char *b);
> > +
> > +/**
> > + * like av_map_strcmp_keyvalue() but is compatible with av_strcasecmp() 
> > and av_map_supercmp_key.
> > + *
> > + * A map initialized with this will allow duplicate keys as long as their 
> > values differ.
> > + */
> > +int av_map_supercmp_keyvalue(const char *a, const char *b);
> > +
> > +/**
> > + * like strcmp() but is compatible with av_strcasecmp().
> > + *
> > + * A map initialized with this will not allow duplicate keys.
> > + */
> > +int av_map_supercmp_key(const char *a, const char *b);
> 
> 
> I don't believe it's clear if and when a user should call these functions or
> simply pass them by address. If so, we should use the typedef, or at least
> reference it in the doc comment.

the user can do whatever she wants with them
av_map_alloc() refers to them already

maybe we should simplify init to not require this at all, iam still thinking 
about that


[...]
> > index 00000000000..6d1699ef4b7
> > --- /dev/null
> > +++ b/tests/ref/fate/map
> > @@ -0,0 +1,27 @@
> > +testing empty set
> > +
> > +testing 1-set
> > +
> > +testing n-set
> > +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
> > +the key=the value 8,10   n=n 2,2   �=� 2,2   "=" 2,2   ]=] 2,2   �=� 2,2   
> > y=y 2,2   *=* 2,2   5=5 2,2   ~=~ 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 
> > 2,2   )=) 2,2   �=� 2,2   e=e 2,2   �=� 2,2   A=A 2,2   B=B 2,2   �=� 2,2   
> > �=� 2,2   �=� 2,2   J=J 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 
> > 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 2,2   b=b 2,2   
> > = 2,2   �=� 2,2   9=9 2,2   j=j 2,2   �=� 2,2   �=� 2,2   Q=Q 2,2   �=� 
> > 2,2   M=M 2,2   = 2,2   �=� 2,2   �=� 2,2   %=% 2,2   �=� 2,2   = 2,2   
> > �=� 2,2   }=} 2,2   = 2,2   �=� 2,2   �=� 2,2   U=U 2,2   �=� 2,2   �=� 
> > 2,2   = 2,2   �=� 2,2   &=& 2,2   I=I 2,2   = 2,2   �=� 2,2   �=� 2,2   
> > a=a 2,2   �=� 2,2   �=� 2,2   6=6 2,2   �=� 2,2   �=� 2,2   �=� 2,2   �=� 
> > 2,2   = 2,2   2=2 2,2
> > =
> >   2,2   F=F 2,2   �=� 2,2   :=: 2,2   �=� 2,2   = 2,2   �=� 2,2   �=� 2,2 
> >   === 2,2   V=V 2,2   Y=Y 2,2   �=� 2,2   = 2,2   = 2,2   q=q 2,2   R=R 
> > 2,2   m=m 2,2   f=f 2,2     =        2,2   Z=Z 2,2   E=E 2,2   .=. 2,2   
> > !=! 2,2   �=� 2,2   �=� 2,2   v=v 2,2   �=� 2,2   �=� 2,2   u=u 2,2   >=> 
> > 2,2   �=� 2,2   r=r 2,2   �=� 2,2   �=� 2,2   i=i 2,2   z=z 2,2   �=� 2,2   
> > N=N 2,2   �=� 2,2   = 2,2   �=� 2,2   �=� 2,2   = 2,2
> > +=
> > + 2,2   �=� 2,2   ^=^ 2,2   1=1 2,2   �=� 2,2   -=- 2,2   �=� 2,2   �=� 2,2 
> >   �=� 2,2   = 2,2
> 
> 
> This may just be my email client messing up, but many of these appear to be
> nonprintable. I don't know why.

Testing that covers non printable chars


thanks for the review

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The educated differ from the uneducated as much as the living from the
dead. -- Aristotle 

Attachment: signature.asc
Description: PGP signature

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to