Skip to content

lib/dbmibase: Fix "Implicit conversion loses integer precision" warnings - #8019

Open
nilason wants to merge 1 commit into
OSGeo:mainfrom
nilason:fix_libdbmibase_implicit_conversion
Open

nilason wants to merge 1 commit into
OSGeo:mainfrom
nilason:fix_libdbmibase_implicit_conversion

Conversation

@nilason

@nilason nilason commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Adresses ” -Wshorten-64-to-32” Clang warnings.

Adresses ” -Wshorten-64-to-32” Clang warnings.
@github-actions github-actions Bot added C Related code is in C database Related to database management libraries labels Oct 5, 2026

@wenzeslaus wenzeslaus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The truncated lengths are used to allocate buffers, so when a length does not fit in int, the buffer is not enlarged. I suggest that lengths stay size_t as returned by strlen() and are checked against INT_MAX (like in #7950) where they enter the int-based dbmi API, i.e., db_malloc() and db_enlarge_string(). When the check fails, the code should fail like the surrounding code, ideally with a memory error. The details below and the inline suggestions are AI generated.

Details (AI generated)

In #8023, the same kind of cast was accepted because HTML_Text() is not reachable. The dbmi functions are used in live code; for example, db_append_string() is called from 66 C files, some of them in loops building SQL statements.

What happens when a length does not fit in int:

  • set_string() and db_append_string(): the wrapped len is negative or small, so x->nalloc < len in db_enlarge_string() is false and nothing is reallocated. strcpy() or strcat() then writes the whole string past the end of the buffer.
  • db_store(): a negative length becomes a 1-byte allocation, because db_malloc() turns n <= 0 into 1, and strcpy() writes past it.
  • db_dirent(): db_malloc((int)path_len) allocates from the truncated value, while snprintf(path, path_len, ...) writes up to the full path_len.
  • db__send_string(): a negative length is converted to a huge size_t in db__send(), which reads past the end of s. A positive truncated length sends the string without its terminating null byte.

The PR currently mixes approaches: set_string() keeps int and casts strlen() right away, db_append_string() switches to size_t but casts at the call without a check, and dirent.c and xdrstring.c cast right away. With the rule above, each place gets:

Place Type int boundary Check
set_string() int -> size_t db_enlarge_string() yes, in the copy branch where len is used
db_append_string() size_t (as in the PR) db_enlarge_string() yes
db_store() new size_t len db_malloc() yes
db__send_string() size_t for the computation, int len kept for sending sent length yes
db_dirent() len, max int -> size_t none, max only goes into the size_t path_len no, and no cast
db_dirent() path_len size_t (as in the PR) db_malloc() yes

The checks fail the same way a real allocation failure does (db_memory_error(), then NULL or DB_MEMORY_ERR), so callers already handle them. The one exception is db__send_string(), which fails like its send errors (db_protocol_error(), DB_PROTOCOL_ERR).

The suggested code was applied to the files of this PR and compiled with clang 18 using -Wshorten-64-to-32 -Wconversion. No new warnings appear, and INT_MAX needs <limits.h> in each file.

Comment thread lib/db/dbmi_base/string.c
}

len = strlen(s) + 1;
len = (int)strlen(s) + 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With size_t len; at the top of set_string():

    len = strlen(s) + 1;

    if (copy) {
        if (len > INT_MAX) {
            db_memory_error();
            return DB_MEMORY_ERR;
        }
        stat = db_enlarge_string(x, (int)len);

Comment thread lib/db/dbmi_base/string.c

len = strlen(db_get_string(x)) + strlen(s) + 1;
stat = db_enlarge_string(x, len);
stat = db_enlarge_string(x, (int)len);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
stat = db_enlarge_string(x, (int)len);
if (len > INT_MAX) {
db_memory_error();
return DB_MEMORY_ERR;
}
stat = db_enlarge_string(x, (int)len);

Comment thread lib/db/dbmi_base/alloc.c
char *a;

a = db_malloc(strlen(s) + 1);
a = db_malloc((int)strlen(s) + 1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    char *a;
    size_t len = strlen(s) + 1;

    if (len > INT_MAX) {
        db_memory_error();
        return NULL;
    }
    a = db_malloc((int)len);

int stat = DB_OK;
const char *s = db_get_string(x);
int len = s ? strlen(s) + 1 : 1;
int len = s ? (int)strlen(s) + 1 : 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sent length stays int, so compute it as size_t and fail like the send errors below:

    size_t size = s ? strlen(s) + 1 : 1;
    int len;

    if (size > INT_MAX) {
        db_protocol_error();
        return DB_PROTOCOL_ERR;
    }
    len = (int)size;

Comment thread lib/db/dbmi_base/dirent.c

size_t path_len = strlen(dirname) + max + 2; // extra 2 for / and NULL
path = db_malloc(path_len);
path = db_malloc((int)path_len);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len and max can be size_t without a cast, since max only goes into path_len. path_len itself needs the check:

Suggested change
path = db_malloc((int)path_len);
if (path_len > INT_MAX) {
db_memory_error();
closedir(dp);
return (dbDirent *)NULL;
}
path = db_malloc((int)path_len);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C Related code is in C database Related to database management libraries

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants