Thread
Commits
-
Fix portability issues in datetime parsing.
- 591e088dd5b3 15.0 landed
-
Fix overflow hazards in interval input and output conversions.
- e39f99046710 15.0 landed
-
Add a couple more tests for interval input decoding.
- 1b208ebaf14e 15.0 landed
-
Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-11T19:48:21Z
The attached patch fixes an overflow bug in DecodeInterval when applying the units week, decade, century, and millennium. The overflow check logic was modelled after the overflow check at the beginning of `int tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span);` in timestamp.c. This is my first patch, so apologies if I screwed up the process somewhere. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-02-11T20:55:42Z
Joseph Koshakow <koshy44@gmail.com> writes: > The attached patch fixes an overflow bug in DecodeInterval when applying > the units week, decade, century, and millennium. The overflow check logic > was modelled after the overflow check at the beginning of `int > tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span);` in timestamp.c. Good catch, but I don't think that tm2interval code is best practice anymore. Rather than bringing "double" arithmetic into the mix, you should use the overflow-detecting arithmetic functions in src/include/common/int.h. The existing code here is also pretty faulty in that it doesn't notice addition overflow when combining multiple units. So for example, instead of tm->tm_mday += val * 7; I think we should write something like if (pg_mul_s32_overflow(val, 7, &tmp)) return DTERR_FIELD_OVERFLOW; if (pg_add_s32_overflow(tm->tm_mday, tmp, &tm->tm_mday)) return DTERR_FIELD_OVERFLOW; Perhaps some macros could be used to make this more legible? regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-11T21:58:09Z
Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> writes: > Joseph Koshakow <koshy44(at)gmail(dot)com> writes: > > The attached patch fixes an overflow bug in DecodeInterval when applying > > the units week, decade, century, and millennium. The overflow check logic > > was modelled after the overflow check at the beginning of `int > > tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span);` in timestamp.c. > > > Good catch, but I don't think that tm2interval code is best practice > anymore. Rather than bringing "double" arithmetic into the mix, > you should use the overflow-detecting arithmetic functions in > src/include/common/int.h. The existing code here is also pretty > faulty in that it doesn't notice addition overflow when combining > multiple units. So for example, instead of > > > tm->tm_mday += val * 7; > > > I think we should write something like > > > if (pg_mul_s32_overflow(val, 7, &tmp)) > return DTERR_FIELD_OVERFLOW; > if (pg_add_s32_overflow(tm->tm_mday, tmp, &tm->tm_mday)) > return DTERR_FIELD_OVERFLOW; > > > Perhaps some macros could be used to make this more legible? > > > regards, tom lane > > > @postgresql Thanks for the feedback Tom, I've attached an updated patch with your suggestions. Feel free to rename the horribly named macro. Also while fixing this I noticed that fractional intervals can also cause an overflow issue. postgres=# SELECT INTERVAL '0.1 months 2147483647 days'; interval ------------------ -2147483646 days (1 row) I haven't looked into it, but it's probably a similar cause. -
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-13T02:16:05Z
On Fri, Feb 11, 2022 at 4:58 PM Joseph Koshakow <koshy44@gmail.com> wrote: > > Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> writes: > > Joseph Koshakow <koshy44(at)gmail(dot)com> writes: > > > The attached patch fixes an overflow bug in DecodeInterval when applying > > > the units week, decade, century, and millennium. The overflow check logic > > > was modelled after the overflow check at the beginning of `int > > > tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span);` in timestamp.c. > > > > > > Good catch, but I don't think that tm2interval code is best practice > > anymore. Rather than bringing "double" arithmetic into the mix, > > you should use the overflow-detecting arithmetic functions in > > src/include/common/int.h. The existing code here is also pretty > > faulty in that it doesn't notice addition overflow when combining > > multiple units. So for example, instead of > > > > > > tm->tm_mday += val * 7; > > > > > > I think we should write something like > > > > > > if (pg_mul_s32_overflow(val, 7, &tmp)) > > return DTERR_FIELD_OVERFLOW; > > if (pg_add_s32_overflow(tm->tm_mday, tmp, &tm->tm_mday)) > > return DTERR_FIELD_OVERFLOW; > > > > > > Perhaps some macros could be used to make this more legible? > > > > > > regards, tom lane > > > > > > @postgresql > > Thanks for the feedback Tom, I've attached an updated patch with > your suggestions. Feel free to rename the horribly named macro. > > Also while fixing this I noticed that fractional intervals can also > cause an overflow issue. > postgres=# SELECT INTERVAL '0.1 months 2147483647 days'; > interval > ------------------ > -2147483646 days > (1 row) > I haven't looked into it, but it's probably a similar cause. Hey Tom, I was originally going to fix the fractional issue in a follow-up patch, but I took a look at it and decided to make a new patch with both fixes. I tried to make the handling of fractional and non-fractional units consistent. I've attached the patch below. While investigating this, I've noticed a couple more overflow issues with Intervals, but I think they're best handled in separate patches. I've included the ones I've found in this email. postgres=# CREATE TEMP TABLE INTERVAL_TBL_OF (f1 interval); CREATE TABLE postgres=# INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('0.1 weeks 2147483647 hrs'); INSERT 0 1 postgres=# SELECT * FROM INTERVAL_TBL_OF; ERROR: interval out of range postgres=# SELECT justify_days(INTERVAL '2147483647 months 2147483647 days'); justify_days ----------------------------------- -172991738 years -4 mons -23 days (1 row) Cheers, Joe Koshakow -
Re: Fix overflow in DecodeInterval
Andres Freund <andres@anarazel.de> — 2022-02-13T03:51:50Z
Hi, On 2022-02-12 21:16:05 -0500, Joseph Koshakow wrote: > I've attached the patch below. Any reason for using int return types? > +/* As above, but initial val produces years */ > +static int > +AdjustYears(int val, struct pg_tm *tm, int multiplier) > +{ > + int years; > + if (pg_mul_s32_overflow(val, multiplier, &years)) > + return 1; > + if (pg_add_s32_overflow(tm->tm_year, years, &tm->tm_year)) > + return 1; > + return 0; > } particularly since the pg_*_overflow stuff uses bool? Greetings, Andres Freund -
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-13T14:35:47Z
On Sat, Feb 12, 2022 at 10:51 PM Andres Freund <andres@anarazel.de> wrote: > Any reason for using int return types? > > particularly since the pg_*_overflow stuff uses bool? I chose int return types to keep all these methods consistent with DecodeInterval, which returns a non-zero int to indicate an error. Though I wasn't sure if an int or bool would be best, so I'm happy to change to bool if people think that's better. Also I'm realizing now that I've incorrectly been using the number of the patch to indicate the version, instead of just sticking a v3 to the front. So sorry about that, all the patches I sent in this thread are the same patch, just different versions. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-13T19:34:34Z
Actually found an additional overflow issue in DecodeInterval. I've updated the patch with the fix. Specifically it prevents trying to negate a field if it equals INT_MIN. Let me know if this is best put into another patch. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Andres Freund <andres@anarazel.de> — 2022-02-13T20:30:37Z
Hi, On 2022-02-13 09:35:47 -0500, Joseph Koshakow wrote: > I chose int return types to keep all these methods > consistent with DecodeInterval, which returns a > non-zero int to indicate an error. That's different, because it actually returns different types of errors. IMO that difference is actually reason to use a bool for the new cases, because then it's a tad clearer that they don't return DTERR_*. > Though I wasn't sure > if an int or bool would be best, so I'm happy to change > to bool if people think that's better. +1 or bool. > Also I'm realizing now that I've incorrectly been using the > number of the patch to indicate the version, instead of just > sticking a v3 to the front. So sorry about that, all the patches > I sent in this thread are the same patch, just different versions. No worries ;) Do we want to consider backpatching these fixes? If so, I'd argue for skipping 10, because it doesn't have int.h stuff yet. There's also the issue with potentially breaking indexes / constraints? Not that goes entirely away across major versions... Greetings, Andres Freund
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-02-13T20:38:39Z
Andres Freund <andres@anarazel.de> writes: > Do we want to consider backpatching these fixes? I wasn't thinking that we should. It's a behavioral change and people might not be pleased to have it appear in minor releases. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-13T22:12:54Z
Attached is a new version switching from ints to bools, as requested. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-15T11:44:40Z
On Sun, Feb 13, 2022 at 5:12 PM Joseph Koshakow <koshy44@gmail.com> wrote: > > Attached is a new version switching from ints to bools, as requested. > > - Joe Koshakow Tom, Andres, Thanks for your feedback! I'm not super familiar with the process, should I submit this thread to the commitfest or just leave it as is? Thanks, Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Andres Freund <andres@anarazel.de> — 2022-02-15T16:28:09Z
Hi, On 2022-02-15 06:44:40 -0500, Joseph Koshakow wrote: > Thanks for your feedback! I'm not super familiar with the process, > should I submit this thread to the commitfest or just leave it as is? Submit it to the CF - then we get an automatic test on a few platforms. I think we can apply it quickly after that... Greetings, Andres Freund
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-18T02:45:45Z
Ok, so I've attached a patch with my final unprompted changes. It contains the following two changes: 1. I found some more overflows with the ISO8601 formats and have included some fixes. 2. I reverted the overflow checks for the seconds field. It's actually a bit more complicated than I thought. For example consider the following query: postgres=# SELECT INTERVAL '0.99999999 min 2147483647 sec'; interval ---------------------- -596523:13:09.000001 (1 row) This query will overflow the tm_sec field of the struct pg_tm, however it's not actually out of range for the Interval. I'm not sure the best way to handle this right now, but I think it would be best to leave it for a future patch. Perhaps the time related fields in struct pg_tm need to be changed to 64 bit ints. - Joe Koshakow -
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-19T19:26:17Z
Copying over a related thread here to have info all in one place. It's a little fragmented so sorry about that. On Fri, Feb 18, 2022 at 11:44 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > > When formatting the output of an Interval, we call abs() on the hours > > field of the Interval. Calling abs(INT_MIN) returns back INT_MIN > > causing the output to contain two '-' characters. The attached patch > > fixes that issue by special casing INT_MIN hours. > > Good catch, but it looks to me like three out of the four formats in > EncodeInterval have variants of this problem --- there are assumptions > throughout that code that we can compute "-x" or "abs(x)" without > fear. Not much point in fixing only one symptom. > > Also, I notice that there's an overflow hazard upstream of here, > in interval2tm: > > regression=# select interval '214748364 hours' * 11; > ERROR: interval out of range > regression=# \errverbose > ERROR: 22008: interval out of range > LOCATION: interval2tm, timestamp.c:1982 > > There's no good excuse for not being able to print a value that > we computed successfully. > > I wonder if the most reasonable fix would be to start using int64 > instead of int arithmetic for the values that are potentially large. > I doubt that we'd be taking much of a performance hit on modern > hardware. > > regards, tom lane Joseph Koshakow <koshy44@gmail.com> writes: > On Fri, Feb 18, 2022 at 11:44 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: >> I wonder if the most reasonable fix would be to start using int64 >> instead of int arithmetic for the values that are potentially large. >> I doubt that we'd be taking much of a performance hit on modern >> hardware. > That's an interesting idea. I've always assumed that the range of the > time fields of Intervals was 2147483647 hours 59 minutes > 59.999999 seconds to -2147483648 hours -59 minutes > -59.999999 seconds. However the only reason that we can't support > the full range of int64 microseconds is because the struct pg_tm fields > are only ints. If we increase those fields to int64 then we'd be able to > support the full int64 range for microseconds as well as implicitly fix > some of the overflow issues in DecodeInterval and EncodeInterval. On Sat, Feb 19, 2022 at 1:52 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > > On Sat, Feb 19, 2022 at 12:00 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > >> I think that messing with struct pg_tm might have too many side-effects. > >> However, pg_tm isn't all that well adapted to intervals in the first > >> place, so it'd make sense to make a new struct specifically for interval > >> decoding. > > > Yeah that's a good idea, pg_tm is used all over the place. Is there a > > reason we need an intermediate structure to convert to and from? > > We could just convert directly to an Interval in DecodeInterval and > > print directly from an Interval in EncodeInterval. > > Yeah, I thought about that too, but if you look at the other callers of > interval2tm, you'll see this same set of issues. I'm inclined to keep > the current code structure and just fix the data structure. Although > interval2tm isn't *that* big, I don't think four copies of its logic > would be an improvement. > > > Also I originally created a separate thread and patch because I > > thought this wouldn't be directly related to my other patch, > > https://commitfest.postgresql.org/37/3541/. However I think with these > > discussed changes it's directly related. So I think it's best to close > > this thread and patch and copy this conversion to the other thread. > > Agreed. > > regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-20T00:16:54Z
Attached is a patch of my first pass. The to_char method isn't finished and I need to add a bunch of tests, but everything else is in place. It ended up being a fairly large change in case anyone wants to take a look the changes so far. One thing I noticed is that interval.c has a ton of code copied and pasted from other files. The code seemed out of date from those other files, so I tried to bring it up to date and add my changes. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-02-20T23:37:07Z
Joseph Koshakow <koshy44@gmail.com> writes: > Attached is a patch of my first pass. The to_char method isn't finished > and I need to add a bunch of tests, but everything else is in place. It > ended up being a fairly large change in case anyone wants to take a look > the changes so far. Couple of quick comments: * You've assumed in a number of places that long == int64. This is wrong on many platforms. Current project style for use of int64 in printf-type calls is to cast the argument to (long long) explicitly and use "%lld" (or "%llu", etc). As for strtoint_64, surely that functionality exists somewhere already (hopefully with fewer bugs than this has). * I think that tools like Coverity will complain about how you've got both calls that check the result of AdjustFractSeconds (etc) and calls that don't. You might consider coding the latter like + /* this can't overflow: */ + (void) AdjustFractSeconds(fval, itm, fsec, SECS_PER_DAY); in hopes of (a) silencing those warnings and (b) making the implicit assumption clear to readers. * I'm not entirely buying use of pg_time_t, rather than just int64, in struct itm. I think the point of this struct is to get away from datetime-specific datatypes. Also, if pg_time_t ever changed width, it'd create issues for users of this struct. I also note a number of places in the patch that are assuming that these fields are int64 not something else. * I'm a little inclined to rename interval2tm/tm2interval to interval2itm/itm2interval, as I think it'd be confusing for those function names to refer to a typedef they no longer use. * The uses of tm2itm make me a bit itchy. Is that sweeping upstream-of-there overflow problems under the rug? * // comments are not project style, either. While pgindent will convert them to /* ... */ style, the results might not be pleasing. > One thing I noticed is that interval.c has a ton of code copied and pasted > from other files. The code seemed out of date from those other files, so > I tried to bring it up to date and add my changes. We haven't actually maintained ecpg's copies of backend datatype-specific code in many years. While bringing that stuff up to speed might be worthwhile (or perhaps not, given the lack of complaints), I'd see it as a separate project. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-02-21T02:53:56Z
On Sun, Feb 20, 2022 at 6:37 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > Couple of quick comments: Thanks for the comments Tom, I'll work on fixing these and submit a new patch. > * The uses of tm2itm make me a bit itchy. Is that sweeping > upstream-of-there overflow problems under the rug? I agree, I'm not super happy with that approach. In fact I'm pretty sure it will cause queries like SELECT INTERVAL '2147483648:00:00'; to overflow upstream, even though queries like SELECT INTERVAL '2147483648 hours'; would not. The places tm2itm is being used are * After DecodeTime * In interval_to_char. The more general issue is how to share code with functions that are doing almost identical things but use pg_tm instead of the new pg_itm? I'm not really sure what the best solution is right now but I will think about it. If anyone has suggestions though, feel free to chime in. - Joe Koshakow -
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-03-06T16:14:25Z
Hi All, Sorry for the delay in the new patch, I've attached my most recent patch to this email. I ended up reworking a good portion of my previous patch so below I've included some reasons why, notes on my current approach, and some pro/cons to the approach. * The main reason for the rework had to do with double conversions and shared code. * The existing code for rounding had a lot of int to double casting and vice versa. I *think* that doubles are able to completely represent the range of ints. However doubles are not able to represent the full range of int64. After making the change I started noticing a lot of lossy behavior. One thought I had was to change the doubles to long doubles, but I wasn't able to figure out if long doubles could completely represent the range of int64. Especially since their size varies depending on the architecture. Does anyone know the answer to this? * I ended up creating two intermediate data structures for Intervals. One for decoding and one for everything else. I'll go into more detail below. * One common benefit was that they both contain a usec field which means that the Interval methods no longer need to carry around a separate fsec argument. * The obvious con here is that Intervals require two unique intermediate data structures, while all other date/time types can share a single intermediate data structure. I find this to be a bit clunky. * pg_itm_in is the struct used for Interval decoding. It's very similar to pg_tm, except all of the time related fields are collapsed into a single `int64 usec` field. * The biggest benefit of this was that all int64-double conversions are limited to a single function, AdjustFractMicroseconds. Instead of fractional units flowing down over every single time field, they only need to flow down into the single `int64 usec` field. * Overflows are caught much earlier in the decoding process which helps avoid wasted work. * I found that the decoding code became simpler for time fields, though this is a bit subjective. * pg_itm is the struct used for all other Interval functionality. It's very similar to pg_tm, except the tm_hour field is converted from int to int64 and an `int tm_usec` field was added. * When encoding and working with Intervals, we almost always want to break the time field out into hours, min, sec, usec. So it's helpful to have a common place to do this, instead of every function duplicating this code. * When breaking the time fields out, a single field will never contain a value greater than could have fit in the next unit higher. Meaning that minutes will never be greater than 60, seconds will be never greater than 60, and usec will never be greater than 1,000. So hours is actually the only field that needs to be int64 and the rest can be an int. * This also helps limit the impact to shared code (see below). * There's some shared code between Intervals and other date/time types. Specifically the DecodeTime function and the datetime_to_char_body function. These functions take in a `struct pg_tm` and a `fsec_t fsec` (fsec_t is just an alias for int32) which allows them to be re-used by all date/time types. The only difference now between pg_tm and pg_itm is the tm_hour field size (the tm_usec field in pg_itm can be used as the fsec). So to get around this I changed the function signatures to take a `struct pg_tm`, `fsec_t fsec`, and an `int64 hour` argument. It's up to the caller to provide to correct hour field. Intervals can easily convert pg_itm to a pg_tm, fsec, and hour. It's honestly a bit error-prone since those functions have to explicitly ignore the pg_tm->tm_hour field and use the provided hour argument instead, but I couldn't think of a better less intrusive solution. If anyone has a better idea, please don't hesitate to bring it up. * This partly existed in the previous patch, but I just wanted to restate it. All modifications to pg_itm_in during decoding is done via helper functions that check for overflow. All invocations of these functions either return an error on overflow or explicitly state why an overflow is impossible. * I completely rewrote the ParseISO8601Number function to try and avoid double to int64 conversions. I tried to model it after the parsing done in DecodeInterval, though I would appreciate extra scrutiny here. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-03-08T00:00:44Z
I just realized another issue today. It may have been obvious from one of Tom's earlier messages, but I'm just now putting the pieces together. On Fri, Feb 18, 2022 at 11:44 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > Also, I notice that there's an overflow hazard upstream of here, > in interval2tm: > > regression=# select interval '214748364 hours' * 11; > ERROR: interval out of range > regression=# \errverbose > ERROR: 22008: interval out of range > LOCATION: interval2tm, timestamp.c:1982 > > There's no good excuse for not being able to print a value that > we computed successfully. Scenarios like this can properly decode the interval, but actually error out when encoding the interval. As a consequence you can insert the value successfully into a table, but any attempt to query the table that includes the "bad interval" value in the result will cause an error. Below I've demonstrated an example: postgres=# CREATE TABLE tbl (i INTERVAL); CREATE TABLE postgres=# INSERT INTO tbl VALUES ('1 day'), ('3 months'), ('2 years'); INSERT 0 3 postgres=# SELECT * FROM tbl; i --------- 1 day 3 mons 2 years (3 rows) postgres=# INSERT INTO tbl VALUES ('2147483647 hours 60 minutes'); INSERT 0 1 postgres=# SELECT * FROM tbl; ERROR: interval out of range This would seriously reduce the usable of any table that contains one of these "bad interval" values. My patch actually fixes this issue, but I just wanted to call it out because it might be relevant when reviewing. -
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-03-22T00:31:28Z
Joseph Koshakow <koshy44@gmail.com> writes: > [ v8-0001-Check-for-overflow-when-decoding-an-interval.patch ] This isn't applying per the cfbot; looks like it got sideswiped by 9e9858389. Here's a quick rebase. I've not reviewed it, but I did notice (because git was in my face about this) that it's got whitespace issues. Please try to avoid unnecessary whitespace changes ... pgindent will clean those up, but it makes reviewing harder. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-03-24T00:27:25Z
On Mon, Mar 21, 2022 at 8:31 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > This isn't applying per the cfbot; looks like it got sideswiped > by 9e9858389. Here's a quick rebase. I've not reviewed it, but > I did notice (because git was in my face about this) that it's > got whitespace issues. Please try to avoid unnecessary whitespace > changes ... pgindent will clean those up, but it makes reviewing > harder. Sorry about that, I didn't have my IDE set up quite right and noticed a little too late that I had some auto-formatting turned on. Thanks for doing the rebase, did it end up fixing the whitespace issues? If not I'll go through the patch and try and fix them all. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-03-24T01:20:47Z
Joseph Koshakow <koshy44@gmail.com> writes: > Sorry about that, I didn't have my IDE set up quite right and > noticed a little too late that I had some auto-formatting turned > on. Thanks for doing the rebase, did it end up fixing > the whitespace issues? If not I'll go through the patch and try > and fix them all. No, I just fixed the merge failure. Our standard way to clean up whitespace issues and make sure code meets our layout conventions is to run pgindent over it [1]. For this particular patch, that might be too much, because it will reindent the sections that you added braces around, making the patch harder to review. So maybe the best bet is to leave well enough alone and expect the committer to re-pgindent before pushing it. However, if you spot any diff hunks where there's just a whitespace change, getting rid of those would be appreciated. regards, tom lane [1] https://wiki.postgresql.org/wiki/Running_pgindent_on_non-core_code_or_development_code
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-02T00:06:50Z
Joseph Koshakow <koshy44@gmail.com> writes: > * The existing code for rounding had a lot of int to double > casting and vice versa. I *think* that doubles are able to completely > represent the range of ints. However doubles are not able to represent > the full range of int64. After making the change I started noticing > a lot of lossy behavior. One thought I had was to change the doubles > to long doubles, but I wasn't able to figure out if long doubles could > completely represent the range of int64. Especially since their size > varies depending on the architecture. Does anyone know the answer to > this? I agree that relying on long double is not a great plan. However, I'm not seeing where there's a problem. AFAICS the revised code only uses doubles to represent fractions from the input, ie if you write "123.456 hours" then the ".456" is carried around for awhile as a float. This does not seem likely to pose any real-world problem; do you have a counterexample? Anyway, I've spent today reviewing the code and cleaning up things I didn't like, and attached is a v10. I almost feel that this is committable, but there is one thing that is bothering me. The part of DecodeInterval that does strange things with signs in the INTSTYLE_SQL_STANDARD case (starting about line 3400 in datetime.c before this patch, or line 3600 after) used to separately force the hour, minute, second, and microsecond fields to negative. Now it forces the merged tm_usec field to negative. It seems to me that this could give a different answer than before, if the h/m/s/us values had been of different signs before they got merged. However, I don't think that that situation is possible in SQL-spec- compliant input, so it may not be a problem. Again, a counterexample would be interesting. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-02T17:20:56Z
I wrote: > ... I almost feel that this is > committable, but there is one thing that is bothering me. The > part of DecodeInterval that does strange things with signs in the > INTSTYLE_SQL_STANDARD case (starting about line 3400 in datetime.c > before this patch, or line 3600 after) used to separately force the > hour, minute, second, and microsecond fields to negative. > Now it forces the merged tm_usec field to negative. It seems to > me that this could give a different answer than before, if the > h/m/s/us values had been of different signs before they got merged. > However, I don't think that that situation is possible in SQL-spec- > compliant input, so it may not be a problem. Again, a counterexample > would be interesting. As best I can tell, the case isn't reachable with spec-compliant input, but it's easy to demonstrate an issue if you set intervalstyle to sql_standard and then put in Postgres-format input. Historically, you got regression=# show intervalstyle; IntervalStyle --------------- postgres (1 row) regression=# select '-23 hours 45 min 12.34 sec'::interval; interval -------------- -22:14:47.66 (1 row) (because by default the field signs are taken as independent) regression=# set intervalstyle = sql_standard ; SET regression=# select '-23 hours 45 min 12.34 sec'::interval; interval -------------- -23:45:12.34 (1 row) However, with this patch both cases produce "-22:14:47.66", because we already merged the differently-signed fields and DecodeInterval can't tease them apart again. Perhaps we could get away with changing this nonstandard corner case, but I'm pretty uncomfortable with that thought --- I don't think random semantics changes are within the charter of this patch. I think the patch can be salvaged, though. I like the concept of converting all the sub-day fields to microseconds immediately, because it avoids a host of issues, so I don't want to give that up. What I'm going to look into is detecting the sign-adjustment-needed case up front (which is easy enough, since it's looking at the input data not the conversion results) and then forcing the individual field values negative before we accumulate them into the pg_itm_in struct. Meanwhile, the fact that we didn't detect this issue immediately shows that there's a gap in our regression tests. So the *first* thing I'm gonna do is push a patch to add test cases like what I showed above. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-02T17:29:32Z
On Fri, Apr 1, 2022 at 8:06 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > > * The existing code for rounding had a lot of int to double > > casting and vice versa. I *think* that doubles are able to completely > > represent the range of ints. However doubles are not able to represent > > the full range of int64. After making the change I started noticing > > a lot of lossy behavior. One thought I had was to change the doubles > > to long doubles, but I wasn't able to figure out if long doubles could > > completely represent the range of int64. Especially since their size > > varies depending on the architecture. Does anyone know the answer to > > this? > > I agree that relying on long double is not a great plan. However, > I'm not seeing where there's a problem. AFAICS the revised code > only uses doubles to represent fractions from the input, ie if you > write "123.456 hours" then the ".456" is carried around for awhile > as a float. This does not seem likely to pose any real-world > problem; do you have a counterexample? Yeah, you're correct, I don't think there is any problem with just using double. I don't exactly remember why I thought long double was necessary in the revised code. I probably just confused myself because it would have been necessary with the old rounding code, but not the revised code. > Anyway, I've spent today reviewing the code and cleaning up things > I didn't like, and attached is a v10. Thanks so much for the review and updates! > I think the patch can be salvaged, though. I like the concept > of converting all the sub-day fields to microseconds immediately, > because it avoids a host of issues, so I don't want to give that up. > What I'm going to look into is detecting the sign-adjustment-needed > case up front (which is easy enough, since it's looking at the > input data not the conversion results) and then forcing the > individual field values negative before we accumulate them into > the pg_itm_in struct. This sounds like a very reasonable and achievable approach to me. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-02T18:22:58Z
On Sat, Apr 2, 2022 at 1:29 PM Joseph Koshakow <koshy44@gmail.com> wrote: > > On Fri, Apr 1, 2022 at 8:06 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > > > Joseph Koshakow <koshy44@gmail.com> writes: > > > * The existing code for rounding had a lot of int to double > > > casting and vice versa. I *think* that doubles are able to completely > > > represent the range of ints. However doubles are not able to represent > > > the full range of int64. After making the change I started noticing > > > a lot of lossy behavior. One thought I had was to change the doubles > > > to long doubles, but I wasn't able to figure out if long doubles could > > > completely represent the range of int64. Especially since their size > > > varies depending on the architecture. Does anyone know the answer to > > > this? > > > > I agree that relying on long double is not a great plan. However, > > I'm not seeing where there's a problem. AFAICS the revised code > > only uses doubles to represent fractions from the input, ie if you > > write "123.456 hours" then the ".456" is carried around for awhile > > as a float. This does not seem likely to pose any real-world > > problem; do you have a counterexample? > > Yeah, you're correct, I don't think there is any problem with just > using double. I don't exactly remember why I thought long double > was necessary in the revised code. I probably just confused > myself because it would have been necessary with the old > rounding code, but not the revised code. Ok I actually remember now, the issue is with the rounding code in AdjustFractMicroseconds. > frac *= scale; > usec = (int64) frac; > > /* Round off any fractional microsecond */ > frac -= usec; > if (frac > 0.5) > usec++; > else if (frac < -0.5) > usec--; I believe it's possible for `frac -= usec;` to result in a value greater than 1 or less than -1 due to the lossiness of int64 to double conversions. Then we'd incorrectly round in one direction. I don't have a concrete counter example, but at worst we'd end up with a result that's a couple of microseconds off, so it's probably not a huge deal. If I'm right about the above, and we care enough to fix it, then I think it can be fixed with the following: > frac *= scale; > usec = (int64) frac; > > /* Remove non fractional part from frac */ > frac -= (double) usec; > /* Adjust for lossy conversion from int64 to double */ > while (frac < 0 && frac < -1) > frac++; > while (frac > 0 && frac > 1) > frac--; > > /* Round off any fractional microsecond */ > if (frac > 0.5) > usec++; > else if (frac < -0.5) > usec--; - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-02T18:32:31Z
On Sat, Apr 2, 2022 at 2:22 PM Joseph Koshakow <koshy44@gmail.com> wrote: > > On Sat, Apr 2, 2022 at 1:29 PM Joseph Koshakow <koshy44@gmail.com> wrote: > > > > On Fri, Apr 1, 2022 at 8:06 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > > > > > Joseph Koshakow <koshy44@gmail.com> writes: > > > > * The existing code for rounding had a lot of int to double > > > > casting and vice versa. I *think* that doubles are able to completely > > > > represent the range of ints. However doubles are not able to represent > > > > the full range of int64. After making the change I started noticing > > > > a lot of lossy behavior. One thought I had was to change the doubles > > > > to long doubles, but I wasn't able to figure out if long doubles could > > > > completely represent the range of int64. Especially since their size > > > > varies depending on the architecture. Does anyone know the answer to > > > > this? > > > > > > I agree that relying on long double is not a great plan. However, > > > I'm not seeing where there's a problem. AFAICS the revised code > > > only uses doubles to represent fractions from the input, ie if you > > > write "123.456 hours" then the ".456" is carried around for awhile > > > as a float. This does not seem likely to pose any real-world > > > problem; do you have a counterexample? > > > > Yeah, you're correct, I don't think there is any problem with just > > using double. I don't exactly remember why I thought long double > > was necessary in the revised code. I probably just confused > > myself because it would have been necessary with the old > > rounding code, but not the revised code. > > Ok I actually remember now, the issue is with the rounding > code in AdjustFractMicroseconds. > > > frac *= scale; > > usec = (int64) frac; > > > > /* Round off any fractional microsecond */ > > frac -= usec; > > if (frac > 0.5) > > usec++; > > else if (frac < -0.5) > > usec--; > > I believe it's possible for `frac -= usec;` to result in a value greater > than 1 or less than -1 due to the lossiness of int64 to double > conversions. Then we'd incorrectly round in one direction. I don't > have a concrete counter example, but at worst we'd end up with a > result that's a couple of microseconds off, so it's probably not a huge > deal. > > If I'm right about the above, and we care enough to fix it, then I think > it can be fixed with the following: > > > frac *= scale; > > usec = (int64) frac; > > > > /* Remove non fractional part from frac */ > > frac -= (double) usec; > > /* Adjust for lossy conversion from int64 to double */ > > while (frac < 0 && frac < -1) > > frac++; > > while (frac > 0 && frac > 1) > > frac--; > > > > /* Round off any fractional microsecond */ > > if (frac > 0.5) > > usec++; > > else if (frac < -0.5) > > usec--; Sorry, those should be inclusive comparisons > frac *= scale; > usec = (int64) frac; > > /* Remove non fractional part from frac */ > frac -= (double) usec; > /* Adjust for lossy conversion from int64 to double */ > while (frac < 0 && frac <= -1) > frac++; > while (frac > 0 && frac >= 1) > frac--; > > /* Round off any fractional microsecond */ > if (frac > 0.5) > usec++; > else if (frac < -0.5) > usec--;
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-02T18:55:13Z
On Fri, Apr 1, 2022 at 8:06 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > I think the patch can be salvaged, though. I like the concept > of converting all the sub-day fields to microseconds immediately, > because it avoids a host of issues, so I don't want to give that up. > What I'm going to look into is detecting the sign-adjustment-needed > case up front (which is easy enough, since it's looking at the > input data not the conversion results) and then forcing the > individual field values negative before we accumulate them into > the pg_itm_in struct. I took a stab at this issue and the attached patch (which would be applied on top of your v10 patch) seems to fix the issue. Feel free to ignore it if you're already working on a fix. - Joe
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-02T19:08:24Z
Joseph Koshakow <koshy44@gmail.com> writes: > Ok I actually remember now, the issue is with the rounding > code in AdjustFractMicroseconds. > ... > I believe it's possible for `frac -= usec;` to result in a value greater > than 1 or less than -1 due to the lossiness of int64 to double > conversions. I think it's not, at least not for the interesting range of possible values in this code. Given that abs(frac) < 1 to start with, the abs value of usec can't exceed the value of scale, which is at most USECS_PER_DAY so it's at most 37 or so bits, which is well within the exact range for any sane implementation of double. It would take a very poor floating-point implementation to not get the right answer here. (And we're largely assuming IEEE-compliant floats these days.) Anyway, the other issue indeed turns out to be easy to fix. Attached is a v11 that deals with that. If the cfbot doesn't complain about it, I'll push this later today. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-02T19:10:18Z
Joseph Koshakow <koshy44@gmail.com> writes: > I took a stab at this issue and the attached patch (which would be > applied on top of your v10 patch) seems to fix the issue. Feel > free to ignore it if you're already working on a fix. You really only need to flip val/fval in one place. More to the point, there's also the hh:mm:ss paths to deal with; see my v11. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-02T19:51:38Z
On Sat, Apr 2, 2022 at 3:08 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > > Ok I actually remember now, the issue is with the rounding > > code in AdjustFractMicroseconds. > > ... > > I believe it's possible for `frac -= usec;` to result in a value greater > > than 1 or less than -1 due to the lossiness of int64 to double > > conversions. > > I think it's not, at least not for the interesting range of possible > values in this code. Given that abs(frac) < 1 to start with, the > abs value of usec can't exceed the value of scale, which is at most > USECS_PER_DAY so it's at most 37 or so bits, which is well within > the exact range for any sane implementation of double. It would > take a very poor floating-point implementation to not get the right > answer here. (And we're largely assuming IEEE-compliant floats these > days.) Ah, I see. That makes sense to me. On Sat, Apr 2, 2022 at 3:10 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > > I took a stab at this issue and the attached patch (which would be > > applied on top of your v10 patch) seems to fix the issue. Feel > > free to ignore it if you're already working on a fix. > > You really only need to flip val/fval in one place. More to the > point, there's also the hh:mm:ss paths to deal with; see my v11. Good point. Thanks again for all the help! - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-02T20:14:15Z
Joseph Koshakow <koshy44@gmail.com> writes: > On Sat, Apr 2, 2022 at 3:08 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: >> I think it's not, at least not for the interesting range of possible >> values in this code. Given that abs(frac) < 1 to start with, the >> abs value of usec can't exceed the value of scale, which is at most >> USECS_PER_DAY so it's at most 37 or so bits, which is well within >> the exact range for any sane implementation of double. It would >> take a very poor floating-point implementation to not get the right >> answer here. (And we're largely assuming IEEE-compliant floats these >> days.) > Ah, I see. That makes sense to me. Cool. I've pushed the patch. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-03T07:09:07Z
I wrote: > Cool. I've pushed the patch. Hmm ... buildfarm's not entirely happy [1][2][3]: diff -U3 /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/expected/interval.out /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/results/interval.out --- /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/expected/interval.out 2022-04-03 04:56:32.000000000 +0000 +++ /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/results/interval.out 2022-04-03 05:23:00.000000000 +0000 @@ -1465,7 +1465,7 @@ LINE 1: select interval 'PT2562047788.1:00:54.775807'; ^ select interval 'PT2562047788:01.:54.775807'; - ERROR: interval field value out of range: "PT2562047788:01.:54.775807" + ERROR: invalid input syntax for type interval: "PT2562047788:01.:54.775807" LINE 1: select interval 'PT2562047788:01.:54.775807'; ^ -- overflowing with fractional fields - SQL standard format What do you make of that? I'm betting that strtod() works a bit differently on those old platforms, but too tired to look closer tonight. regards, tom lane [1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=sungazer&dt=2022-04-03%2004%3A56%3A34 [2] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=hoverfly&dt=2022-04-03%2000%3A51%3A50 [3] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=anole&dt=2022-04-03%2000%3A32%3A10 -
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-03T15:23:07Z
On Sun, Apr 3, 2022 at 3:09 AM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > I wrote: > > Cool. I've pushed the patch. > > Hmm ... buildfarm's not entirely happy [1][2][3]: > > diff -U3 /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/expected/interval.out /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/results/interval.out > --- /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/expected/interval.out 2022-04-03 04:56:32.000000000 +0000 > +++ /home/nm/farm/gcc64/HEAD/pgsql.build/src/test/regress/results/interval.out 2022-04-03 05:23:00.000000000 +0000 > @@ -1465,7 +1465,7 @@ > LINE 1: select interval 'PT2562047788.1:00:54.775807'; > ^ > select interval 'PT2562047788:01.:54.775807'; > - ERROR: interval field value out of range: "PT2562047788:01.:54.775807" > + ERROR: invalid input syntax for type interval: "PT2562047788:01.:54.775807" > LINE 1: select interval 'PT2562047788:01.:54.775807'; > ^ > -- overflowing with fractional fields - SQL standard format > > What do you make of that? I'm betting that strtod() works a > bit differently on those old platforms, but too tired to > look closer tonight. > > regards, tom lane > > [1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=sungazer&dt=2022-04-03%2004%3A56%3A34 > [2] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=hoverfly&dt=2022-04-03%2000%3A51%3A50 > [3] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=anole&dt=2022-04-03%2000%3A32%3A10 I think I know that the issue is. It's with `ParseISO8601Number` and the minutes field "1.". Previously that function parsed the entire field into a single double, so "1." would be parsed into 1.0. Now we try to parse the integer and decimal parts separately. So we first parse "1" into 1 and then fail to "." into anything because it's not a valid decimal. What's interesting is that I believe this syntax, "1.", always would have failed for non-ISO8601 Interval. It was only previously valid with ISO8601 intervals. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-03T15:44:58Z
Joseph Koshakow <koshy44@gmail.com> writes: > On Sun, Apr 3, 2022 at 3:09 AM Tom Lane <tgl@sss.pgh.pa.us> wrote: >> Hmm ... buildfarm's not entirely happy [1][2][3]: > I think I know that the issue is. It's with `ParseISO8601Number` and > the minutes field "1.". > Previously that function parsed the entire field into a single double, > so "1." would > be parsed into 1.0. Now we try to parse the integer and decimal parts > separately. So > we first parse "1" into 1 and then fail to "." into anything because > it's not a valid decimal. Interesting point, but then why doesn't it fail everywhere? regards, tom lane
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-03T16:03:23Z
I wrote: > Joseph Koshakow <koshy44@gmail.com> writes: >> I think I know that the issue is. It's with `ParseISO8601Number` and >> the minutes field "1.". >> Previously that function parsed the entire field into a single double, >> so "1." would >> be parsed into 1.0. Now we try to parse the integer and decimal parts >> separately. So >> we first parse "1" into 1 and then fail to "." into anything because >> it's not a valid decimal. > Interesting point, but then why doesn't it fail everywhere? Oh ... a bit of testing says that strtod() on an empty string succeeds (returning zero) on Linux, but fails with EINVAL on AIX. The latter is a lot less surprising than the former, so we'd better cope. (Reading POSIX with an eagle eye, it looks like both behaviors are allowed per spec: this is why you have to check that endptr was advanced to be sure everything is kosher.) regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-03T16:22:12Z
On Sun, Apr 3, 2022 at 12:03 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > I wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > >> I think I know that the issue is. It's with `ParseISO8601Number` and > >> the minutes field "1.". > >> Previously that function parsed the entire field into a single double, > >> so "1." would > >> be parsed into 1.0. Now we try to parse the integer and decimal parts > >> separately. So > >> we first parse "1" into 1 and then fail to "." into anything because > >> it's not a valid decimal. > > > Interesting point, but then why doesn't it fail everywhere? > > Oh ... a bit of testing says that strtod() on an empty string > succeeds (returning zero) on Linux, but fails with EINVAL on > AIX. The latter is a lot less surprising than the former, > so we'd better cope. > > (Reading POSIX with an eagle eye, it looks like both behaviors > are allowed per spec: this is why you have to check that endptr > was advanced to be sure everything is kosher.) > > regards, tom lane I'm not sure I follow exactly. Where would we pass an empty string to strtod()? Wouldn't we be passing a string with a single character of '.'? Either way, from reading the man pages though it seems that strtod() has the same behavior on any invalid input in Linux, return 0 and don't advance endptr. So I think we need to check that endptr has moved both after the call to strtoi64() and strtod(). - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-03T16:30:32Z
Joseph Koshakow <koshy44@gmail.com> writes: > On Sun, Apr 3, 2022 at 12:03 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: >> Oh ... a bit of testing says that strtod() on an empty string >> succeeds (returning zero) on Linux, but fails with EINVAL on >> AIX. The latter is a lot less surprising than the former, >> so we'd better cope. > I'm not sure I follow exactly. Where would we pass an empty > string to strtod()? Wouldn't we be passing a string with a > single character of '.'? Oh, I was thinking that we passed "cp + 1" to strtod, but that was just caffeine deprivation. You're right, what we are asking it to parse is "." not "". The result is the same though: per testing, AIX sets EINVAL and Linux doesn't. > So I think we need to check that endptr has moved both after > the call to strtoi64() and strtod(). I'm not sure we need to do that explicitly, given that there's a check later as to whether endptr is pointing at \0; that will fail if endptr wasn't advanced. The fix I was loosely envisioning was to check for cp[1] == '\0' and not bother calling strtod() in that case. regards, tom lane
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-03T16:44:46Z
On Sun, Apr 3, 2022 at 12:30 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > Joseph Koshakow <koshy44@gmail.com> writes: > > So I think we need to check that endptr has moved both after > > the call to strtoi64() and strtod(). > > I'm not sure we need to do that explicitly, given that there's > a check later as to whether endptr is pointing at \0; that will > fail if endptr wasn't advanced. > > The fix I was loosely envisioning was to check for cp[1] == '\0' > and not bother calling strtod() in that case. Ah, ok I see what you mean. I agree an approach like that should work, but I don't actually think cp is null terminated in this case. The entire Interval is passed to DecodeISO8601Interval() as one big string, so the specific number we're parsing may be somewhere in the middle. If we just do the opposite and check isdigit(cp[1]) and only call strtod() in that case I think it should work. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-03T17:00:48Z
On Sun, Apr 3, 2022 at 12:44 PM Joseph Koshakow <koshy44@gmail.com> wrote: > > On Sun, Apr 3, 2022 at 12:30 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > > > > Joseph Koshakow <koshy44@gmail.com> writes: > > > So I think we need to check that endptr has moved both after > > > the call to strtoi64() and strtod(). > > > > I'm not sure we need to do that explicitly, given that there's > > a check later as to whether endptr is pointing at \0; that will > > fail if endptr wasn't advanced. > > > > The fix I was loosely envisioning was to check for cp[1] == '\0' > > and not bother calling strtod() in that case. > > Ah, ok I see what you mean. I agree an approach like that should > work, but I don't actually think cp is null terminated in this case. The > entire Interval is passed to DecodeISO8601Interval() as one big > string, so the specific number we're parsing may be somewhere > in the middle. > > If we just do the opposite and check isdigit(cp[1]) and only call > strtod() in that case I think it should work. > > - Joe Koshakow How does this patch look? I don't really have any way to test it on AIX. - Joe Koshakow
-
Re: Fix overflow in DecodeInterval
Tom Lane <tgl@sss.pgh.pa.us> — 2022-04-03T19:06:55Z
Joseph Koshakow <koshy44@gmail.com> writes: > How does this patch look? I don't really have any way to test it on > AIX. That buildfarm machine is pretty slow, so I'm not in a hurry to test it manually either. However, now that we realize the issue is about whether strtod(".") produces EINVAL or not, I think we need to fix all the places in datetime.c that are risking that. After a bit of hacking I have the attached. (I think that the call sites for strtoint and its variants are not at risk of passing empty strings, so there's not need for concern there.) BTW, the way you had it coded would allow 'P.Y0M3DT4H5M6S', which I don't think we want to allow --- at least, that's rejected by v14 on my machine. regards, tom lane -
Re: Fix overflow in DecodeInterval
Joseph Koshakow <koshy44@gmail.com> — 2022-04-03T22:19:54Z
On Sun, Apr 3, 2022 at 3:06 PM Tom Lane <tgl@sss.pgh.pa.us> wrote: > That buildfarm machine is pretty slow, so I'm not in a hurry to test > it manually either. However, now that we realize the issue is about > whether strtod(".") produces EINVAL or not, I think we need to fix > all the places in datetime.c that are risking that. After a bit of > hacking I have the attached. (I think that the call sites for > strtoint and its variants are not at risk of passing empty strings, > so there's not need for concern there.) > > BTW, the way you had it coded would allow 'P.Y0M3DT4H5M6S', which > I don't think we want to allow --- at least, that's rejected by v14 > on my machine. Oh yeah, good catch. Your patch seems like it should fix all the issues. Thanks again for the help! - Joe Koshakow