cvt_d_st and cvt_f_st do not check target field size
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
EPICS Base |
New
|
Undecided
|
Unassigned |
Bug Description
The functions to convert float and double values to string do not check the size of the target field. These functions are entries in the dbFastPutConver
This may cause buffer overruns when writing double or float values into short string fields, such as EGU with large precision values.
BTW: putDoubleString and putFloatString which are used for arrays in the similar dbPutConvertRoutine table have a similar but not so severe problem. They use the target size to iterate to the next array element but do not check if the target element is actually long enough to hold the double converted to string. This is not so much of a practical problem because all strings arrays have 40 chars at the moment and cvtDoubleToString artificially limits precision to 17.
cvt_d_st and cvt_f_st should check the target field size.
Maybe cvtDoubleToString needs a buffersize argument.
There is no way to add arguments to individual conversion functions, they must all present the exact same calling signature, which is a major problem for the cvt_d_st() and cvt_f_st() routines with a "too-small" output buffer.
Oh, and since both log(2**63-1)+1 > 19 and log(2**64-1) > 19 the new cvt_q_st() and cvt_uq_st() routines on 3.16 and later can also overflow a 20-character output buffer. How should we indicate this has happened? My inclination would be to replace the result with a string like "<overflow>", any objections to that? What about when the above real number conversions don't fit, should we limit the precision we feed into them, or just return "<overflow>" again?
One difference between the "fast" conversions and the dbConvert.c code is that the latter has separate get and put operations:
long get<1><2>(const dbAddr *paddr, void *pto, long nRequest, long no_elements, long offset);
long put<1><2>(dbAddr *paddr, const void *pfrom, long nRequest, long no_elements, long offset);
For put operations the dbAddr argument provides the size of the target field, so the put<real>String() converters do know it and can be made to use it.
Unfortunately for get operations the const dbAddr argument describes the source buffer, thus the get<real>String() routines still have to assume that the target buffer is MAX_STRING_SIZE characters. That may be less of a problem though, I can't think of any input links that are fetched into a small string buffer.
Thus my preferred solution is currently to drop the "fast" convert routines and only use the dbConvert.h API (in dbPut() at least). Then add cvt<type>ToString() routines that can't overflow their buffers, and change dbConvert.c to use them. I think this should fix the worst of the problem.
Comments?